A practical journey of learning PHP file uploads and downloads, from fixing server issues to building secure handlers. Includes Junior, Mid, and Senior developer test questions, plus full mid-level answers.
Learning PHP file uploads can feel confusing at first — especially when you click Upload and nothing happens.
That’s exactly how my journey started:
But after troubleshooting the server, learning how PHP processes form data, and building upload/download scripts from scratch — everything finally clicked.
In this post, I’ll show you how I learned file uploads in PHP, what mistakes I made, how I fixed them, and the developer tests (Junior, Mid, Senior) I created to measure progress.
The Mid-Level test includes full answers.
At the beginning, I tried opening: upload.php
But instead of code running, I got:
Why?
Because PHP must run through a server, not by opening the file directly.
I also tried:
php -S localhost:8000/upload.php
The right way was to navigate to my project folder:
cd myproject
php -S localhost:8000
Then open:
http://localhost:8000/index.html
After doing that, the form finally executed the PHP script.
Here’s the first working form I created:
<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="myfile">
<button type="submit" name="submit">Upload</button>
</form>
Key lessons:
- enctype="multipart/form-data" is mandatory
- A named submit button triggers $_POST["submit"]
- Uploaded file info is always in $_FILES
- move_uploaded_file() safely stores the file
Once these pieces came together, uploads worked flawlessly.
File downloads taught me about headers. A simple version looks like this:
header('Content-Disposition: attachment; filename="file.ext"');
readfile("uploads/file.ext");
This tells the browser:
“Download this file, don’t display it.”
To measure progress (and help evaluate other developers), I created three tests:
Junior → basic PHP
Mid-Level → practical uploads & security
Senior → architecture, S3, chunked uploads, queues
Below are all the tests — with mid-level answers included.
Allows binary data (like files) to be sent with the form. Required for uploads.
tmp_name: Temporary location of uploaded file on server
name: Original filename from user’s computer
| Risk | Prevention |
|---|---|
| Malicious file types | Validate MIME type |
| Oversized uploads | Max file size checks |
| Directory traversal | Use basename() and sanitize |
It only moves files uploaded through PHP’s upload process, preventing file injection.
Content-Type: application/octet-stream
Content-Disposition: attachment
Content-Length: <size>
The entire POST request is dropped, and $_FILES becomes empty.
Task 1: Secure Upload Handler (Images Only)
<?php
header("Content-Type: application/json");
if (!isset($_FILES['file'])) {
echo json_encode(["status" => "error"]);
exit;
}
$file = $_FILES['file'];
if ($file['error'] !== UPLOAD_ERR_OK) {
echo json_encode(["status" => "error"]);
exit;
}
if ($file['size'] > 2 * 1024 * 1024) { // 2MB
echo json_encode(["status" => "error"]);
exit;
}
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
$allowed = ['image/jpeg', 'image/png'];
if (!in_array($mime, $allowed)) {
echo json_encode(["status" => "error"]);
exit;
}
$ext = $mime === 'image/png' ? 'png' : 'jpg';
$newName = "user_" . time() . "." . $ext;
move_uploaded_file($file['tmp_name'], "uploads/" . $newName);
echo json_encode(["status" => "success", "file" => $newName]);
Task 2: Secure File Download Script
<?php
if (!isset($_GET['file'])) exit("Missing file");
$file = basename($_GET['file']); // Prevent traversal
$path = "uploads/" . $file;
if (!file_exists($path)) exit("Not found");
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $file . '"');
readfile($path);
exit;
Include backend endpoints and chunk assembly algorithm.
Show queue flow and worker design.
Explain how to generate and validate URLs.
Include redirect flow and validation.
Test invalid type, oversized file, failed move, missing tmp file.
Include authentication (JWT), rate limiting, API routes, and DB schema.
I started this journey confused by PHP not executing my upload script. By learning how the server works, how forms submit data, and how files are validated, I was able to build:
secure upload handlers
safe download scripts
multiple file upload systems
developer evaluation tests for every level