メインコンテンツへ移動

ファイルのドラッグ&ドロップアップロード

無料2015-07-06#HTML#JS#Solution#文件拖放上传.HTML5拖放#HTML5拖动#文件上传#无刷新上传#FormData

HTML5はファイルのドラッグ&ドロップアップロードをサポートしており、直感的で便利であり、ユーザーエクスペリエンスが向上します。本記事では FormData + Ajax による実装方法を紹介し、フロントエンドとバックエンド(PHP)の完全なコードを提供します。

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> 関数の引数に注意してください。これを知らなければ、正しく記述することは不可能です。

参考文献:

  • 先人によるブログ記事いくつか

コメント

コメントはまだありません

コメントを書く