文件上传处理
在线手册:中文 英文
PHP手册

错误信息说明

从 PHP 4.2.0 开始,PHP 将随文件信息数组一起返回一个对应的错误代码。该代码可以在文件上传时生成的文件数组中的 error 字段中被找到,也就是 $_FILES['userfile']['error']

UPLOAD_ERR_OK

其值为 0,没有错误发生,文件上传成功。

UPLOAD_ERR_INI_SIZE

其值为 1,上传的文件超过了 php.iniupload_max_filesize 选项限制的值。

UPLOAD_ERR_FORM_SIZE

其值为 2,上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。

UPLOAD_ERR_PARTIAL

其值为 3,文件只有部分被上传。

UPLOAD_ERR_NO_FILE

其值为 4,没有文件被上传。

UPLOAD_ERR_NO_TMP_DIR

其值为 6,找不到临时文件夹。PHP 4.3.10 和 PHP 5.0.3 引进。

UPLOAD_ERR_CANT_WRITE

其值为 7,文件写入失败。PHP 5.1.0 引进。

Note:

以上值在 PHP 4.3.0 之后变成了 PHP 常量。


文件上传处理
在线手册:中文 英文
PHP手册
PHP手册 - N: 错误信息说明

用户评论:

Anonymous (28-Jan-2012 02:49)

<?php
// Sorry, where says
define("UPLOAD_ERR_EMPTY",5);
   if(
$file['size'] == 0){
    
$file['error'] = 5;
   }
// Should say
define("UPLOAD_ERR_EMPTY",5);
   if(
$file['size'] == 0 && $file['error'] == 0){
    
$file['error'] = 5;
   }
// Please can anyone edit that?
?>

capitanqueso (28-Jan-2012 02:09)

<?php
/*
If you ever try to upload an empty file using fread(), php may show a nasty warning (according to your "error_reporting") about "Length parameter must be greater than 0"
especially if you are parsing this as xml.
So in order to handle this error from here you may do the next:
*/
$file = $_FILES['file'];
$error_text = true; // Show text or number
define("UPLOAD_ERR_EMPTY",5);
  if(
$file['size'] == 0){
   
$file['error'] = 5;
  }
 
$upload_errors = array(
   
UPLOAD_ERR_OK        => "No errors.",
   
UPLOAD_ERR_INI_SIZE    => "Larger than upload_max_filesize.",
   
UPLOAD_ERR_FORM_SIZE    => "Larger than form MAX_FILE_SIZE.",
   
UPLOAD_ERR_PARTIAL    => "Partial upload.",
   
UPLOAD_ERR_NO_FILE        => "No file.",
   
UPLOAD_ERR_NO_TMP_DIR    => "No temporary directory.",
   
UPLOAD_ERR_CANT_WRITE    => "Can't write to disk.",
   
UPLOAD_ERR_EXTENSION     => "File upload stopped by extension.",
   
UPLOAD_ERR_EMPTY        => "File is empty." // add this to avoid an offset
 
);
  
// error: report what PHP says went wrong
  
$err = ($error_text) ? $upload_errors[$file['error']] : $file['error'] ;
  
header("Content-Type: text/xml");
   echo
'<errors>
             <error>'
.
              
$err .'
             </error>
           </errors>
   '
;
  
// Add your code to prevent fread() to run, either from here or with a previous "if"
?>

Jeff Miner mrjminer AT gmail DOT com (10-Aug-2010 09:32)

One thing that is annoying is that the way these constant values are handled requires processing no error with the equality, which wastes a little bit of space.  Even though "no error" is 0, which typically evaluates to "false" in an if statement, it will always evaluate to true in this context.

So, instead of this:
-----
<?php
if($_FILES['userfile']['error']) {
 
// handle the error
} else {
 
// process
}
?>
-----
You have to do this:
-----
<?php
if($_FILES['userfile']['error']==0) {
 
// process
} else {
 
// handle the error
}
?>
-----
Also, ctype_digit fails, but is_int works.  If you're wondering... no, it doesn't make any sense.

To Schoschie:

You ask the question:  Why make stuff complicated when you can make it easy?  I ask the same question since the version of the code you / Anonymous / Thalent (per danbrown) have posted is unnecessary overhead and would result in a function call, as well as a potentially lengthy switch statement.  In a loop, that would be deadly... try this instead:

-----
<?php
$error_types
= array(
1=>'The uploaded file exceeds the upload_max_filesize directive in php.ini.',
'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.',
'The uploaded file was only partially uploaded.',
'No file was uploaded.',
6=>'Missing a temporary folder.',
'Failed to write file to disk.',
'A PHP extension stopped the file upload.'
);

// Outside a loop...
if($_FILES['userfile']['error']==0) {
 
// process
} else {
 
$error_message = $error_types[$_FILES['userfile']['error']];
 
// do whatever with the error message
}

