最近アップロード関連の機能を久しぶりに作ることがありました。
ドラック&ドロップでのファイルのマルチアップロード機能について、
サンプルソースや懸念事項など、まとめてみたいと思います。
サーバーサイドは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
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" c
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" cros
<script>
$(function(){
// ドラッグしたままエリアに乗った&外れたとき
$(document).on('dragover', '#file_drag_drop_area, #file_drag_drop_area_stl', function (event) {
event.preventDefault();
$(this).css("background-color", "#999999");
});
$(document).on('dragleave', '#file_drag_drop_area, #file_drag_drop_area_stl', function (event) {
event.preventDefault();
$(this).css("background-color", "transparent");
});
// ドラッグした時
$(document).on('drop', '#file_drag_drop_area', function (event) {
let org_e = event;
if (event.originalEvent) {
org_e = event.originalEvent;
}
org_e.preventDefault();
file_input.files = org_e.dataTransfer.files;
$(this).css("background-color", "transparent");
});
});
</script>
</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オブジェクトの扱いに気を付ける、
みたいな感じですかね。
それでは👋
コメント