带有POST数据的Javascript XMLHttpRequest上传文件

时间:2018-02-08 15:46:02

标签: javascript php file-upload

我正在尝试使用拖放功能在JavaScript中创建小型上传。我编写了代码,但它似乎没有用。当前网站的工作方式,上传脚本必须为网站提供PHPSESSID等信息,服务器处理请求的附加数据以及文件本身。如果用户删除多个文件,脚本应该逐个上传所有文件。目前我甚至无法让JavaScript上传一个文件。查看调试工具时,服务器正在响应网站本身,而不是用于文件上传的响应。

在较旧版本的代码上使用现有表单上传文件时,我注意到在发送文件内容之前来自Web浏览器的请求如下所示:

Content-Disposition: form-data; name="file"; filename="file.txt"
Content-Type: text/plain

然而,当使用我使用的脚本发送时,我只看到了这个:

Content-Disposition: form-data; name="file"

但我不确定代码有什么问题,并且无法找到任何有助于解决此问题的内容。

我不想使用其他库,例如JQuery或任何类似的

Javascript代码:

function drop(e){
    e.preventDefault();
    if(e.dataTransfer.items){
        for(var i=0; i < e.dataTransfer.items.length; i++){
            var reader = new FileReader();
            var req = new XMLHttpRequest();
            var f = e.dataTransfer.files[i]
            req.onprogress = function(e){
                if (e.lengthComputable){
                    console.log("progress: " + e.loaded / e.total);
                }
            }
            req.open("POST", document.location, true);
            req.setRequestHeader("Content-Type", "application/octet-stream");
            reader.onload = function(e){
                var fd = new FormData();
                fd.append("PHPSESSID", document.cookie.split("=")[1]);
                fd.append("request", JSON.stringify({"command":"upload", "path":path + f.name, "path-type":pathtype}))
                fd.append("file", e.target.result);
                req.send(fd);
            }
            reader.readAsBinaryString(e.dataTransfer.items[i].getAsFile());
        }
    }else{
        for(var i=0; i < e.dataTransfer.files.length; i++){
            console.log(e.dataTransfer.files[i]);
        }
    }
}

负责上传的PHP代码:

if(isset($_POST['request'])){
    $request = json_decode($_POST['request'], true);
    if($request['command'] == "upload"){
        if(isset($request['path']) && isset($request['path-type'])){
            $path = "";
            if($request['path-type'] === "private"){
                $path = truepath($private_dir . $request['path']);
                if(!(substr($path, 0, strlen($private_dir)) === $private_dir)){
                    die();
                }
            }elseif($request['path-type'] === "public"){
                $path = truepath($public_dir . $request['path']);
                if(!(substr($path, 0, strlen($public_dir)) === $public_dir)){
                    die();
                }
            }else{
                die();
            }
            move_uploaded_file($_FILES["file"]["tmp_name"], $path);
            die();
        }
    }
    die();
}

1 个答案:

答案 0 :(得分:1)

经过几天的实验,我发现服务器端失败的原因是因为代码没有设置$_POST$_FILES

代码失败的原因有很多,都是由JavaScript方面引起的。

需要改变的事情:

  1. FileReader完全没必要。
  2. req.setRequestHeader("Content-Type", "application/octet-stream");不正确,因为它应该是&multi39 / form-data&#39;。除此之外,它不应该被设置,因为它将破坏内容类型标题。这是因为在上传文件时,Content-Type标题还包含由浏览器生成的边界。设置Content-Type时,您将覆盖为文件上传生成的浏览器。 I was able to find this out thanks to this answer.
  3. PHP方面的代码(令人惊讶)是正确的。 JavaScript的最新代码是:

    function drop(e){
        e.preventDefault();
        if(e.dataTransfer.files){
            for(var i=0; i < e.dataTransfer.files.length; i++){
                var req = new XMLHttpRequest();
                var f = e.dataTransfer.files[i]
                req.onprogress = function(e){
                    if (e.lengthComputable){
                        console.log("progress: " + e.loaded / e.total);
                    }
                }
                req.open("POST", document.location, true);
                req.overrideMimeType('application/octet-stream')
                var fd = new FormData();
                fd.append("PHPSESSID", document.cookie.split("=")[1]);
                fd.append("request", JSON.stringify({"command":"upload", "path":path + f.name, "path-type":pathtype}))
                fd.append("file", f);
                req.send(fd);
            }
        }
    }