is_uploaded_file

Checks whether the given path is a file that was uploaded to this request via HTTP POST.

Signature
is_uploaded_file(string $filename): bool
  • Added in PHP 4.0.3

Parameters

ParameterTypeDescription
$filenamestringThe path to test. This must be the server-side temporary path, i.e. $_FILES['field']['tmp_name'].

Return value

booltrue if the file at filename was uploaded via HTTP POST in the current request, false otherwise.

Errors

Does not throw; it returns false for any path PHP did not register as an upload in this request.

When PHP handles a multipart/form-data POST it writes each uploaded part to a temporary file and records that path in an internal list. is_uploaded_file() simply asks whether a path is on that list. Nothing else — not a path in the temp directory, not a file you created yourself — will make it return true.

When to reach for it

Use it in any handler that accepts a filename from the client and then reads, copies, or deletes that file. Without the check, an attacker who can influence the path can point your "upload processor" at /etc/passwd, a session file, or your own configuration, and your code will happily read it out or move it into the public web root.

What trips people up

The single most common bug is passing $_FILES['f']['name'] instead of $_FILES['f']['tmp_name']. The name key is the original filename from the client's machine, is entirely attacker-controlled, and is not a path on your server, so the check always fails. Also note that move_uploaded_file() performs this same validation internally: if you move the file with it, a separate is_uploaded_file() call is redundant. The extra call earns its place when you want to fopen() or hash the temp file before deciding where it goes.

Example

Example · php
<?php
// Upload handler: run inside a real POST request.
if (!isset($_FILES['avatar']) || $_FILES['avatar']['error'] !== UPLOAD_ERR_OK) {
    exit("No usable upload\n");
}

$tmp = $_FILES['avatar']['tmp_name'];
if (!is_uploaded_file($tmp)) {
    exit("Refusing: not an HTTP POST upload\n");
}

echo "Accepted ", $_FILES['avatar']['size'], " bytes\n";
echo "sha256: ", hash_file('sha256', $tmp), "\n";

When to use it

  • Validate the temp path before hashing or virus-scanning an upload in place, ahead of deciding its final location.
  • Guard a legacy handler that takes a path from the request and reads it back to the browser.
  • Reject requests where the upload field was forged as a plain POST string rather than a real file part.

Frequently asked questions

Do I need is_uploaded_file if I already use move_uploaded_file?

No. move_uploaded_file() performs the same check internally and fails if the source was not an upload. The separate call is only worth it when you read, hash, or scan the temporary file before moving it.

Why does is_uploaded_file always return false for my upload?

Almost always because you passed $_FILES['field']['name'] instead of $_FILES['field']['tmp_name']. The name key holds the client's original filename, which is not a path on your server.

Does is_uploaded_file validate the file type or contents?

No, it only confirms the file arrived through this request's POST body. Use finfo or getimagesize() to check what is actually inside, and never trust the client-supplied MIME type in $_FILES['field']['type'].

More examples

Inspect before moving

The guard runs before finfo touches the file, so a forged path can never be sniffed or stored. The final filename is generated server-side, so the client's chosen name never reaches the filesystem.

Example · php
<?php
$tmp = $_FILES['doc']['tmp_name'] ?? '';

if (!is_uploaded_file($tmp)) {
    http_response_code(400);
    exit('bad upload');
}

$mime = (new finfo(FILEINFO_MIME_TYPE))->file($tmp);
if ($mime !== 'application/pdf') {
    exit("rejected: $mime\n");
}

move_uploaded_file($tmp, 'storage/' . bin2hex(random_bytes(8)) . '.pdf');
echo "stored\n";

Handling a multi-file field

With <input type="file" name="photos[]"> PHP transposes the array, so tmp_name is a list. Each entry still needs its own error check and its own is_uploaded_file() call.

Example · php
<?php
$files = $_FILES['photos'] ?? ['tmp_name' => []];

foreach ($files['tmp_name'] as $i => $tmp) {
    if ($files['error'][$i] !== UPLOAD_ERR_OK || !is_uploaded_file($tmp)) {
        echo "skip #$i\n";
        continue;
    }
    echo "#$i ok, ", filesize($tmp), " bytes\n";
}

Discussion

  • Be the first to comment on this lesson.