如何使用HTML和PHP,通过HTTP POST选择并上传多个文件?

176

我有使用 <input type="file"> 上传单个文件的经验。但是,我在尝试上传多个文件时遇到了困难。

例如,我想选择一系列的图片然后一次性将它们全部上传到服务器上。

如果可能的话,最好使用一个单独的文件输入控件。

有没有人知道如何实现这个功能呢?


3
您是说在文件选择对话框中选择多个文件,还是使用多个文件输入? - MitMaro
1
你好,您是否可以上传一个归档文件(zip、rar、tar等)? - sourcerebels
9个回答

221

这在HTML5中是可能的。例如(PHP 5.4):

<!doctype html>
<html>
    <head>
        <title>Test</title>
    </head>
    <body>
        <form method="post" enctype="multipart/form-data">
            <input type="file" name="my_file[]" multiple>
            <input type="submit" value="Upload">
        </form>
        <?php
            if (isset($_FILES['my_file'])) {
                $myFile = $_FILES['my_file'];
                $fileCount = count($myFile["name"]);

                for ($i = 0; $i < $fileCount; $i++) {
                    ?>
                        <p>File #<?= $i+1 ?>:</p>
                        <p>
                            Name: <?= $myFile["name"][$i] ?><br>
                            Temporary file: <?= $myFile["tmp_name"][$i] ?><br>
                            Type: <?= $myFile["type"][$i] ?><br>
                            Size: <?= $myFile["size"][$i] ?><br>
                            Error: <?= $myFile["error"][$i] ?><br>
                        </p>
                    <?php
                }
            }
        ?>
    </body>
</html>

在Chrome中选择两个项目后,它看起来像这样:

chrome multiple file select

点击“上传”按钮后,它看起来像这样:

submitting multiple files to PHP

这只是一个完全工作答案的草图。有关在PHP中正确、安全地处理文件上传的更多信息,请参见PHP手册:处理文件上传


10
它是否通过W3C验证,或者应该使用multiple =“multiple” - vol7ron
10
我相信这是有效的:http://thoughtresults.com/html5-boolean-attributes。如果您添加<!doctype html>,它将通过w3c验证器。 - Mark E. Haase
2
是的,它可能会验证HTML,但无法通过XHTML。尽管我仍然喜欢使用XHTML,但我认为现在人们建议远离它。 - vol7ron
11
如果不添加属性name(例如name="file[]"),它就无法工作。我尝试编辑答案,但被拒绝了。 - Michel Ayres
1
谢谢@MichelAyres,我已经更新了我的回答。当我最初写这个回答时,我只解决了问题的HTML部分,因为有其他的答案解释了PHP部分。随着时间的推移,这变成了一个受欢迎的答案,所以我现在扩展到涵盖HTML和PHP两个方面。 - Mark E. Haase
1
我们如何限制用户在上传文件时只能使用Shift或Control键选择三个文件? - Rahul

98

要创建多文件上传,你需要做以下几件事情,其实很基础:不需要使用Java、Ajax或Flash,只需从以下内容开始构建普通的文件上传表单:

<form enctype="multipart/form-data" action="post_upload.php" method="POST">

成功的关键在于:

<input type="file" name="file[]" multiple />

不要忘记这些方括号!在post_upload.php中尝试以下代码:

<?php print_r($_FILES['file']['tmp_name']); ?>

请注意,你将得到一个包含 tmp_name 数据的数组,这意味着你可以通过第三对方括号访问每个文件,例如:

$_FILES['file']['tmp_name'][0]

您可以使用PHP的count()函数来计算选择的文件数量。祝好运!


5
谢谢你的建议!它为我节省了很多时间。+1 - BPm
它运行得非常好...但我在Internet Explorer(v8)中以这种方式上传遇到了问题。我认为IE不支持这种上传方式。 - Tariq M Nasim
4
您可以使用foreach语句循环遍历文件,而无需知道上传的文件数量... - ygesher
请注意,如果您在HTML中使用名称中的键,例如name="file[3]",则需要通过$_FILES['file']['tmp_name'][3]访问该值,以防不明显。 - MyStream

8

在Firefox 5中的完整解决方案:

