POST メソッドによるアップロード

この機能により、テキスト、バイナリファイルの両方をアップロードできるように なります。 PHP の認証機構およびファイル操作関数を用いて、アップロードを許可する ユーザーとアップロード後にそのファイルを使用して行う動作を完全に制御する ことが可能です。

PHP は、全ての RFC-1867 対応ブラウザからファイルのアップロードを 受けることができます。

注意: 関係する設定に関する注記

php.inifile_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 は、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.iniupload_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");
    }
}
?>

ファイルアップロードのプログレスバーは、セッションのアップロードの進捗 で実装することができます。

add a note add a note

User Contributed Notes 10 notes

up
12
daevid at daevid dot com
4 years ago
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";
}
?>
up
10
michael
4 years ago
Just a little note, when I was trying to get this to work on my webserver I got error telling me the permissions were wrong, I checked and couldn't see anything wrong then I thought to try "./" for my upload directory instead of the full address which was something like "home/username/public_html/uploaddir". This will save it in the same directory as your script for the program above thats something like

<?php
// In PHP versions earlier than 4.1.0, $HTTP_POST_FILES should be used instead
// of $_FILES.

$uploaddir = './';//<----This is all I changed
$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>";

?>

I know something trivial but when your new to this, those kind of things elude you.
up
4
Anonymous
1 year ago
Normalizing $_FILES structure:

<?php
    $files
= [];
   
$fix = function (&$files, $values, $prop) use (&$fix) {
        foreach (
$values as $key => $value) {
            if (
is_array($value)) {
               
$fix($files[$key], $value, $prop);
            } else {
               
$files[$key][$prop] = $value;
            }
        }
    };
    foreach (
$_FILES as $name => $props) {
        foreach (
$props as $prop => $value) {
            if (
is_array($value)) {
               
$fix($files[$name], $value, $prop);
            } else {
               
$files[$name][$prop] = $value;
            }
        }
    }
?>
up
3
gustavo at roskus dot com
2 years ago
Some hosting does not have permission to use the move_uploaded_file function should replace the copy function
up
3
Mark
3 years ago
$_FILES will be empty if a user attempts to upload a file greater than post_max_size in your php.ini

post_max_size should be >= upload_max_filesize in your php.ini.
up
2
claude dot pache at gmail dot com
5 years ago
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.
up
1
zingaburga at hotmail dot com
3 years ago
The documentation is a little unclear about the MAX_FILE_SIZE value sent in the form with multiple file input fields.  The following is what I have found through testing - hopefully it may clarify it for others.

The MAX_FILE_SIZE is applied to each file (not the total size of all files) and to all file inputs which appear after it.  This means that it can be overridden for different file fields.  You can also disable it by sending no number, or sending 0 (probably anything that == '0' if you think about it).

Example:

<form enctype="multipart/form-data" action="." method="POST">
  <!-- no maximum size for userfile0 -->
  <input name="userfile0" type="file" />

  <input type="hidden" name="MAX_FILE_SIZE" value="1000" />
  <!-- maximum size for userfile1 is 1000 bytes -->
  <input name="userfile1" type="file" />
  <!-- maximum size for userfile2 is 1000 bytes -->
  <input name="userfile2" type="file" />

  <input type="hidden" name="MAX_FILE_SIZE" value="2000" />
  <!-- maximum size for userfile3 is 2000 bytes -->
  <input name="userfile3" type="file" />

  <input type="hidden" name="MAX_FILE_SIZE" value="0" />
  <!-- no maximum size for userfile4 -->
  <input name="userfile4" type="file" />
</form>
up
0
eslindsey at gmail dot com
5 years ago
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).
up
-1
Age Bosma
2 years ago
"If no file is selected for upload in your form, PHP will return $_FILES['userfile']['size'] as 0, and $_FILES['userfile']['tmp_name'] as none."

Note that the situation above is the same when a file exceeding the MAX_FILE_SIZE hidden field is being uploaded. In this case $_FILES['userfile']['size'] is also set to 0, and $_FILES['userfile']['tmp_name'] is also empty. The difference would only be the error code.
Simply checking for these two conditions and assuming no file upload has been attempted is incorrect.

Instead, check if $_FILES['userfile']['name'] is set or not. If it is, a file upload has at least been attempted (a failed attempt or not). If it is not set, no attempt has been made.
up
-3
mail at markuszeller dot com
3 years ago
If you want to increase the upload size, it could make sense to allow it only to a specified directory and not in the php.ini for the whole domain or server. In my case it worked very well placing that into the .htaccess file like this:

php_value    upload_max_filesize    100M
php_value    post_max_size    101M

Remember, post_max_size must be bigger than the upload_max_filesize.
To Top