PHP
Implement Secure File Uploads in PHP
Learn to safely handle file uploads in PHP by validating file types, sizes, and names, significantly reducing the risk of malicious file execution and server compromise.
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['uploadedFile'])) {
$uploadDir = 'uploads/'; // Directory where files will be stored
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 in bytes
$file = $_FILES['uploadedFile'];
// Basic error checking
if ($file['error'] !== UPLOAD_ERR_OK) {
echo "File upload failed with error code: " . $file['error'];
exit;
}
// Validate file size
if ($file['size'] > $maxFileSize) {
echo "Error: File size exceeds the allowed limit of 5MB.";
exit;
}
// Validate file type (MIME type check)
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!in_array($mimeType, $allowedMimeTypes)) {
echo "Error: Invalid file type. Only JPEG, PNG, and PDF are allowed.";
exit;
}
// Further validation: Check file extension based on MIME type (double-check)
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
$allowedExtensions = [
'image/jpeg' => ['jpg', 'jpeg'],
'image/png' => ['png'],
'application/pdf' => ['pdf']
];
if (!isset($allowedExtensions[$mimeType]) || !in_array(strtolower($extension), $allowedExtensions[$mimeType])) {
echo "Error: Mismatched file extension for the detected MIME type.";
exit;
}
// Generate a unique filename to prevent overwriting and path traversal
$newFileName = uniqid('upload_', true) . '.' . strtolower($extension);
$destinationPath = $uploadDir . $newFileName;
// Move the uploaded file
if (move_uploaded_file($file['tmp_name'], $destinationPath)) {
echo "File uploaded successfully: " . htmlspecialchars($newFileName);
} else {
echo "Error: Could not move uploaded file.";
}
} else {
echo "
<form action='' method='post' enctype='multipart/form-data'>
Select file to upload (Max 5MB, JPG, PNG, PDF):
<input type='file' name='uploadedFile' id='uploadedFile'>
<input type='submit' value='Upload File' name='submit'>
</form>
";
}
?>
How it works: This PHP snippet demonstrates secure practices for handling file uploads. It validates the uploaded file's size and performs a critical MIME type check using `finfo_open` to prevent malicious files from being disguised as benign ones. It also cross-references the detected MIME type with the file extension for an extra layer of security. Finally, it generates a unique filename to avoid overwriting existing files and potential path traversal vulnerabilities, then safely moves the file to a designated `uploads` directory.