<html>
<head>
</head>
<body>
 <form name="uploader" id="uploader" action="multifile.php" method="POST" enctype="multipart/form-data" >
  <input id="infile" name="infile[]" type="file" onBlur="submit();" multiple="true" ></input> 
 </form>

<?php
echo "No. files uploaded : ".count($_FILES['infile']['name'])."<br>"; 


$uploadDir = "images/";
for ($i = 0; $i < count($_FILES['infile']['name']); $i++) {

 echo "File names : ".$_FILES['infile']['name'][$i]."<br>";
 $ext = substr(strrchr($_FILES['infile']['name'][$i], "."), 1); 

 // generate a random new file name to avoid name conflict
 $fPath = md5(rand() * time()) . ".$ext";

 echo "File paths : ".$_FILES['infile']['tmp_name'][$i]."<br>";
 $result = move_uploaded_file($_FILES['infile']['tmp_name'][$i], $uploadDir . $fPath);

 if (strlen($ext) > 0){
  echo "Uploaded ". $fPath ." succefully. <br>";
 }
}
echo "Upload complete.<br>";
?>

</body>
</html>

代码被剪切了。这是它上面的内容: <html> <head> </head> <body> <form name="uploader" id="uploader" action="multifile.php" method="POST" enctype="multipart/form-data" > <input id="infile" name="infile[]" type="file" onBlur="submit();" multiple="true" ></input> </form> - Thaps
3
在IE8中它无法工作,建议使用一个真正的浏览器。 - Thaps

6
<form action="" method="POST" enctype="multipart/form-data">
  Select image to upload:
  <input type="file"   name="file[]" multiple/>
  <input type="submit" name="submit" value="Upload Image" />
</form>

使用FOR循环

<?php    
  $file_dir  = "uploads";    
  if (isset($_POST["submit"])) {

    for ($x = 0; $x < count($_FILES['file']['name']); $x++) {               

      $file_name   = $_FILES['file']['name'][$x];
      $file_tmp    = $_FILES['file']['tmp_name'][$x];

      /* location file save */
      $file_target = $file_dir . DIRECTORY_SEPARATOR . $file_name; /* DIRECTORY_SEPARATOR = / or \ */

      if (move_uploaded_file($file_tmp, $file_target)) {                        
        echo "{$file_name} has been uploaded. <br />";                      
      } else {                      
        echo "Sorry, there was an error uploading {$file_name}.";                               
      }                 

    }               
  }    
?>

使用FOREACH循环

<?php
  $file_dir  = "uploads";    
  if (isset($_POST["submit"])) {

    foreach ($_FILES['file']['name'] as $key => $value) {                   

      $file_name   = $_FILES['file']['name'][$key];
      $file_tmp    = $_FILES['file']['tmp_name'][$key];

      /* location file save */
      $file_target = $file_dir . DIRECTORY_SEPARATOR . $file_name; /* DIRECTORY_SEPARATOR = / or \ */

      if (move_uploaded_file($file_tmp, $file_target)) {                        
        echo "{$file_name} has been uploaded. <br />";                      
      } else {                      
        echo "Sorry, there was an error uploading {$file_name}.";                               
      }                 

    }               
  }
?>

6
在开始之前,你应该创建一个像这样的表单:
<form method="post" enctype="multipart/form-data" >
   <input type="file" name="file[]" multiple id="file"/>
   <input type="submit" name="ok"  />
</form> 

那太好了。现在在您的表单代码下面或任何您喜欢的页面上添加这段代码。
<?php
if(isset($_POST['ok']))
   foreach ($_FILES['file']['name'] as $filename) {
    echo $filename.'<br/>';
}
?>

这很容易...完成


5
如果您想从文件选择对话框中选择多个文件,那么大多数情况下您会比较困难。您需要使用Java applet或类似的东西(我认为有一种使用小型Flash文件的方法,如果我找到了,我会更新)。目前,单个文件输入仅允许选择单个文件。
如果您要使用多个文件输入,则与使用一个文件输入没有太大区别。发布一些代码,我会尽力帮助您进一步。
更新: 有一种方法可以使用单个“浏览”按钮,它使用了Flash。我个人从未使用过这个,但我已经阅读了相当多关于它的内容。我认为这是您最好的选择。 http://swfupload.org/

