I think the way an array of attachments works is kind of cumbersome. Usually the PHP guys are right on the money, but this is just counter-intuitive. It should have been more like:
Array
(
[0] => Array
(
[name] => facepalm.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpn3FmFr
[error] => 0
[size] => 15476
)
[1] => Array
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] =>
)
)
and not this
Array
(
[name] => Array
(
[0] => facepalm.jpg
[1] =>
)
[type] => Array
(
[0] => image/jpeg
[1] =>
)
[tmp_name] => Array
(
[0] => /tmp/phpn3FmFr
[1] =>
)
[error] => Array
(
[0] => 0
[1] => 4
)
[size] => Array
(
[0] => 15476
[1] => 0
)
)
Anyways, here is a fuller example than the sparce one in the documentation above:
<?php
foreach ($_FILES["attachment"]["error"] as $key => $error)
{
$tmp_name = $_FILES["attachment"]["tmp_name"][$key];
if (!$tmp_name) continue;
$name = basename($_FILES["attachment"]["name"][$key]);
if ($error == UPLOAD_ERR_OK)
{
if ( move_uploaded_file($tmp_name, "/tmp/".$name) )
$uploaded_array[] .= "Uploaded file '".$name."'.<br/>\n";
else
$errormsg .= "Could not move uploaded file '".$tmp_name."' to '".$name."'<br/>\n";
}
else $errormsg .= "Upload error. [".$error."] on file '".$name."'<br/>\n";
}
?>
POST メソッドによるアップロード
この機能により、テキスト、バイナリファイルの両方をアップロードできるように なります。 PHP の認証機構およびファイル操作関数を用いて、アップロードを許可する ユーザーとアップロード後にそのファイルを使用して行う動作を完全に制御する ことが可能です。
PHP は、全ての RFC-1867 対応ブラウザ(Netscape Navigator 3 以上、 Microsoft からのパッチをあてた Microsoft Internet Explorer 3 または パッチ無しのそれ以降の版を含みます)からファイルのアップロードを 受けることができます。
注意: 関係する設定に関する注記
php.iniの file_uploads, upload_max_filesize, upload_tmp_dir, post_max_size, max_input_time ディレクティブも参照ください。
PHP は Netscape Composer および W3C の Amaya クライアントにより使用される PUT メソッドによるファイルアップロードもサポートしています。詳細は、PUT メソッドのサポート を参照ください。
例1 ファイルアップロード用のフォーム
ファイルアップロード画面は、次のような特別なフォームを作成すること により、作成することができます。
<!-- データのエンコード方式である enctype は、必ず以下のようにしなければなりません -->
<form enctype="multipart/form-data" action="__URL__" method="POST">
<!-- MAX_FILE_SIZE は、必ず "file" input フィールドより前になければなりません -->
<input type="hidden" name="MAX_FILE_SIZE" value="30000" />
<!-- input 要素の名前が $_FILES 配列での名前となります -->
このファイルをアップロード: <input name="userfile" type="file" />
<input type="submit" value="ファイルを送信" />
</form>
上の例の __URL__ は、PHP ファイルを指すよう置換される 必要があります。
hidden フィールドMAX_FILE_SIZE は、 input フィールド file の前に置く必要があります。 この値は、PHP で取得可能なファイルの最大サイズを規定します。この値はバイト数で指定します。 MAX_FILE_SIZE は常に指定しておくべきです。 巨大なファイルを転送しようとして長時間待ち続け、 結局ファイルが大きすぎて転送できなかったなどといった羽目に陥るのを防げるからです。 注意: ブラウザ側でこの最大値を出し抜くのは簡単なことなので、この機能を信頼して、 これより大きなサイズのファイルがブロックされることを前提にしてはいけません。 しかし、PHP 側の最大サイズの設定を欺くことはできません。
注意: アップロード用のフォームが enctype="multipart/form-data" 属性を有しているかを 確認してください。さもないと、ファイルのアップロードは動作しません。
オートグローバル $_FILES は、PHP 4.1.0 以降に存在します ($HTTP_POST_FILES は、これ以前のバージョンに存在します)。 これらの配列には、全てアップロードされたファイルの情報が 含まれています。
$_FILES の内容は次のようになります。ここでは、上の例のスクリプトで使われたように、 アップロードファイルの名前として userfile を 使用することを仮定していることに注意してください。 実際にはどんな名前にすることもできます。
- $_FILES['userfile']['name']
-
クライアントマシンの元のファイル名。
- $_FILES['userfile']['type']
-
ファイルの MIME 型。ただし、ブラウザがこの情報を提供する場合。 例えば、"image/gif" のようになります。 この MIME 型は PHP 側ではチェックされません。そのため、 この値は信用できません。
- $_FILES['userfile']['size']
-
アップロードされたファイルのバイト単位のサイズ。
- $_FILES['userfile']['tmp_name']
-
アップロードされたファイルがサーバー上で保存されているテンポラ リファイルの名前。
- $_FILES['userfile']['error']
-
このファイルアップロードに関する エラーコード ['error']は、PHP 4.2.0 で追加されました。
php.ini の upload_tmp_dir ディレクティブで 他の場所を指定しない限り、ファイルはサーバーにおけるデフォルトの テンポラリディレクトリに保存されます。サーバーのデフォルトディレクトリは、 PHP を実行する環境において環境変数 TMPDIR を設定する ことにより変更することができます。しかし、PHP スクリプトの内部から putenv() 関数により設定しても上手くいきません。 この環境変数は、アップロードされたファイルに他の処理を行う際にも 同様に使用することが可能です。
例2 ファイルのアップロードを検証する
詳細については、is_uploaded_file() および move_uploaded_file() の関数のエントリも 参照ください。以下はフォームからファイルをアップロードするプロセスの例です。
<?php
// 4.1.0より前のPHPでは$FILESの代わりに$HTTP_POST_FILESを使用する必要
// があります。
$uploaddir = '/var/www/uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
echo '<pre>';
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n";
} else {
echo "Possible file upload attack!\n";
}
echo 'Here is some more debugging info:';
print_r($_FILES);
print "</pre>";
?>
アップロードされたファイルを受け取る PHP スクリプトは、アップロード されたファイルを用いて何をするべきかを決めるために必要なロジックを 全て実装する必要があります。例えば、変数 $_FILES['userfile']['size'] を使用して、小さすぎたり 大きすぎたりするファイルを捨てることができます。指定した型以外の ファイルを全て捨てるために変数 $_FILES['userfile']['type'] を用いることができますが、 これはあくまでいくつかのチェックの中のひとつとしてのみ実行するように してください。なぜなら、この値を設定するのはあくまでもクライアントであり、 PHP 側では何もチェックしていないからです。 PHP 4.2.0 以降、 $_FILES['userfile']['error'] を使用することができ、 エラーコード に基づき、ロジックを構成することができます。 何らかの方法により、テンポラリディレクトリからファイルを削除したり 他の場所に移動したりする必要があります。
フォームでアップロードされるファイルが選択されていない場合、PHP は $_FILES['userfile']['size'] として 0 を返し、 $_FILES['userfile']['tmp_name'] には値を 設定しません。
移動または名前の変更が行われていない場合、リクエストの終了時に そのファイルはテンポラリディレクトリから削除されます。
例3 ファイルの配列をアップロードする
PHP はファイルについても HTML フォームで配列を使用すること をサポートしています。
<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
foreach ($_FILES["pictures"]["error"] as $key => $error) {
if ($error == UPLOAD_ERR_OK) {
$tmp_name = $_FILES["pictures"]["tmp_name"][$key];
$name = $_FILES["pictures"]["name"][$key];
move_uploaded_file($tmp_name, "data/$name");
}
}
?>
ファイルアップロードのプログレスバーは、apc.rfc1867 で実装することができます。
POST メソッドによるアップロード
12-Jun-2009 06:35
30-Mar-2009 04:09
Also note that since MAX_FILE_SIZE hidden field is supplied by the browser doing the submitting, it is easily overridden from the clients' side. You should always perform your own examination and error checking of the file after it reaches you, instead of relying on information submitted by the client. This includes checks for file size (always check the length of the actual data versus the reported file size) as well as file type (the MIME type submitted by the browser can be inaccurate at best, and intentionally set to an incorrect value at worst).
20-Mar-2009 02:26
Note that the MAX_FILE_SIZE hidden field is only used by the PHP script which receives the request, as an instruction to reject files larger than the given bound. This field has no significance for the browser, it does not provide a client-side check of the file-size, and it has nothing to do with web standards or browser features.
