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

arl*_*dia 5 javascript html5 xmlhttprequest filereader

我正在尝试通过HTML5 FileReader在Web浏览器中选择本地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>
Run Code Online (Sandbox Code Playgroud)

然后我的PHP脚本执行此操作:

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

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

如果我打开桌面上的原始文件和文本编辑器中服务器上的上传文件来检查它们的内容,它们几乎可以完全不同.原始文件如下所示:

?ÿ?‡JFIF??;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90
Run Code Online (Sandbox Code Playgroud)

但上传的文件如下所示:

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

有趣的是,如果我使用上面注释掉的行查看JavaScript警报中的数据,它看起来就像上传文件的数据一样,所以看起来好像FileReader一开始没有提供正确的数据,而不是在服务器上传输或保存数据时引入的问题.有谁能解释一下?

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

更新:我只是想通了如果我跳过FileReader代码并将ajax.send(data)更改为ajax.send(文件),图像将被正确传输并保存在服务器上.所以我的问题基本上已经解决了,但是我会给那些可以解释为什么我的原始方法与readAsBinaryString不起作用的人奖励答案.

Mar*_*ijn 5

你的问题在于readAsBinaryString. 这会将二进制数据逐字节转换为字符串,以便您将文本字符串发送到 PHP 文件。现在文本字符串总是有一个编码;当您使用 XmlHttpRequest 上传字符串时,默认情况下它将使用 UTF-8

因此,最初应该代表一个字节的每个字符将被编码为 UTF-8...它为每个字符使用多个字节,并且代码点高于 127!

最好的方法是使用readAsArrayBuffer而不是readAsBinaryString. 这将避免所有字符集转换(处理字符串时必需的)。