File Uploads & Handling
Let users upload files safely — profile pictures, documents — by validating the type and size and storing the file securely.
What you will learn
- Build an upload form and read $_FILES
- Validate file type and size before saving
- Store uploads safely with a unique name
How uploads work
Almost every real app lets users upload something — a profile photo, a resume, an invoice. In PHP, an uploaded file does not arrive in $_POST; it arrives in a special array called $_FILES. Handling uploads safely is a common project and interview task, because a careless upload form is a serious security hole.
The flow always has three stages: the form sends the file, PHP receives it in a temporary location, and your code validates it and moves it to permanent storage.
- The HTML form must use
enctype="multipart/form-data"andmethod="post"so files can be sent. - PHP receives the file into a temporary location and describes it in
$_FILES. - You validate it — check the type and size are acceptable.
- If it passes, you move it from the temp location to a permanent folder with
move_uploaded_file().
The upload form
The form needs one special attribute, enctype, without which the file is not actually sent:
<!-- upload.html -->
<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="photo">
<button type="submit">Upload</button>
</form>The key is enctype="multipart/form-data" — it tells the browser to package the file (binary data) along with the form. The <input type="file" name="photo"> creates the choose-file button; photo is the name PHP will use to find this file in $_FILES.
Note: No PHP output yet — this is just the form. Forget the enctype and $_FILES will be empty even though the user picked a file. It is the single most common upload mistake.
Receiving and validating the file
Now the PHP that receives it. We never trust the file blindly — we check its real type and size first, then store it under a fresh, safe name.
<?php
$file = $_FILES["photo"];
// 1. basic error + size check (max 2 MB)
if ($file["error"] !== 0) {
exit("Upload failed.");
}
if ($file["size"] > 2 * 1024 * 1024) {
exit("File too large (max 2 MB).");
}
// 2. allow only real image types
$allowed = ["image/jpeg", "image/png", "image/webp"];
$type = mime_content_type($file["tmp_name"]);
if (!in_array($type, $allowed)) {
exit("Only JPG, PNG or WebP images are allowed.");
}
// 3. give it a safe, unique name and move it
$ext = pathinfo($file["name"], PATHINFO_EXTENSION);
$safeName = uniqid("img_") . "." . $ext;
move_uploaded_file($file["tmp_name"], "uploads/" . $safeName);
echo "Uploaded as " . htmlspecialchars($safeName);
?>Reading it in three stages. Stage 1 reads $_FILES["photo"] — an array describing the upload — and rejects it if PHP flagged an error or the size exceeds 2 MB (2 * 1024 * 1024 bytes). Stage 2 uses mime_content_type() to detect the file’s real type by looking inside it (not trusting the filename), and rejects anything not in our $allowed image list. Stage 3 builds a brand-new name with uniqid("img_") so uploads never overwrite each other or carry a dangerous original name, then move_uploaded_file() moves it from the temp spot into the uploads/ folder.
Note: Output (for a valid 800 KB PNG):
Uploaded as img_66a1f2c3d4e5b.png
The file is now safely in uploads/ under a unique name. A too-big file would have printed File too large (max 2 MB). and a .php disguised as an image would have failed the type check — exactly the attacks we are blocking.
Watch out: Never trust the file’s original name or its extension to decide the type — attackers rename virus.php to photo.jpg. Check the real type with mime_content_type(), store uploads outside any folder PHP will execute, and never let an uploaded file be run as a script.
Q. Where does an uploaded file arrive in PHP?
✍️ Practice
- Build an upload form and print the uploaded file’s name, size and type from
$_FILES. - Reject any file larger than 1 MB or not a JPG/PNG.
🏠 Homework
- Build a profile-picture uploader that validates type and size, stores the image with a unique name, and shows it back to the user.