// In a loop...
for($x=0,$y=count($_FILES['userfile']['error']);$x<$y;++$x) {
  if(
$_FILES['userfile']['error'][$x]==0) {
   
// process
 
} else {
   
$error_message = $error_types[$_FILES['userfile']['error'][$x]];
   
// Do whatever with the error message
 
}
}

// When you're done... if you aren't doing all of this in a function that's about to end / complete all the processing and want to reclaim the memory
unset($error_types);
?>

Tom (09-Aug-2010 11:06)

Note: something that might surprise you, PHP also provides a value in the $_FILES array, if the input element has no value at all, stating an error UPLOAD_ERR_NO_FILE.

So UPLOAD_ERR_NO_FILE is not an error, but a note that the input element just had no value. Thus you can't rely on the $_FILES array to see if a file was provided. Instead you have to walk the array and check every single damn entry - which can be quite difficult since the values may be nested if you use input elements named like "foo[bar][bla]".

Seems like PHP just introduced you to yet another common pitfall.

fbsoft01 at yahoo dot com (08-Jul-2010 11:10)

Hy guys, i've been trying to set an upload.php script on my Slack 11 machine, unfortunely i always get UPLOAD_ERR_CANT_WRITE, but in that folder the file actually doesn't exists and the folder is set with the user and group set in apache , and i chmod'it to 0777 or 0755 neither worked.
Also php ver is 5.2.3 and apache 2.2.4
NEEED HEEEELP :)

bohwaz (19-Feb-2010 12:41)

If you are having a UPLOAD_ERR_NO_TMP_DIR (#6) error then check if you're not using open_basedir. If so, make sure to add /tmp to open_basedir, like that (for apache2) :

php_admin_value open_basedir /home/bohwaz/:/tmp/

Don't forget the trailing slash.

jille at quis dot cx (24-May-2009 04:12)

UPLOAD_ERR_PARTIAL is given when the mime boundary is not found after the file data. A possibly cause for this is that the upload was cancelled by the user (pressed ESC, etc).

Schoschie (nh t ngin dott de) (26-Apr-2009 05:43)

Why make stuff complicated when you can make it easy?

[Edit of edit by danbrown AT php DOT net: This code is a fixed version of a note originally submitted by (Thalent, Michiel Thalen) on 04-Mar-2009.]

<?php

function file_upload_error_message($error_code) {
    switch (
$error_code) {
        case
UPLOAD_ERR_INI_SIZE:
            return
'The uploaded file exceeds the upload_max_filesize directive in php.ini';
        case
UPLOAD_ERR_FORM_SIZE:
            return
'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
        case
UPLOAD_ERR_PARTIAL:
            return
'The uploaded file was only partially uploaded';
        case
UPLOAD_ERR_NO_FILE:
            return
'No file was uploaded';
        case
UPLOAD_ERR_NO_TMP_DIR:
            return
'Missing a temporary folder';
        case
UPLOAD_ERR_CANT_WRITE:
            return
'Failed to write file to disk';
        case
UPLOAD_ERR_EXTENSION:
            return
'File upload stopped by extension';
        default:
            return
'Unknown upload error';
    }
}

// Example
if ($_FILES['file']['error'] === UPLOAD_ERR_OK)
   
// upload ok
else
   
$error_message = file_upload_error_message($_FILES['file']['error']);

?>

Anonymous (05-Mar-2009 02:32)

[EDIT BY danbrown AT php DOT net: This code is a fixed version of a note originally submitted by (Thalent, Michiel Thalen) on 04-Mar-2009.]


This is a handy exception to use when handling upload errors:

<?php

class UploadException extends Exception
{
    public function
__construct($code) {
       
$message = $this->codeToMessage($code);
       
parent::__construct($message, $code);
    }

    private function
codeToMessage($code)
    {
        switch (
$code) {
            case
UPLOAD_ERR_INI_SIZE:
               
$message = "The uploaded file exceeds the upload_max_filesize directive in php.ini";
                break;
            case
UPLOAD_ERR_FORM_SIZE:
               
$message = "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form";
                break;
            case
UPLOAD_ERR_PARTIAL:
               
$message = "The uploaded file was only partially uploaded";
                break;
            case
UPLOAD_ERR_NO_FILE:
               
$message = "No file was uploaded";
                break;
            case
UPLOAD_ERR_NO_TMP_DIR:
               
$message = "Missing a temporary folder";
                break;
            case
UPLOAD_ERR_CANT_WRITE:
               
$message = "Failed to write file to disk";
                break;
            case
UPLOAD_ERR_EXTENSION:
               
$message = "File upload stopped by extension";
                break;

            default:
               
$message = "Unknown upload error";
                break;
        }
        return
$message;
    }
}

// Use
 
if ($_FILES['file']['error'] === UPLOAD_ERR_OK) {
//uploading successfully done
} else {
throw new
UploadException($_FILES['file']['error']);
}
?>

info at foto50 dot com (03-Jul-2007 10:03)

For those reading this manual in german (and/or probably some other languages) and you miss error numbers listed here, have a look to the english version of this page ;)

belowtherim2000 at yahoo dot com (21-Jun-2007 02:25)

I've been playing around with the file size limits and with respect to the post_max_size setting, there appears to be a hard limit of 2047M.  Any number that you specify above that results in a failed upload without any informative error describing what went wrong.  This happens regardless of how small the file you're uploading may be.  On error, my page attempts to output the name of the original file.  But what I discovered is that this original file name, which I maintained in a local variable, actually gets corrupted.  Even my attempt to output the error code in $_FILES['uploadedfiles']['error'] returns an empty string/value.

Hopefully, this tidbit will save someone else some grief.

svenr at selfhtml dot org (23-Apr-2007 11:15)

Clarification on the MAX_FILE_SIZE hidden form field and the UPLOAD_ERR_FORM_SIZE error code:

PHP has the somewhat strange feature of checking multiple "maximum file sizes".

The two widely known limits are the php.ini settings "post_max_size" and "upload_max_size", which in combination impose a hard limit on the maximum amount of data that can be received.

In addition to this PHP somehow got implemented a soft limit feature. It checks the existance of a form field names "max_file_size" (upper case is also OK), which should contain an integer with the maximum number of bytes allowed. If the uploaded file is bigger than the integer in this field, PHP disallows this upload and presents an error code in the $_FILES-Array.

The PHP documentation also makes (or made - see bug #40387 - http://bugs.php.net/bug.php?id=40387) vague references to "allows browsers to check the file size before uploading". This, however, is not true and has never been. Up til today there has never been a RFC proposing the usage of such named form field, nor has there been a browser actually checking its existance or content, or preventing anything. The PHP documentation implies that a browser may alert the user that his upload is too big - this is simply wrong.

Please note that using this PHP feature is not a good idea. A form field can easily be changed by the client. If you have to check the size of a file, do it conventionally within your script, using a script-defined integer, not an arbitrary number you got from the HTTP client (which always must be mistrusted from a security standpoint).

abuse dot bernhardkroll at arcor dot de (06-Apr-2007 02:08)

For a multifile upload try this:

<?php

foreach($_FILES as $file)
{
    if(
$file['error'] == 0 && $file['size'] > 0)
    {
       
move_uploaded_file($file['tmp_name'], $targetdir.$file['name']);
    }
}

?>

web att lapas dott id dott lv (23-Feb-2007 01:49)

1. And what about multiple file upload ? - If there is an UPLOAD_ERR_INI_SIZE error with multiple files - we can`t detect it normaly ? ...because that we have an array, but this error returns null and can`t use foreach. So, by having a multiple upload, we can`t normaly inform user about that.. we can just detect, that sizeof($_FILES["file"]["error"]) == 0 , but we can`t actualy return an error code. The max_file_size also is not an exit, becouse it refers on each file seperatly, but upload_max_filesize directive in php.ini refers to all files together. So, for example, if upload_max_filesize=8Mb , max_file_size = 7Mb and one of my files is 6.5Mb and other is 5Mb, it exeeds the upload_max_filesize - cant return an error, becouse we don`t know where to get that error.
Unfortunately we cannot get the file sizes on client side, even AJAX normaly can`t do that.

2. If in file field we paste something, like, D:\whatever , then there also isn`t an error to return in spite of that no such file at all.

stephen at poppymedia dot co dot uk (26-Sep-2005 11:05)

if post is greater than post_max_size set in php.ini

$_FILES and $_POST will return empty

adam at gotlinux dot us (27-May-2005 03:28)

This is probably useful to someone.

<?php
array(
       
0=>"There is no error, the file uploaded with success",
       
1=>"The uploaded file exceeds the upload_max_filesize directive in php.ini",
       
2=>"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"
       
3=>"The uploaded file was only partially uploaded",
       
4=>"No file was uploaded",
       
6=>"Missing a temporary folder"
);
?>

sysadmin at cs dot fit dot edu (16-Feb-2005 03:13)

I noticed that on PHP-4.3.2 that $_FILES can also not be set if the file uploaded exceeds the limits set by upload-max-filesize in the php.ini, rather than setting error $_FILES["file"]["error"]

krissv at ifi.uio.no (28-Jan-2005 12:11)

When $_FILES etc is empty like Dub spencer says in the note at the top and the error is not set, that might be because the form enctype isnt sat correctly. then nothing more than maybe a http server error happens.

enctype="multipart/form-data" works fine

Dub Spencer (26-Nov-2004 02:56)

Upload doesnt work, and no error?

actually, both $_FILES and $_REQUEST in the posted to script are empty?

just see, if  "post_max_size" is lower than the data you want to load.

in the apache error log, there will be an entry like "Invalid method in request". and in the access log, there will be two requests: one for the POST, and another that starts with all "----" and produces a 501.

tyler at fishmas dot org (04-Nov-2004 03:08)

In regards to the dud filename being sent, a very simple way to check for this is to check the file size as well as the file name.  For example, to check the file size simple use the size attribute in your file info array:

<?php
if($_FILES["file_id"]["size"]  == 0)
{
        
// ...PROCESS ERROR
}
?>