如何通过XMLHttpRequest使用复制粘贴JavaScript接收PHP图像数据

6
我尝试创建一个类似于GMail使用的图片上传功能。您可以从桌面上复制(CTRL-C)一张图片,然后粘贴(CTRL-V)到网站上。 然后,通过XMLHttpRequest将图像上传到处理传入文件的php脚本,其中“处理”意味着对其进行重命名并存储在服务器上。
我已经能够获取图像(和数据),但是我无法成功提交和接收XMLHttpRequest。 我的Javascript代码如下:
  document.onpaste = function(e){
        var items = e.clipboardData.items;
        console.log(JSON.stringify(items));
        if (e.clipboardData.items[1].kind === 'file') {
            // get the blob
            var imageFile = items[1].getAsFile();
            console.log(imageFile);
            var reader = new FileReader();
            reader.onload = function(event) {
                console.log(event.target.result); // data url!
                submitFileForm(event.target.result, 'paste');
            };
        }
    };

 function submitFileForm(file, type) {
        var formData = new FormData();
        formData.append('file', file);
        formData.append('submission-type', type);

        var xhr = new XMLHttpRequest();
        xhr.open('POST', 'php/image-upload.php');
        xhr.onload = function () {
            if (xhr.status == 200) {
                console.log('all done: ');
            } else {
                console.log('Nope');
            }
        };

        xhr.send(formData);
    }

处理 PHP(php/image-upload.php)看起来像这样:
$base64string = $_POST['file'];
file_put_contents('img.png', base64_decode($base64string));

我认为$_POST['file']保持为空,但我不确定。此外,我还遇到了“blob size”(在console.log()中显示)比实际图像大小要大得多的问题。但也许这并不重要或者是由编码引起的。
开发者控制台会显示这个信息。
{"0":{"type":"text/plain","kind":"string"},"1":{"type":"image/png","kind":"file"},"length":2} image-upload.js:8
Blob {type: "image/png", size: 135619, slice: function}

如果我通过右键单击实际的图像文件查看文件信息,它会显示大小为5,320字节(磁盘上为8 KB)

我不一定需要使用XMLHttpRequest,这只是我首先想到的。如果有更好的方法来实现使用JavaScript实时上传图像到服务器,请告诉我们。


开发者控制台的网络选项卡显示了什么?文件是否实际通过网络提交,还是只发送了一个空表单? - DevZer0
你的 reader.onload = function(event) { console.log(event.target.result); // data url! submitFileForm(event.target.result, 'paste'); }; 函数没有触发。 - DevZer0
4个回答

11

您可以从桌面复制(CTRL-C)一张图片并将其粘贴(CTRL-V)到网站上。

不,这是不可能的。您可以粘贴例如截图和来自网络的图像,这是Gmail 所做的

您最大的错误是在已经拥有文件时使用FileReader,只有当存在适当的HTTP上传时,$_FILES数组才会被填充,而不是用于即席的base64 POST参数。要进行适当的HTTP上传,您只需 .append()一个文件或blob对象(文件Blob)。

这是一个独立的PHP文件,应该可以正常工作,请将文件托管,打开它作为页面,然后在页面上截取屏幕截图并粘贴,几秒钟后图像应该出现在页面上。

<?php
if( isset( $_FILES['file'] ) ) {
    $file_contents = file_get_contents( $_FILES['file']['tmp_name'] );
    header("Content-Type: " . $_FILES['file']['type'] );
    die($file_contents);
}
else {
    header("HTTP/1.1 400 Bad Request");
}
print_r($_FILES);
?>

<script>
document.onpaste = function (e) {
    var items = e.clipboardData.items;
    var files = [];
    for( var i = 0, len = items.length; i < len; ++i ) {
        var item = items[i];
        if( item.kind === "file" ) {
            submitFileForm(item.getAsFile(), "paste");
        }
    }

};

function submitFileForm(file, type) {
    var extension = file.type.match(/\/([a-z0-9]+)/i)[1].toLowerCase();
    var formData = new FormData();
    formData.append('file', file, "image_file");
    formData.append('extension', extension );
    formData.append("mimetype", file.type );
    formData.append('submission-type', type);

    var xhr = new XMLHttpRequest();
    xhr.responseType = "blob";
    xhr.open('POST', '<?php echo basename(__FILE__); ?>');
    xhr.onload = function () {
        if (xhr.status == 200) {
            var img = new Image();
            img.src = (window.URL || window.webkitURL)
                .createObjectURL( xhr.response );
            document.body.appendChild(img);
        }
    };

    xhr.send(formData);
}
</script>

pathinfo($_FILES['file']['name'])['extension'] 是空的 :(. 如果您能告诉我如何获取图像扩展名,那么这个问题就解决了。 :) - poitroae
完美,我只是用Ajax代码替换了XMLRequest,这并不重要,只取决于你使用的是什么。 - Ahmed Sunny

3

我已经发布了一个完整可用的示例。之前的问题在于您需要正确构建blob。通过将文件数据注入到数组表示法中。

document.onpaste = function(e){
    var items = e.clipboardData.items;
    console.log(JSON.stringify(items));
    if (e.clipboardData.items[0].kind === 'file') {
            // get the blob
        var imageFile = items[0].getAsFile();
        console.log(imageFile);
        var reader = new FileReader();
        reader.onload = function(event) {
            console.log(event.target.result); // data url!
            submitFileForm(event.target.result, 'paste');
        };
        reader.readAsBinaryString(imageFile);
    }
};

function submitFileForm(file, type) {
    var formData = new FormData();
    var myBlob = new Blob([file], { "type" : "image/png"} );
    formData.append('file', myBlob, 'file.jpg');
    formData.append('submission-type', type);

    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/task/file');
    xhr.onload = function () {
        if (xhr.status == 200) {
            console.log('all done: ');
        } else {
            console.log('Nope');
        }
    };

    xhr.send(formData);
}

好的,我现在正确地发送数据了。但是,每次都会创建一个大小为零字节的文件。我也尝试使用 $_FILES,但我不确定那是否正确。你有什么想法吗? - poitroae
听起来不错,但对我没有用。文件大小仍为0字节。请注意,Blob将数组作为其第一个参数。此外,以这种方式,我的所有$ _POST变量(例如'submission-type')都被清除了,这意味着它们在php脚本中未定义。你自己试过了吗?如果你能帮助我就真的非常感激! - poitroae
DevZer0赏金计划已经开始! - poitroae
你能否请发布 PHP 部分? :) - poitroae

-1

图片文件大小是否可能大于您的“upload_max_filesize”设置?(通常默认为2兆字节)


我有所怀疑,磁盘上的图像大小为5,320字节(磁盘上为8 KB)。 - poitroae

-1

我猜文件应该在 $_FILE 数组里而不是 $_POST,因为它是一个文件。 如果不是的话,你可以将图像转换为字符串并将 imagestring 作为 GET 请求发送。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接