上传多个文件

可以对 input 域使用不同的 name 来上传多个文件。

PHP 支持同时上传多个文件并将它们的信息自动以数组的形式组织。要完成这项功能,需要在 HTML 表单中对文件上传域使用和多选框与复选框相同的数组式提交语法。

注: 对多文件上传的支持是在 PHP 3.0.10 版本添加的。

例子 38-4. 上传多个文件

<form action="file-upload.php" method="post" enctype="multipart/form-data">
  Send these files:<br />
  <input name="userfile[]" type="file" /><br />
  <input name="userfile[]" type="file" /><br />
  <input type="submit" value="Send files" />
</form>

当以上表单被提交后,数组 $_FILES['userfile']$_FILES['userfile']['name']$_FILES['userfile']['size'] 将被初始化(在 PHP 4.1.0 以前版本是 $HTTP_POST_FILES)。如果 register_globals 的设置为 on,则和文件上传相关的全局变量也将被初始化。所有这些提交的信息都将被储存到以数字为索引的数组中。

例如,假设名为 /home/test/review.html/home/test/xwp.out 的文件被提交,则 $_FILES['userfile']['name'][0] 的值将是 review.html,而 $_FILES['userfile']['name'][1] 的值将是 xwp.out。类似的,$_FILES['userfile']['size'][0] 将包含文件 review.html 的大小,依此类推。

此外也同时设置了 $_FILES['userfile']['name'][0]$_FILES['userfile']['tmp_name'][0]$_FILES['userfile']['size'][0] 以及 $_FILES['userfile']['type'][0]


add a note add a note User Contributed Notes
Bob Doe
09-Aug-2005 05:17
Here is a the simple test form I needed, pieced togther from 2 or 3 posts in the documentation elsewhere.

<html>
<head>
<title>HTML Form for uploading image to server</title>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<p>Pictures:
<input type="file" name="pictures[]" />
<input type="file" name="pictures[]" />
<input type="file" name="pictures[]" />
<input type="submit" value="Send" />
</p>
</form>
<?php
//places files into same dir as form resides
foreach ($_FILES["pictures"]["error"] as $key => $error) {
   if (
$error == UPLOAD_ERR_OK) {
       echo
"$error_codes[$error]";
      
move_uploaded_file(
        
$_FILES["pictures"]["tmp_name"][$key],
        
$_FILES["pictures"]["name"][$key]
       ) or die(
"Problems with upload");
   }
}
?>
</body>
</html>
29-Jul-2005 10:50
re: phpuser's comment

I found that if instead of the form structure at the top of the page use one like this:

<form action="file-upload.php" method="post" enctype="multipart/form-data">
  Send these files:<br />
  <input name="userfile1" type="file" /><br />
  <input name="userfile2" type="file" /><br />
  <input type="submit" value="Send files" />
</form>

Notice the names are unique and not an array element.  Now the array is structured more like phpuser would like. I did this and used...

foreach ($_FILES as $file) { ... }

without issue.
sgoodman_at_nojunk_immunetolerance.org
17-Jun-2005 10:03
Re: phpuser_at_gmail's comment, a simpler way to have create that data structure is to name your HTML file inputs different names. If you want to upload multiple files, use:
<input type=file name=file1>
<input type=file name=file2>
<input type=file name=file3>
etc...
Each field name will be a key in the $_FILES array.
bishop
03-Jun-2005 02:27
Elaboration on phpuser at gmail dot com reArrayFiles() function (which assumed sequential, integer keys and uni-dimensional), this function will work regardless of key and key depth:

<?php
// information grouper
function groupFileInfoByVariable(&$top, $info, $attr) {
   if (
is_array($info)) {
       foreach (
$info as $var => $val) {
           if (
is_array($val)) {
              
groupFileInfoByVariable($top[$var], $val, $attr);
           } else {
              
$top[$var][$attr] = $val;
           }
       }
   } else {
      
$top[$attr] = $info;
   }

   return
true;
}

// usage
$newOrdering = array ();
foreach (
$_FILES as $var => $info) {
   foreach (
array_keys($info) as $attr) {
      
groupFileInfoByVariable($newOrdering, $info[$attr], $attr);
   }
}

// $newOrdering holds the updated order
?>
phpuser at gmail dot com
26-May-2005 11:09
When uploading multiple files, the $_FILES variable is created in the form:

Array
(
   [name] => Array
       (
           [0] => foo.txt
           [1] => bar.txt
       )

   [type] => Array
       (
           [0] => text/plain
           [1] => text/plain
       )

   [tmp_name] => Array
       (
           [0] => /tmp/phpYzdqkD
           [1] => /tmp/phpeEwEWG
       )

   [error] => Array
       (
           [0] => 0
           [1] => 0
       )

   [size] => Array
       (
           [0] => 123
           [1] => 456
       )
)

I found it made for a little cleaner code if I had the uploaded files array in the form

Array
(
   [0] => Array
       (
           [name] => foo.txt
           [type] => text/plain
           [tmp_name] => /tmp/phpYzdqkD
           [error] => 0
           [size] => 123
       )

   [1] => Array
       (
           [name] => bar.txt
           [type] => text/plain
           [tmp_name] => /tmp/phpeEwEWG
           [error] => 0
           [size] => 456
       )
)

I wrote a quick function that would convert the $_FILES array to the cleaner (IMHO) array.

<?php

function reArrayFiles(&$file_post) {

  
$file_ary = array();
  
$file_count = count($file_post['name']);
  
$file_keys = array_keys($file_post);

   for (
$i=0; $i<$file_count; $i++) {
       foreach (
$file_keys as $key) {
          
$file_ary[$i][$key] = $file_post[$key][$i];
       }
   }

   return
$file_ary;
}

?>

Now I can do the following:

<?php

if ($_FILES['upload']) {
  
$file_ary = reArrayFiles($_FILES['ufile']);

   foreach (
$file_ary as $file) {
       print
'File Name: ' . $file['name'];
       print
'File Type: ' . $file['type'];
       print
'File Size: ' . $file['size'];
   }
}

?>