HTML5のFile APIを使って、複数(の画像)ファイルをサーバにアップロードする方法。
2017/12/09
HTML5のFile APIを使うと、複数ファイルのアップロードが簡単に出来るそうなので、試してみました。
対象のブラウザがモダンブラウザに限定されるようなのですが、妙に簡単に出来たのが印象的。
ちなみに、CakePHP2(2.3.6)でも動きました。
HTML5 File API とは?
File APIとは、今までJavaScriptが直接扱うことが出来なかったローカルファイルに対して、読み取り操作を実現可能にするものです。また、今後の展開としてローカルファイルの書き込みや保存、さらにはWebアプリに専用のファイルシステムをサポートするAPIも、W3Cで標準化作業が進行中です。
IE10で動くHTML5アプリ実装例 「File APIを利用したアプリ」 (1/3):CodeZine
とこのとで、ローカルファイルを扱えるようになった、とのことです。
対象のブラウザは、
- Internet Explorer
- 10以降
- Firefox
- 3.5以降
- Google Chrome
- 6以降
- Safari
- 5以降
- Opera
- 10以降
と、なります。
ただし、SafariではFileReaderオブジェクトを、Internet Explorer 10ではreadAsBinaryStringメソッドをサポートしていません。
テストコード
では、その辺りを踏まえてるのかどうか分かりませんが、実際に動かしてみます。
index.htmlです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <title>HTML5 File API multiple upload</title> </head> <body> <h1>HTML5 File API</h1> <form action="./upload.php" method="post" enctype="multipart/form-data"> Files:<input type="file" name="upfile[]" multiple> <input type="submit" value="submit"> </form> </body> </html> |
単なるフォームを用意しただけです。
upload.phpは、受け取った$_POST内容で画像ファイルをセーブするルーチンです。
注意するのが、ファイルタグの部分。
<input type="file" name="upfile[]" multiple>
- nameを配列とすべく『[]』をつける
- 『multiple』で、複数ファイルを扱えるようにする
という2点が注目するところ。
試しに、3枚のファイルを送信した結果を var_dump()すると、以下のようになります。
なお、複数のファイルを選択する方法はOSによって異なります。
Windowsではctrl+クリック、MacOSではCommand+クリック。あるいは、Shift+クリックで範囲選択することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
array(1) { ["upfile"]=> array(5) { ["name"]=> array(3) { [0]=> string(12) "6791558.jpg" [1]=> string(12) "6795085.jpg" [2]=> string(12) "3956c40b.jpg" } ["type"]=> array(3) { [0]=> string(10) "image/jpeg" [1]=> string(10) "image/jpeg" [2]=> string(10) "image/jpeg" } ["tmp_name"]=> array(3) { [0]=> string(27) "C:\Windows\Temp\php2D40.tmp" [1]=> string(27) "C:\Windows\Temp\php2D70.tmp" [2]=> string(27) "C:\Windows\Temp\php2D71.tmp" } ["error"]=> array(3) { [0]=> int(0) [1]=> int(0) [2]=> int(0) } ["size"]=> array(3) { [0]=> int(96238) [1]=> int(44178) [2]=> int(89470) } } } |
PHPerな人たちなら、見覚えのある形式で受信できていますね。
$_POSTで受信できているので、あとは画像を作成すればいいだけです。
とりあえず、以下の様なphpを組んでみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
define('FILE_PATH','./image/'); //保存するパスを指定 if ( !empty($_FILES) ) { for ( $i=0; $i<count($_FILES["upfile"]["tmp_name"]); $i++ ) { if ( is_uploaded_file($_FILES["upfile"]["tmp_name"][$i]) ) { $name = $_FILES['upfile']['name'][$i]; $tempFile = $_FILES['upfile']['tmp_name'][$i]; // Validate the file type $fileTypes = array('jpg','jpeg','gif','png'); // File extensions $fileParts = pathinfo($_FILES['upfile']['name'][$i]); // ファイル名がアルファベットのみかをチェック if ( preg_match("/^([a-zA-Z0-9\.\-\_])+$/ui", $name) == "0" ) { // アルファベット以外を含む場合はファイル名を日時とする $saveFileName = date("Ymd_His", time()); } else { if ( preg_match("/\.jpg$/ui", $name) == true ) { $ret = explode('.jpg', $name); } elseif ( preg_match("/\.gif$/ui", $name) == true ) { $ret = explode('.gif', $name); } elseif ( preg_match("/\.png$/ui", $name) == true ) { $ret = explode('.png', $name); } $saveFileName = $ret[0]; // 拡張子を除いたそのまま } // マイクロ秒をファイル名に付加 $saveFileName = FILE_PATH . '[' . (microtime()*1000000) . ']' . $saveFileName; if ( in_array($fileParts['extension'], $fileTypes) ) { if ( move_uploaded_file($_FILES["upfile"]["tmp_name"][$i], $saveFileName . '.' . $fileParts['extension']) ) { //chmod($fileName, 0644); echo $_FILES["upfile"]["name"][$i] . "をアップロードしました。<br>"; } else { echo "アップロードエラー"; } } else { echo "アップロードの対象は画像ファイル(.jpg/.gif/.png)のみです。"; } } } } |
仕様としては、送信された回数分ループを回し、アルファベットのみなファイル名の場合は、
[マイクロ秒]元ファイル名.拡張子 の形式で、
アルファベット以外の文字が含まれるファイル名画像の場合は、
[マイクロ秒]yyyymmdd_hhmmss.拡張子 の形式で保存します。
まぁ、さほど凝ったこともしていないので、もっと良い感じのルーチンが存在すると思います。
実際に試してみる
初期画面
ファイル選択
「017.png」「国会議事堂.png」「上野動物園.png」の3個の複数ファイルを選択中。
選択後画面
Chromeでは、選択すると、個数が表示されます。
アップロード結果
元のファイル名でアップしたファイルを表示しています。
アップロードされた画像
アップロードされている画像。phpで組んだルーチン通り、[マイクロ秒]ファイル名.拡張子の形式で保存されています。
多少、ブラウザ依存になりますが、これで複数ファイルのアップロードが可能になるとは、HTML5、良い感じですよね。
[tgAmazonItemLookup asin="4048862588" related="1"]