CodeBlanks Logo Icon CodeBlanks

Integrating file upload

PHP course · Intermediate · Lesson 97/115

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

  1. Match the $_FILES keys

    name
    Original file name
    tmp_name
    Temporary path
    size
    File size
    error
    Error code
  2. Which key holds the temporary path of the uploaded file?

    • tmp_name
    • name
    • size
    • error
    Show answer

    tmp_name — Correct. tmp_name holds the temporary path; move_uploaded_file moves from this path.

  3. 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']));

All lessons in Intermediate