File uploads
Accept a photo or resume without letting an attacker upload a script.
PHP
<?php
$maxBytes = 2 * 1024 * 1024;
$allowed = ["image/jpeg" => "jpg", "image/png" => "png", "application/pdf" => "pdf"];
$error = "";
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$file = $_FILES["resume"] ?? null;
if (!$file || $file["error"] !== UPLOAD_ERR_OK) {
$error = "Upload failed, please try again";
} elseif ($file["size"] > $maxBytes) {
$error = "File must be under 2 MB";
} else {
$type = (new finfo(FILEINFO_MIME_TYPE))->file($file["tmp_name"]);
if (!isset($allowed[$type])) {
$error = "Only JPG, PNG or PDF";
} else {
$name = bin2hex(random_bytes(16)) . "." . $allowed[$type];
move_uploaded_file($file["tmp_name"], __DIR__ . "/../uploads/" . $name);
}
}
}
?>
<form method="post" enctype="multipart/form-data">
<input type="file" name="resume" accept=".jpg,.png,.pdf" required>
<button>Upload</button>
</form>
<p><?= htmlspecialchars($error) ?></p>- Without enctype="multipart/form-data", the file never arrives.
- Check the real type with finfo. The file name and the type the browser reports can both be faked.
- Give the file a new random name. Never keep the user's name, which could be ../../index.php.
- Store uploads outside the public web folder, or stop PHP from running in that folder.
- upload_max_filesize and post_max_size in php.ini set the largest file the server accepts.