Last updated: August 25, 2026.
A secure upload handler validates the request, enforces a server-side size limit, identifies the file from its contents, generates its own filename, and stores it where uploaded code cannot execute.
Upload form
<form action="upload.php" method="post" enctype="multipart/form-data">
<label for="uploaded-file">Choose a JPEG or PNG image</label>
<input id="uploaded-file" name="uploaded_file"
type="file" accept="image/jpeg,image/png" required>
<button type="submit">Upload</button>
</form>The accept attribute improves the file picker but is not security validation. The server must enforce every rule.
Validate and store the upload
<?php
declare(strict_types=1);
$file = $_FILES['uploaded_file'] ?? null;
if (!is_array($file) || is_array($file['error'] ?? null)) {
throw new RuntimeException('Invalid upload request.');
}
if ($file['error'] !== UPLOAD_ERR_OK) {
throw new RuntimeException('Upload failed with code ' . $file['error']);
}
if ($file['size'] > 5_000_000) {
throw new RuntimeException('The file is larger than 5 MB.');
}
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($file['tmp_name']);
$extensions = ['image/jpeg' => 'jpg', 'image/png' => 'png'];
if (!isset($extensions[$mime])) {
throw new RuntimeException('Only JPEG and PNG images are accepted.');
}
$name = bin2hex(random_bytes(16)) . '.' . $extensions[$mime];
$uploadDirectory = dirname(__DIR__) . '/private-uploads';
if (!is_dir($uploadDirectory) || !is_writable($uploadDirectory)) {
throw new RuntimeException('Upload storage is unavailable.');
}
if (!move_uploaded_file($file['tmp_name'], $uploadDirectory . '/' . $name)) {
throw new RuntimeException('The uploaded file could not be stored.');
}
echo 'Upload completed.';Production checklist
- Require authentication and authorization before accepting a file.
- Use CSRF protection for browser-based forms.
- Store files outside the public web root or serve them through a controlled download endpoint.
- Set
upload_max_filesize,post_max_size, request limits, and storage quotas. - Use generated names; keep the original name only as separately encoded metadata.
- Scan risky document types and re-encode images when appropriate.
See PHP’s file-upload documentation for upload error codes and configuration details.
Need uploads inside a database application? PHPRunner can generate authenticated upload forms, validation, and database-backed file fields.
One thought on “Secure File Upload with PHP”