在PHP中比较服务器上的大文件大小和post请求中的大小

在PHP中比较服务器上的大文件大小和post请求中的大小

问题描述:

I have an Apache server where files are uploaded in an HTTP post request (<form enctype="multipart/form-data" action="upload.php" method="post">). It happens from time to time (very rarely, but it happens nonetheless), for reasons that still elude me, that after a file has been uploaded, its size on disk will not match the size of the original file.

What I'd like to do is to catch those errors before returning from the PHP script which copies the file from /tmp to its final destination. My first idea was to compare $_FILES['uploadedfile']['size'] and filesize($target_path), which seems to work fine for files up to 2GB. However, as soon as the file size's number of bytes is over 32 bits long, $_FILES['uploadedfile']['size'] overflows and becomes negative. Moreover, I suspect that using this value as the "reference file size" might be too late in the upload process (i.e. it's the file size on the server, not on the client).

There's the possibility of extracting the file size from $_SERVER['CONTENT_LENGTH'], but this value also includes what seems to be request "metadata", and I could not find documentation on how to separate that data from the actual file size (the "metadata" size changes from request to request)

The easiest way would be to ask the client to post the source's file size as a request parameter, but I'd like to have as little change as possible on the client's side.

I was also told an "HTTP PUT" could prevent the problem in the first place, but I'm still in the early stages of investigating that. I'd still like to find a solution with my current POST method.

For reference, my upload script looks approximately like this now:

$id = strtolower($_POST["assetid"]);
$project = strtolower($_POST["project"]);
$target_path = Settings::getAssetPath($project,$id);

if (move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
    if (filesize($target_path) != $_FILES['uploadedfile']['size']){
        header("HTTP/1.0 500 Internal Server Error");
        $result .= "Uploaded file size does not match source file size!<br />";
    }
    else {
        header("HTTP/1.0 200 OK");
        $result .= "The file " . basename($_FILES['uploadedfile']['name']) . " has been uploaded successfully.";
    }
} else {
    header("HTTP/1.0 500 Internal Server Error");
    $result .= "There was an error uploading the file, please try again!<br />";
}

Any ideas are very welcome!

Your upload script is incorrect. ['size'] is what has been received by the server. If the upload aborts/fails for any reason, ['size'] WILL be incorrect. You must check for upload success before doing ANYTHING with the upload data:

if($_FILES['uploadedfile']['error'] !== UPLOAD_ERR_OK) {
   die("Upload failed with error code " . $_FILES['uploadedfile']['error']);
}

the error codes are defined here: http://www.php.net/manual/en/features.file-upload.errors.php