在通过ajax从php流向客户端之后获取错误的文件编码(?)

时间:2017-05-18 18:37:44

标签: php laravel character-encoding

使用laravel我将二进制数据发送到客户端,稍后将其保存到客户端的计算机。 我正在使用ajax并传输内容。 这是我从服务器发送的内容:

$fileRecord = File::findOrFail($fileId);
set_time_limit(0);

$fs = Storage::disk('local')->getDriver();
$metaData = $fs->getMetadata($fileRecord->getFilePath());
$fileStream = $fs->readStream($fileRecord->getFilePath());

return response()->stream(function () use ($fileStream) {
    while(@ob_end_clean());
    fpassthru($fileStream);
}, 200, [
    'Content-Transfer-Encoding' => 'binary',
    'Content-Type'              => $metaData['type'],
    'Content-Disposition'       => "attachment; filename=\"{$fileRecord->getFullFileName()}\"",
]);

我解决了与数据大小相关的几个问题,如提到here

但是我无法在客户端上获得正确的文件内容。我尝试将内容保存到服务器上的其他文件中,一切正常。

以下是我得到的样本(样本从开头到某个字符列出一段文件):

Ex 1. png image

这应该是:

89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 06 40 00 00 04 B0 08 02 00 00 00 2C 63 11 C0 00 00 00 04 67 41 4D 41 00 00 D6 D8 D4 4F 58 32 00 00 00 19 74 45 58 74 53 6F 66 74 77 61 72 65 00 41 64 6F 62 65 20 49 6D 61 67 65 52 65 61 64 79 71 C9 65 3C 00 07 8D 52 49 44 41 54

这就是生成的内容:

从devTools复制到文件

C2 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 06 40 00 00 04 C2 B0 08 02 00 00 00 2C 63 11 C3 80 00 00 00 04 67 41 4D 41 00 00 C3 96 C3 98 C3 94 4F 58 32 00 00 00 19 74 45 58 74 53 6F 66 74 77 61 72 65 00 41 64 6F 62 65 20 49 6D 61 67 65 52 65 61 64 79 71 C3 89 65 3C 00 07 C2 8D 52 49 44 41 54
浏览器将数据作为客户端上的文件下载后

EF BF BD 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 06 40 00 00 04 EF BF BD 08 02 00 00 00 2C 63 11 EF BF BD 00 00 00 04 67 41 4D 41 00 00 EF BF BD EF BF BD EF BF BD 4F 58 32 00 00 00 19 74 45 58 74 53 6F 66 74 77 61 72 65 00 41 64 6F 62 65 20 49 6D 61 67 65 52 65 61 64 79 71 EF BF BD 65 3C 00 07 EF BF BD 52 49 44 41 54

Ex 2. pdf档案

这应该是:

25 50 44 46 2D 31 2E 35 0D 0A 25 B5 B5 B5 B5 0D 0A 31 20 30 20 6F 62 6A 0D 0A 3C 3C 2F 54 79 70 65 2F 43 61 74 61 6C 6F 67 2F 50 61 67 65 73 20 32 20 30 20 52 2F 4C 61 6E 67 28 65 6E 2D 55 53 29 20 2F 53 74 72 75 63 74 54 72 65 65 52 6F 6F 74 20 33 31

这就是生成的内容:

从devTools手动复制到文件

25 50 44 46 2D 31 2E 35 0D 0A 25 C2 B5 C2 B5 C2 B5 C2 B5 0D 0A 31 20 30 20 6F 62 6A 0D 0A 3C 3C 2F 54 79 70 65 2F 43 61 74 61 6C 6F 67 2F 50 61 67 65 73 20 32 20 30 20 52 2F 4C 61 6E 67 28 65 6E 2D 55 53 29 20 2F 53 74 72 75 63 74 54 72 65 65 52 6F 6F 74 20 33 31
浏览器将数据作为客户端
上的文件下载后

25 50 44 46 2D 31 2E 35 0D 0A 25 EF BF BD EF BF BD EF BF BD EF BF BD 0D 0A 31 20 30 20 6F 62 6A 0D 0A 3C 3C 2F 54 79 70 65 2F 43 61 74 61 6C 6F 67 2F 50 61 67 65 73 20 32 20 30 20 52 2F 4C 61 6E 67 28 65 6E 2D 55 53 29 20 2F 53 74 72 75 63 74 54 72 65 65 52 6F 6F 74 20 33 31

我在客户端上获得的一些标题(chrome devTools):

对于png文件:

Content-Disposition:attachment;filename="8c4d44a0-3bd9-11e7-8e6a-4ff287c4841c.png"
Content-Length:739993
Content-Transfer-Encoding:binary
Content-Type:image/png; charset=utf-8

对于pdf文件:

Content-Disposition:attachment; filename="e88fd450-3bd8-11e7-9dfa-99b21f936329.pdf"
Content-Length:420639
Content-Transfer-Encoding:binary
Content-Type:application/pdf; charset=utf-8

P.S。您可以看到格式错误的数据中存在C2个字符或EF BF BD字符序列。所以在我看来这是一个编码问题。我尝试在字符串上使用utf8_encode,但无济于事。文件句柄上的mb_detect_encoding返回空字符串。

我做错了什么?

P.P.S。在客户端上,我使用以下方式从ajax获取的二进制数据:

saveAs(new Blob([ajaxData], { type: mimeType }), fileName);

我使用Blob.jssaveAs

1 个答案:

答案 0 :(得分:0)

我终于弄清楚它是什么。 显然你不能直接将二进制数据输入javascript中的Blob对象(至少对于pdf,pngs,jpegs它不起作用),但是必须使用这样的东西:

function binaryToUint8Arr (bin) {
    var length = bin.length;
    var buf = new ArrayBuffer(length);
    var arr = new Uint8Array(buf);
    for (var i = 0; i < length; i++) {
        arr[i] = bin.charCodeAt(i);
    }
    return buf;
}

我找到了这个解决方案herehere人说:

  

我基本上需要将原始二进制文件包装在arraybuffer中和   将二进制字符转换为Unicode

所以我的代码变成了:

saveAs(new Blob([binaryToUint8Arr(ajaxData)], { type: mimeType }), fileName);

(其中ajaxData是我从ajax获得的二进制数据)