PHP

Secure File Uploads (PHP)

Implement secure file uploads in PHP by validating file types and sizes, handling errors, and storing files outside the web root to prevent common vulnerabilities.

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['uploadedFile'])) {
    $uploadDir = __DIR__ . '/../uploads/'; // Store outside web root for security
    if (!is_dir($uploadDir)) {
        mkdir($uploadDir, 0755, true); // Create directory if it doesn't exist
    }

    $allowedMimeTypes = ['image/jpeg', 'image/png', 'application/pdf'];
    $maxFileSize = 5 * 1024 * 1024; // 5 MB

    $file = $_FILES['uploadedFile'];

    // 1. Check for upload errors
    if ($file['error'] !== UPLOAD_ERR_OK) {
        switch ($file['error']) {
            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:
                $message = "File is too large (exceeds PHP config or form limit)."; break;
            case UPLOAD_ERR_PARTIAL:
                $message = "File upload was interrupted."; break;
            case UPLOAD_ERR_NO_FILE:
                $message = "No file was uploaded."; break;
            default:
                $message = "Unknown upload error."; break;
        }
        die("Error: " . $message);
    }

    // 2. Validate file size
    if ($file['size'] > $maxFileSize) {
        die("Error: File size exceeds the allowed limit of " . ($maxFileSize / (1024*1024)) . "MB.");
    }

    // 3. Validate file type (using finfo for true MIME type check)
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mimeType = $finfo->file($file['tmp_name']);
    if (!in_array($mimeType, $allowedMimeTypes)) {
        die("Error: Invalid file type. Allowed types are: " . implode(', ', $allowedMimeTypes));
    }

    // 4. Generate a unique and safe filename
    $fileExtension = pathinfo($file['name'], PATHINFO_EXTENSION);
    $safeFilename = bin2hex(random_bytes(16)) . '.' . $fileExtension;
    $uploadFilePath = $uploadDir . $safeFilename;

    // 5. Move the uploaded file
    if (move_uploaded_file($file['tmp_name'], $uploadFilePath)) {
        echo "File uploaded successfully. Stored at: " . htmlspecialchars($uploadFilePath) . "
";
        // You might save $safeFilename to your database here
    } else {
        die("Error: Failed to move uploaded file.");
    }
} else {
    // Display the upload form
    echo '<form action="" method="POST" enctype="multipart/form-data">';
    echo '  <label for="uploadedFile">Choose file to upload (Max 5MB, JPG/PNG/PDF):</label><br>';
    echo '  <input type="file" name="uploadedFile" id="uploadedFile" accept="image/jpeg,image/png,application/pdf"><br><br>';
    echo '  <button type="submit">Upload File</button>';
    echo '</form>';
}
?>
How it works: This PHP snippet provides a secure approach to handling file uploads. It includes crucial steps such as checking for upload errors, validating the file size, and performing a robust MIME type check using `finfo` to prevent malicious file execution. It generates a unique, cryptographically secure filename to avoid path traversal and overwriting existing files, and crucially, stores the uploaded files in a directory *outside* the web root, preventing direct browser access and execution of potentially dangerous content.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs