PHP
Implementing Secure File Uploads in PHP
Secure your web application by implementing robust server-side file upload validation, including type checks, size limits, and safe storage practices in PHP.
<?php
// Define upload directory outside the web root for security
define('UPLOAD_DIR', __DIR__ . '/../uploads_secure/'); // One level up from script's directory
// Ensure upload directory exists and is writable
if (!is_dir(UPLOAD_DIR)) {
mkdir(UPLOAD_DIR, 0755, true);
}
function handleSecureFileUpload(array $file): array {
$response = ['success' => false, 'message' => ''];
// Check for upload errors
if ($file['error'] !== UPLOAD_ERR_OK) {
$response['message'] = 'File upload error: ' . $file['error'];
return $response;
}
// 1. Validate file size
$maxFileSize = 5 * 1024 * 1024; // 5 MB
if ($file['size'] > $maxFileSize) {
$response['message'] = 'File is too large. Maximum size is ' . ($maxFileSize / (1024 * 1024)) . 'MB.';
return $response;
}
// 2. Validate file type (MIME type and extension)
$allowedMimeTypes = ['image/jpeg', 'image/png', 'application/pdf'];
$allowedExtensions = ['jpg', 'jpeg', 'png', 'pdf'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($mimeType, $allowedMimeTypes) || !in_array($extension, $allowedExtensions)) {
$response['message'] = 'Invalid file type. Only JPEG, PNG, and PDF are allowed.';
return $response;
}
// 3. Generate a unique and safe filename
$newFileName = uniqid('', true) . '.' . $extension;
$targetFilePath = UPLOAD_DIR . $newFileName;
// 4. Move the uploaded file to a secure directory
if (move_uploaded_file($file['tmp_name'], $targetFilePath)) {
// Set restrictive permissions on the uploaded file
chmod($targetFilePath, 0644); // User read/write, group read, others read
$response['success'] = true;
$response['message'] = 'File uploaded successfully.';
$response['filePath'] = $targetFilePath; // Store only the path, not web-accessible URL
} else {
$response['message'] = 'Failed to move uploaded file.';
}
return $response;
}
// Example Usage (assuming $_FILES['user_file'] exists from a form submission)
// if (isset($_FILES['user_file'])) {
// $uploadResult = handleSecureFileUpload($_FILES['user_file']);
// if ($uploadResult['success']) {
// echo "Upload successful: " . $uploadResult['filePath'];
// } else {
// echo "Upload failed: " . $uploadResult['message'];
// }
// } else {
// // Handle no file uploaded scenario
// }
?>
How it works: This PHP snippet outlines crucial steps for secure file uploads. It validates file size and MIME type to prevent oversized or malicious executable files. It generates a unique filename to avoid overwriting or path traversal issues and stores files outside the web root for enhanced security. Finally, it sets restrictive permissions on the uploaded file.