PHP
Securely Validate File Uploads in PHP
Implement robust server-side validation for file uploads in PHP, checking file type, size, and potential malicious content to ensure the security of your web application.
<?php
// Define upload directory and allowed file types/sizes
$upload_dir = __DIR__ . '/uploads/';
$allowed_mimes = ['image/jpeg', 'image/png', 'application/pdf'];
$max_file_size = 5 * 1024 * 1024; // 5 MB
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['user_file'])) {
$file = $_FILES['user_file'];
// 1. Check for upload errors
if ($file['error'] !== UPLOAD_ERR_OK) {
die('File upload error: ' . $file['error']);
}
// 2. Validate file size
if ($file['size'] > $max_file_size) {
die('File is too large. Max size is 5MB.');
}
// 3. Validate file type (using actual MIME type, not just extension)
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime_type = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!in_array($mime_type, $allowed_mimes)) {
die('Invalid file type. Only JPG, PNG, PDF are allowed. Detected: ' . $mime_type);
}
// 4. Generate a unique, secure filename to prevent path traversal/overwrite
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
$new_file_name = uniqid('upload_', true) . '.' . $extension;
$destination_path = $upload_dir . $new_file_name;
// 5. Move the uploaded file to its final, secure destination
if (move_uploaded_file($file['tmp_name'], $destination_path)) {
echo 'File uploaded successfully: ' . $new_file_name;
// Optionally, remove execute permissions on the uploaded file if possible (e.g., chmod($destination_path, 0644);)
} else {
die('Failed to move uploaded file.');
}
} else {
echo '<form method="POST" enctype="multipart/form-data">';
echo ' <input type="file" name="user_file">';
echo ' <button type="submit">Upload File</button>';
echo '</form>';
}
?>
How it works: This PHP snippet provides a comprehensive example of secure file upload validation. It covers several crucial security checks: verifying `UPLOAD_ERR_OK` to detect general upload problems, validating the file `size` to prevent denial-of-service attacks, and critically, checking the actual file's `mime_type` using `finfo_open` rather than relying solely on the file extension (which can be easily faked). It then generates a `uniqid` to create a secure, unpredictable filename to prevent path traversal and file overwrite vulnerabilities, finally moving the file to a designated `uploads/` directory outside of the web root if possible, or at least in a directory with restricted execution permissions.