PHP
Integrating file upload
Add an optional file upload (e.g. a screenshot) to the contact form.
File upload integration
You may want to let users attach a file (e.g. a screenshot) to the contact form. As you learned in previous groups, an uploaded file arrives in the $_FILES superglobal; each file has name, tmp_name, error and size fields.
You write a handleUpload(array $file): string function. First you check whether $file['error'] equals UPLOAD_ERR_OK; if not, return "skip". Then you check $file['size'] against a size limit (e.g. 2 MB). When everything is fine, you move the file to a permanent location with move_uploaded_file.
Moving with move_uploaded_file
An uploaded file first lands in a temporary path (tmp_name). This file is deleted when the script ends; to keep it, you call move_uploaded_file($file['tmp_name'], $dest) to move it to the target location. When building $dest, use basename($file['name']) for safety, so a user cannot send a path with parent directory segments.
This function only works for real HTTP uploads; in CLI tests it returns false without a warning. The test output stays deterministic this way.
Exercise Write the handleUpload function
Write a handleUpload(array $file): string function. If $file['error'] !== UPLOAD_ERR_OK return "skip". If $file['size'] > 2 * 1024 * 1024 return "skip". Then build the path with $dest = __DIR__ . "/uploads/" . basename($file['name']);, call move_uploaded_file($file['tmp_name'], $dest); and return "ok". For testing, add three files to $_FILES: valid (error=UPLOAD_ERR_OK, size=1024), too big (size=3*1024*1024) and failed (error=UPLOAD_ERR_NO_FILE). Write echo handleUpload($_FILES['ok']) . "/" . handleUpload($_FILES['big']) . "/" . handleUpload($_FILES['err']);.
Show example solution
string { if ($file['error'] !== UPLOAD_ERR_OK) { return "skip"; } if ($file['size'] > 2 * 1024 * 1024) { return "skip"; } $dest = __DIR__ . "/uploads/" . basename($file['name']); move_uploaded_file($file['tmp_name'], $dest); return "ok"; }. Add three files to $_FILES with keys 'ok', 'big', 'err'; echo handleUpload($_FILES['ok']) . "/" . handleUpload($_FILES['big']) . "/" . handleUpload($_FILES['err']);.
Example solution:
<?php
// Add file upload integration
class ContactMessage {
public string $name = "";
public string $email = "";
public string $message = "";
}
function renderForm(): string {
return '<form method="post" action="/contact.php">'
. '<label>Name: <input type="text" name="name"></label>'
. '<label>Email: <input type="email" name="email"></label>'
. '<label>Message: <textarea name="message"></textarea></label>'
. '<input type="submit" value="Send">'
. '</form>';
}
function validateMessage(ContactMessage $m): array {
$errors = [];
if (empty($m->name)) {
$errors[] = "Name empty";
}
if (empty($m->email) || filter_var($m->email, FILTER_VALIDATE_EMAIL) === false) {
$errors[] = "Email invalid";
}
return $errors;
}
function handleUpload(array $file): string {
if ($file['error'] !== UPLOAD_ERR_OK) {
return "skip";
}
if ($file['size'] > 2 * 1024 * 1024) {
return "skip";
}
$dest = __DIR__ . "/uploads/" . basename($file['name']);
move_uploaded_file($file['tmp_name'], $dest);
return "ok";
}
$_FILES = [
'ok' => ['name' => 'image.png', 'type' => 'image/png', 'tmp_name' => '/tmp/temp.tmp', 'error' => UPLOAD_ERR_OK, 'size' => 1024],
'big' => ['name' => 'large.zip', 'type' => 'application/zip', 'tmp_name' => '/tmp/big.tmp', 'error' => UPLOAD_ERR_OK, 'size' => 3 * 1024 * 1024],
'err' => ['name' => '', 'type' => '', 'tmp_name' => '', 'error' => UPLOAD_ERR_NO_FILE, 'size' => 0],
];
echo handleUpload($_FILES['ok']) . "/" . handleUpload($_FILES['big']) . "/" . handleUpload($_FILES['err']);
Test yourself
-
Match the $_FILES keys
- name
- Original file name
- tmp_name
- Temporary path
- size
- File size
- error
- Error code
-
Which key holds the temporary path of the uploaded file?
Show answer
tmp_name — Correct. tmp_name holds the temporary path; move_uploaded_file moves from this path.
-
Complete the move_uploaded_file call
move_uploaded_file($file['____'], __DIR__ . "/uploads/" . basename($file['name']));
Show answer
move_uploaded_file($file['tmp_name'], __DIR__ . "/uploads/" . basename($file['name']));
Next lesson: Project final - Contact form