POST メソッドによるアップロード
この機能により、テキスト、バイナリファイルの両方をアップロードできるように
なります。
PHP の認証機構およびファイル操作関数を用いて、アップロードを許可する
ユーザーとアップロード後にそのファイルを使用して行う動作を完全に制御する
ことが可能です。
PHP は、全ての RFC-1867 対応ブラウザからファイルのアップロードを
受けることができます。
注意:
関係する設定に関する注記
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 要素の name 属性の値が、$_FILES 配列のキーになります -->
このファイルをアップロード: <input name="userfile" type="file" />
<input type="submit" value="ファイルを送信" />
</form>
上の例の __URL__
は、PHP ファイルを指すよう置換される
必要があります。
"MAX_FILE_SIZE
" hidden フィールドは、
"file" input フィールドの前に置く必要があります。
この値は、PHP で取得可能なファイルの最大サイズを規定します。この値はバイト数で指定します。
MAX_FILE_SIZE
は常に指定しておくべきです。
巨大なファイルを転送しようとして長時間待ち続け、
結局ファイルが大きすぎて転送できなかったなどといった羽目に陥るのを防げるからです。
注意: ブラウザ側でこの最大値を出し抜くのは簡単なことなので、この機能を信頼して、
これより大きなサイズのファイルがブロックされることを前提にしてはいけません。
しかし、PHP 側の最大サイズの設定を欺くことはできません。
注意:
アップロード用のフォームが
enctype="multipart/form-data"
属性を有しているかを
確認してください。さもないと、ファイルのアップロードは動作しません。
グローバルの $_FILES には、アップロードされたファイルの情報が含まれます。
サンプルのフォームからの内容は次のようになります。ここでは、上の例のスクリプトで使われたように、
アップロードファイルの名前として userfile を
使用することを仮定していることに注意してください。
実際にはどんな名前にすることもできます。
-
$_FILES['userfile']['name']
-
クライアントマシンの元のファイル名。
-
$_FILES['userfile']['type']
-
ファイルの MIME 型。ただし、ブラウザがこの情報を提供する場合。
例えば、"image/gif"
のようになります。
この MIME 型は PHP 側ではチェックされません。そのため、
この値は信用できません。
-
$_FILES['userfile']['size']
-
アップロードされたファイルのバイト単位のサイズ。
-
$_FILES['userfile']['tmp_name']
-
アップロードされたファイルがサーバー上で保存されているテンポラ
リファイルの名前。
-
$_FILES['userfile']['error']
-
このファイルアップロードに関する
エラーコード
-
$_FILES['userfile']['full_path']
-
ブラウザからアップロードされたファイルのフルパス。
この値は実際のディレクトリ構造を反映しているとは必ずしも言えないため、
信用できません。
PHP 8.1.0 以降で利用可能です。
php.ini の upload_tmp_dir ディレクティブで
他の場所を指定しない限り、ファイルはサーバーにおけるデフォルトの
テンポラリディレクトリに保存されます。サーバーのデフォルトディレクトリは、
PHP を実行する環境において環境変数 TMPDIR を設定する
ことにより変更することができます。しかし、PHP スクリプトの内部から
putenv() 関数により設定しても上手くいきません。
この環境変数は、アップロードされたファイルに他の処理を行う際にも
同様に使用することが可能です。
例2 ファイルのアップロードを検証する
詳細については、is_uploaded_file()
および move_uploaded_file() の関数のエントリも
参照ください。以下はフォームからファイルをアップロードするプロセスの例です。
<?php
$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 側では何もチェックしていないからです。
また、
$_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];
// basename() で、ひとまずファイルシステムトラバーサル攻撃は防げるでしょう。
// ファイル名についてのその他のバリデーションも、適切に行いましょう。
$name = basename($_FILES["pictures"]["name"][$key]);
move_uploaded_file($tmp_name, "data/$name");
}
}
?>
ファイルアップロードのプログレスバーは、セッションのアップロードの進捗
で実装することができます。