最近アップロード関連の機能を久しぶりに作ることがありました。
ドラック&ドロップでのファイルのマルチアップロード機能について、 サンプルソースや懸念事項など、まとめてみたいと思います。 サーバーサイドはPHPで書いてます。
フォームを書く
フロントのHTML&Javascriptは、こんな感じになるかと思います。 javascriptにはdrag&dropした時の挙動を書いてます👌
<html lang="ja">
<head>
<title>multi upload test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9
https://code.jquery.com/jquery-3.3.1.slim.min.js
</head>
<body>
<div class="mt-3">
<form id="file_upload_form" method="post" enctype="multipart/form-data" action="upload.php">
<div id="file_drag_drop_area" class="text-center p-3 rounded col-md-10 mx-auto" style="border:3px #000000 dashed;">
ここにファイルをドラッグ&ドロップ<br/>
<span>または</span><br/>
<input id="file_input" type="file" name="file[]" multiple />
</div>
<div class="d-flex justify-content-center mt-2">
<input type="submit" value="送信" class="btn btn-primary pl-3 pr-3" />
</div>
</form>
</div>
</body>
</html>
危険なので、デモではアップロードできないようにしています😅 ここにDEMOフォームを置いてます
HTMLフォームでの注意点
HTMLのフォームに関しては、 enctype="multipart/form-data" をつけ忘れると、アップロードできないので注意が必要です。input type="file" でファイルの入力フォームを作れますが、複数の場合はname属性の箇所を[] で配列にして、multiple 属性を付けておきます。
javascriptでの注意点
event.preventDefaultについて
ドラッグドロップのエリアを目立たせるため、jQueryでドラッグして上に乗った時の処理(dragover)とドラッグエリアから外れた時の処理(dragleave)を書いていますが
event.preventDefault(); でブラウザデフォルトの動きをキャンセルしています。これを書いてないと、上手く動きません。
例えばこの処理を書かずに、画像をクロームに乗せたときは、その画像がそのまま表示されます。。🤦♂️
event.originalEventについて
jqueryのイベント(event)からはdataTransferを取得することが出来ないので、DOMイベントを取得するためにoriginalEventから取ってきています。dataTransfer.files にドロップしたファイルの情報が入っていて、それをDOMのid=”file_input”にセットしています。
javascriptでこれがやりたい
フォームにセットしたファイル名が見たい
filesにファイルのデータが入ってます(FileListオブジェクトになってます)ので、そのnameプロパティを参照します。 これを使うと、拡張子のチェックが出来ます。
for(let i = 0; i < file_input.files.length; i++) {
console.log(file_input.files[i].name);
}
一部ファイルを削除したい
delete file_input.files[0]; とかで消せそうな気がしますが、消えません・・・
DataTransferを通さないと、内容を変更できないようです。
DataTransferを新しく作って、必要なファイルだけaddし、その後元のfilesを上がきすればOKです。
let data_transfer = new DataTransfer();
data_transfer.items.add(file_input.files[1]);
data_transfer.items.add(file_input.files[2]);
file_input.files = data_transfer.files;
PHP(フレームワークなしで書く)
formのactionで指定している箇所で処理をするので、upload.phpを用意して下記のような感じにします。 アップロードしたファイルのバリデーションなども必要かと思いますが、とりあえずアップロードのみです。
<?php
// uploadするディレクトリ
$upload_dir = './';
for ($i=0; $i < count($_FILES['file']['name']); $i++) {
$uploadfile = $upload_dir . basename($_FILES['file']['name'][$i]);
if (move_uploaded_file($_FILES['file']['tmp_name'][$i], $uploadfile)) {
echo "successfully uploaded.<br>";
} else {
echo "upload faild<br>";
}
}
アップロードされると、$_POSTではなく$_FILESに情報が入って、バックエンドに渡ってきます。 気をつけるのは$_FILES[‘file’]が配列になるのかと思いきや、$_FILES[‘file’][‘name’]とか$_FILES[‘file’][‘tmp_name’]が配列になる所ですね。
move_uploaded_fileでphpのtemp位置から(第一引数)、指定した場所(第二引数)に移動してくれます。
まとめ
気をつけるところをまとめると、 ・フォームの書き方に気を付ける。 ・ドラッグ&ドロップさせるときは、event.preventDefault(); を付けてブラウザデフォルトの挙動をキャンセルする。 ・jqueryのevent引数からfilesは取れないので、originalEventを使う。 ・FileListオブジェクトの扱いに気を付ける、
みたいな感じですかね。 それでは👋
コメント