1
我添加了基于Flash的多文件上传器的链接。 - MitMaro
我用过swfupload,它有时候会让人感到有点麻烦,但实际上并不难使用。 - Meep3D
@Barsoom 是正确的。在过去几年中,多文件上传方面已经有了很大的改进。 :D - MitMaro

1
如果您使用多个输入字段,可以设置name="file[]"(或任何其他名称)。这将在上传时将它们放入一个数组中($_FILES['file'] = array ({file_array},{file_array]..))。

0

1
你可以使用PEAR包,但这个任务相当简单,除非你需要该包提供的额外功能(国际化错误消息、验证等),否则我建议使用本地PHP函数。但这只是我的个人意见。 :) - MitMaro
1
我同意你的观点,这也是为什么我写了“部分答案”的原因。但我也尽力重复使用代码,并且我经常尽可能多地使用pear(pear编码人员比我好得多:-D)。 - damko

0
我创建了一个PHP函数,用于上传多个图片,此函数可以将多个图片上传到特定的文件夹,并将记录保存到数据库中。 在以下代码中,$arrayimage是通过表单发送的图像数组,请注意,它不允许使用多个上传,但您需要创建具有相同名称的不同输入字段,以便在单击按钮时设置动态添加文件输入字段。 $dir是您想要保存图像的目录,$fields是您想要存储在数据库中的字段的名称。
数据库字段必须以数组格式存在,例如,如果您有像ID、名称、地址这样的字段名,则需要像下面这样发布数据:
$fields=array("id"=$_POST['idfieldname'], "name"=$_POST['namefield'],"address"=$_POST['addressfield']);

然后将该字段传递到函数 $fields 中。

$table 是您要存储数据的表的名称。

function multipleImageUpload($arrayimage,$dir,$fields,$table)
{
    //extracting extension of uploaded file
    $allowedExts = array("gif", "jpeg", "jpg", "png");
    $temp = explode(".", $arrayimage["name"]);
    $extension = end($temp);

    //validating image
    if ((($arrayimage["type"] == "image/gif")
    || ($arrayimage["type"] == "image/jpeg")
    || ($arrayimage["type"] == "image/jpg")
    || ($arrayimage["type"] == "image/pjpeg")
    || ($arrayimage["type"] == "image/x-png")
    || ($arrayimage["type"] == "image/png"))

    //check image size

    && ($arrayimage["size"] < 20000000)

    //check iamge extension in above created extension array
    && in_array($extension, $allowedExts)) 
    {
        if ($arrayimage["error"] > 0) 
        {
            echo "Error: " . $arrayimage["error"] . "<br>";
        } 
        else 
        {
            echo "Upload: " . $arrayimage["name"] . "<br>";
            echo "Type: " . $arrayimage["type"] . "<br>";
            echo "Size: " . ($arrayimage["size"] / 1024) . " kB<br>";
            echo "Stored in: ".$arrayimage['tmp_name']."<br>";

            //check if file is exist in folder of not
            if (file_exists($dir."/".$arrayimage["name"])) 
            {
                echo $arrayimage['name'] . " already exists. ";
            } 
            else 
            {
                //extracting database fields and value
                foreach($fields as $key=>$val)
                {
                    $f[]=$key;
                    $v[]=$val;
                    $fi=implode(",",$f);
                    $value=implode("','",$v);
                }
                //dynamic sql for inserting data into any table
                $sql="INSERT INTO " . $table ."(".$fi.") VALUES ('".$value."')";
                //echo $sql;
                $imginsquery=mysql_query($sql);
                move_uploaded_file($arrayimage["tmp_name"],$dir."/".$arrayimage['name']);
                echo "<br> Stored in: " .$dir ."/ Folder <br>";

            }
        }
    } 
    //if file not match with extension
    else 
    {
        echo "Invalid file";
    }
}
//function imageUpload ends here
}

//imageFunctions类在此结束

您可以尝试使用此代码插入多个带有扩展名的图像,此函数是为了检查图像文件而创建的,您可以在代码中替换特定文件的扩展名列表


大家好,我使用文件输入将文档附加到自动生成的电子邮件中。我能够一次性附加多个文档,但我想从不同的目录附加多个文档。目前,如果我这样做,我当前选定的文档将被新选择的文档替换。请问我该如何处理。谢谢。 - Kunbi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接