複数ファイルのアップロード
input
で異なった name
を
使用することにより、複数のファイルをアップロードすることができます。
複数のファイルを一度にアップロードし、自動的にまとめられた情報を 配列で取得することが可能です。これを行うには、HTML フォームで 複数選択可能なセレクトやチェックボックスを指定する際と同様、 配列を用いた投稿用の構文を使用する必要があります。
例1 複数ファイルのアップロード
<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'] が設定されます。
例えば、ファイル名が /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] も設定されます。
max_file_uploads は一回のリクエストあたりでアップロードできるファイルの数の制限値となります。 フォームからの一回のリクエストで、 これを超える数のファイルをアップロードしてしまわないようにしましょう。
例2 ディレクトリ全体をアップロードする
HTML のファイルアップロードフィールド中に、
webkitdirectory
属性を指定することで
ディレクトリ全体をアップロードすることができます。
この機能はほとんどのモダンなブラウザでサポートされています。
full_path
の情報を使うと、
相対パスを保存することもできますし、
サーバー上で同じディレクトリを再構築することもできます。
<form action="file-upload.php" method="post" enctype="multipart/form-data"> Send this directory:<br /> <input name="userfile[]" type="file" webkitdirectory multiple /> <input type="submit" value="Send files" /> </form>
webkitdirectory
属性は標準ではありませんし、
標準化の過程にも入っていません。
この属性を Web 上の本番環境で使わないで下さい:
なぜなら、この属性を全ユーザーが使えるとは限らないからです。
また、この属性はクライアントの実装に非互換がある可能性もありますし、
振る舞いが将来変更される可能性もあります。
PHP は ブラウザ/ユーザーエージェントから送られてきた相対パスの情報をパースし、
その情報を $_FILES 配列に渡すことだけを行います。
full_path
配列中の値が、
実際のディレクトリ構造を含んでいるという保証はありません。
よって、PHP アプリケーションはこの情報を信用してはいけません。
User Contributed Notes 8 notes
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'];
}
}
?>
A bit update to 14 year ago note from "phpuser at gmail dot com".
That update converts to a really more friendly array form incoming _POST info for uploaded files.
And that variants works identical for non-multiple uploads and multiple uploads:
<?php
//Функция переформатирует массив поданных POST'ом файлов
function reArrayFiles(&$file_post){
$isMulti = is_array($file_post['name']);
$file_count = $isMulti?count($file_post['name']):1;
$file_keys = array_keys($file_post);
$file_ary = []; //Итоговый массив
for($i=0; $i<$file_count; $i++)
foreach($file_keys as $key)
if($isMulti)
$file_ary[$i][$key] = $file_post[$key][$i];
else
$file_ary[$i][$key] = $file_post[$key];
return $file_ary;
}
?>
This is also needed for <input type=file multiple> elements.
So, if you have an input element like this:
<input type="file" multiple="multiple" name="foobar" />
This should be written as
<input type="file" multiple="multiple" name="foobar[]" />
else you'll only be able to get one of the files.
Just combine temporary path with the filename which will result an array like:
array(2) {
["/tmp/phpAYCvcc"]=> string(10) "file1.jpg"
["/tmp/phpCDg79o"]=> string(10) "file2.jpg"
}
The code:
$files = array_combine(
$_FILES['receipt']['tmp_name'],
$_FILES['receipt']['name']
);
foreach ($files as $key => $value) {
// save your files locally
}
Here is a function to fix the indices of a multi-dimensional for easier parsing when dealing with file uploads. It takes a single $_FILES field array as a parameter and separates each individual uploaded file by numeric key. This allows for iterating like:
<?php
fixFilesArray($_FILES['array_of_files']);
foreach ($_FILES['array_of_files'] as $position => $file) {
// should output array with indices name, type, tmp_name, error, size
var_dump($file);
}
?>
Here's the code:
<?php
/**
* Fixes the odd indexing of multiple file uploads from the format:
*
* $_FILES['field']['key']['index']
*
* To the more standard and appropriate:
*
* $_FILES['field']['index']['key']
*
* @param array $files
* @author Corey Ballou
* @link http://www.jqueryin.com
*/
function fixFilesArray(&$files)
{
$names = array( 'name' => 1, 'type' => 1, 'tmp_name' => 1, 'error' => 1, 'size' => 1);
foreach ($files as $key => $part) {
// only deal with valid keys and multiple files
$key = (string) $key;
if (isset($names[$key]) && is_array($part)) {
foreach ($part as $position => $value) {
$files[$position][$key] = $value;
}
// remove old key reference
unset($files[$key]);
}
}
}
?>
The cleanest way to rearrange the $_FILES
<?php
function rearrange( $arr ){
foreach( $arr as $key => $all ){
foreach( $all as $i => $val ){
$new[$i][$key] = $val;
}
}
return $new;
}
?>
This is a very simple example:
Part I : HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<form action="upload.php" method="post" multipart="" enctype="multipart/form-data">
<input type="file" name="img[]" multiple>
<input type="submit">
</form>
</body>
</html>
Part II : PHP
<?php
echo '<pre>';
$img = $_FILES['img'];
if(!empty($img))
{
$img_desc = reArrayFiles($img);
print_r($img_desc);
foreach($img_desc as $val)
{
$newname = date('YmdHis',time()).mt_rand().'.jpg';
move_uploaded_file($val['tmp_name'],'./uploads/'.$newname);
}
}
function reArrayFiles($file)
{
$file_ary = array();
$file_count = count($file['name']);
$file_key = array_keys($file);
for($i=0;$i<$file_count;$i++)
{
foreach($file_key as $val)
{
$file_ary[$i][$val] = $file[$val][$i];
}
}
return $file_ary;
}
function reArrayImages($file_post) {
$file_ary = [];
$file_keys = array_keys($file_post);
foreach ($file_post as $key => $value) {
foreach ($value as $key2 => $value2) {
$file_ary[$key2][$key] = $value2;
}
}
return $file_ary;
}