1. inputコントロールによるドラッグ&ドロップアップロードの実装
<form action="http://localhost:82/drag&drop/fileUpload.php" method="POST" enctype="multipart/form-data">
<input type="file" name="myfile" id="">
<input type="submit" value="上传文件">
</form>
注意:<code>method="POST"</code>、<code>enctype="multipart/form-data"</code>、および<code>type="file" name="myfile"</code>を必ず設定してください。これら3つのうち1つでも欠けると、バックエンドのPHPでデータを受信できなくなります。
もちろん、ファイルをドラッグ&ドロップした後、送信ボタンをクリックするとブラウザがビジー状態になり、ページがリフレッシュされます。フォーム送信の方法ではアップロード時のページリフレッシュを避けることができませんが、後述する方法ではリフレッシュなしのドラッグ&ドロップアップロードを実現できます。
(バックエンドのコードは FormData + Ajax 方式と同じです。後述の内容を参照してください)
2. FormData + Ajaxによるドラッグ&ドロップアップロードの実装
<div id="dropArea3">文件放置区域</div>
<script>
// 可拖放元素
var area3 = document.getElementById('dropArea3');
// 文件放置区域
area3.ondragover = function(e) {
e.preventDefault();
}
area3.ondrop = function(e) {
e.preventDefault();
var files = e.dataTransfer.files;
if (files && files.length > 0) {
// 输出文件信息
var str = '';
for(var i = 0; i < files.length; i++) {
var file = files[i];
// 在线预览图片也需要先把图片上传到服务器,因为无法获取客户端文件url
// 上传文件直接xhr发送file对象即可
var formData = new FormData();
formData.append('myfile', file);
// JQ方式
// $.ajax({
// type : 'POST',
// url: 'http://localhost:82/drag&drop/fileUpload.php',
/* 必须设置下面两个属性,否则会导致$_FILES收不到数据 */
// processData: false,
// contentType: false,
// data: formData,
// success: function(res){
// console.log('success');
// console.log(res);
// },
// error: function(res) {
// console.log('error');
// }
// });
// 原生JS方式
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:82/drag&drop/fileUpload.php", true);
/* 千万不能设置,会导致$_FILES收不到数据 */
// xhr.setRequestHeader('Content-Type', 'multipart/form-data');
xhr.send(formData);
xhr.onload = function(e) {
if (this.status == 200) {
console.log(this.responseText);
}
};
console.log(file);
}
console.log('receive a file');
}
}
</script>
上記のコードでは、jQueryとネイティブJSの2つの方法を紹介しました。コードを見ると、実際にはネイティブJSの方が便利であることがわかります(ContentTypeを絶対に設定してはいけないことに注意してください)。注意すべきこの点は、図らずも成功しやすい部分です。一方、jQueryの実装方法は理解しにくいものです(processDataとcontentTypeをfalseに設定しなければならないなんて、そう簡単には思いつきませんよね……)。
したがって、この部分はネイティブJSで実装することをお勧めします。互換性については、ドラッグ&ドロップをサポートしているブラウザであれば、標準のXHRもかなり前からサポートされているはずです。
3. バックエンドの処理
まず一点明確にしておくと、Ajaxでのファイル送信にはPOSTメソッドを使いますが、送信されるのはあくまでファイル(いくつかの追加属性を持つもの)であり、普通の文字列ではありません。そのため、PHPのバックエンドでは <code>$_POST</code> 配列ではなく、<code>$_FILES</code> 配列で受け取ることになります。
<?php
/* 从$_FILES中取,而不是$_POST */
$file = $_FILES['myfile'];
$fileName = $file['name'];
// echo $fileName;
$fileSize = $file['size'];
// echo $fileSize;
if ($fileName != "") {
$rand = rand(100, 999);
$pics = date("YmdHis") . $rand . $fileName;
//上传路径
$filePath = "files/". $pics;
/* tmp_name是定死的,php出于服务器安全性考虑,过滤文件名 */
if (move_uploaded_file($_FILES['myfile']["tmp_name"], $filePath)) {
echo $filePath;
}
}
?>
上記の複数行コメントの内容、特に <code>move_uploaded_file</code> 関数の引数に注意してください。これを知らなければ、正しく記述することは不可能です。
参考文献:
- 先人によるブログ記事いくつか
コメントはまだありません