Skip to main content

File Drag-and-Drop Upload

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

HTML5 supports file drag-and-drop uploading, which is intuitive, convenient, and provides a better user experience. This article introduces the implementation method using FormData + Ajax and provides complete front-end and back-end (PHP) code.

1. Implementing Drag-and-Drop Upload with Input Control

<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>

Note: You must set method="POST", enctype="multipart/form-data", and type="file" name="myfile". Missing any of these three will result in the back-end PHP being unable to receive data.

Of course, after dragging and dropping the file, clicking the submit button will cause the browser to show a busy state and the page will start to refresh. Using form submission cannot avoid page refreshing when uploading files; the method introduced later can achieve refresh-free drag-and-drop uploading.

(The back-end code is the same as the FormData + Ajax method, please see below.)

2. Implementing Drag-and-Drop Upload with 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>

The code above introduces two methods: jQuery and native JS. Looking at the code, you can find that using native JS is actually more convenient (note that you must not set ContentType); after all, this point is easy to get right by chance. On the other hand, the jQuery implementation is harder to understand (processData and contentType must be set to false, which is quite counterintuitive).

Therefore, it is recommended to use native JS to implement this part. As for compatibility, browsers that support file drag-and-drop should have supported standard XHR for a long time anyway.

3. Back-end Processing

First, let's be clear: although Ajax sends files using the POST method, it is sending files (which have some extra attributes) rather than a plain string. Therefore, the PHP back-end uses the $_FILES array to receive them, not the $_POST array.

<?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;
    }
}
?>

Note the multi-line comments above, especially the parameters of the move_uploaded_file function; it's impossible to get it right without knowing them.

References:

  • Several blog posts from predecessors

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment