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.