代码之家  ›  专栏  ›  技术社区  ›  arlomedia

从FileReader获得的JPEG数据与文件中的数据不匹配

  •  5
  • arlomedia  · 技术社区  · 11 年前

    我正试图通过HTML5FileReader在网络浏览器中选择一个本地JPEG文件,这样我就可以在不重新加载页面的情况下将其提交到服务器。所有的机制都在工作,我想我正在传输和保存JavaScript给我的确切数据,但结果是服务器上的JPEG文件无效。以下是演示该问题的基本代码:

    <form name="add_photos">
        ​<input type=​"file" name=​"photo" id=​"photo" /><br />
        ​<input type=​"button" value=​"Upload" onclick=​"upload_photo()​;​" />​
    </form>
    
    <script type="text/javascript">
        function upload_photo() {
            file = document.add_photos.photo.files[0];
            if (file) {
                fileReader = new FileReader();
                fileReader.onload = upload_photo_ready;
                fileReader.readAsBinaryString(file);
            }
        }
    
        function upload_photo_ready(event) {
            data = event.target.result;
            // alert(data);
    
            URL = "submit.php";
            ajax = new XMLHttpRequest();
            ajax.open("POST", URL, 1);
            ajax.setRequestHeader("Ajax-Request", "1");
            ajax.send(data);
        }
    </script>
    

    然后我的PHP脚本会这样做:

    $data = file_get_contents("php://input");
    $filename = "test.jpg";
    file_put_contents($filename, $data);
    $result = imagecreatefromjpeg($filename);
    

    最后一行抛出了一个PHP错误“test.jpg不是一个有效的JPEG文件。”如果我将数据下载回Mac并尝试在Preview中打开它,Preview会说该文件“可能已损坏或使用了Preview无法识别的文件格式。”

    如果我在文本编辑器中打开桌面上的原始文件和服务器上上传的文件来检查它们的内容,它们几乎相同,但并不完全相同。原始文件的开头如下:

    ˇÿˇ‡JFIFˇ˛;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90
    

    但是上传的文件是这样开始的:

    ÿØÿàJFIFÿþ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90
    

    有趣的是,如果我在上面注释行的JavaScript警报中查看数据,它看起来就像上传的文件的数据,所以看起来FileReader一开始就没有给出正确的数据,而不是在服务器上传输或保存数据时出现的问题。有人能解释一下吗?

    我正在使用Safari 6,我也尝试过Firefox 14。

    更新:我刚刚发现,如果我跳过FileReader代码,将ajax.send(数据)更改为ajax.send(文件),那么图像就会正确地传输并保存在服务器上。因此,我的问题基本上得到了解决,但我会把答案授予任何能够解释为什么我最初使用readAsBinaryString的方法不起作用的人。

    1 回复  |  直到 11 年前
        1
  •  5
  •   Martijn    11 年前

    你的问题在于 readAsBinaryString 。这将把二进制数据逐字节传输到一个字符串中,这样您就可以向PHP文件发送一个文本字符串。现在,文本字符串总是有一个编码;当您使用XmlHttpRequest上传字符串时, by default it will use UTF-8 .

    因此,每个原本应该表示一个字节的字符都将被编码为UTF-8 多个字节 对于代码点在127以上的每个字符!

    你最好的办法是使用 readAsArrayBuffer 而不是 只读二进制字符串 。这将避免所有字符集转换(当 dealing with strings ).