Challenge 3 — Solution
Task: Write a complete safe file-upload handler for a field named
"document" that only allows PDF files (application/pdf) up to 5MB,
checks the real MIME type with mime_content_type(), generates a new
filename with uniqid(), and moves the file into an "uploads/" folder —
echoing clear success or failure messages at each validation step.
";
} elseif ($_FILES['document']['size'] > $maxSize) {
echo "File too large (max 5MB).
";
} else {
$actualType = mime_content_type($_FILES['document']['tmp_name']);
if (!in_array($actualType, $allowedTypes)) {
echo "Invalid file type — only PDF files are allowed.
";
} else {
$newName = uniqid() . '.pdf';
$destination = "uploads/$newName";
if (move_uploaded_file($_FILES['document']['tmp_name'], $destination)) {
echo "Document uploaded successfully as $newName.
";
} else {
echo "Something went wrong while saving the file.
";
}
}
}
?>
Output:
(Depends on the actual uploaded file - assuming a genuine, valid PDF
under 5MB was submitted:)
Document uploaded successfully as 65432a1b8f9c3.pdf.
Notes:
- The four checks run in a deliberate order: upload error first (did
the upload even succeed at the transport level), then size, then the
real content type via mime_content_type() - each elseif only runs if
every earlier check already passed, avoiding wasted work checking a
file that already failed an earlier, cheaper test.
- mime_content_type() is used specifically instead of trusting
$_FILES['document']['type'], since the claimed type is set by the
browser and can be faked - a file renamed to look like a PDF but
containing something else entirely would be caught here.
- uniqid() . '.pdf' generates a completely new, unpredictable filename,
discarding the visitor's own original filename entirely - preventing
both filename collisions between different uploads and the path-
traversal risk of trusting a visitor-supplied filename directly.
- move_uploaded_file()'s own return value is checked too (rather than
assuming it always succeeds), since a genuine filesystem-level problem
(e.g. the uploads/ folder not being writable) is still possible even
after every earlier validation step has passed.