-1

我有一个 PHP 应用程序,它使用League/csv生成一个简单的 CSV 文件。某些列包含可能具有非 ANSI 值的名称/地址。我的客户要求对输出 CSV 文件进行编码,iso-8859-1而不是utf-8像现在这样。

我相信我的问题可以归结为以下问题(response来自 laravel):


        $headers = [
            'Content-type' => "text/csv; charset=iso-8859-1",
            'Content-Disposition' => 'attachment; filename="CLI.csv"'
        ];
        return response()->stream(function() {

            $fh = fopen('php://output', 'wb');
            fwrite($fh, "Vià Cittè\n");
            fwrite($fh, mb_convert_encoding("Vià Cittè\n", 'iso-8859-1'));
            fwrite($fh, mb_convert_encoding("Vià Cittè\n", 'iso-8859-1', 'utf-8'));
            fwrite($fh, iconv('utf-8', 'iso-8859-1', "Vià Cittè\n"));
            fwrite($fh, utf8_decode("Vià Cittè\n"));
            fwrite($fh, utf8_encode("Vià Cittè\n"));
            fclose($fh);

        }, 200, $headers);

我希望至少有一些行以Vià Cittè\niso-8859-1 编码,但它们最终都错了。这是我使用 iso-8859-1 作为编码打开输出文件时看到的内容:

在此处输入图像描述

由于某种原因,输出似乎被重新编码为 utf-8。

有人可以告诉我如何避免出现这种重新编码问题吗?


在我的真实代码中,我不是直接使用 编写的fopen,而是将 League/csv 与它的Writerand一起使用CharsetConverter。我进行了各种尝试,但结果与上述相同。

注意:我目前在 linux 上使用 PHP 7.3。php 服务器位于 nginx 代理(位于不同的 docker 容器中)后面的 docker 容器内。

4

1 回答 1

-1

您有几个有效的转换,以及明显的随机尝试。这都是做一些适当的测试的问题。

生的 统一码 UTF-8 ISO-8859-1
à U+00E0 带坟墓的拉丁文小写字母 A C3 A0 E0
è U+00E8 带坟墓的拉丁文小写字母 E C3 A8 E8
$utf8 = "\u{00E0}\u{00E8}";
var_dump($utf8, bin2hex($utf8));

$latin1 = [
    utf8_decode($utf8),
    iconv('UTF-8', 'ISO-8859-1', $utf8),
    mb_convert_encoding($utf8, 'ISO-8859-1', 'UTF-8'),
];
var_dump(array_map('bin2hex', $latin1));

假设一切都配置为使用 UTF-8(我们不是生活在 1995 年的穴居人),您将看到:

string(4) "àè"
string(8) "c3a0c3a8"
array(3) {
  [0]=>
  string(4) "e0e8"
  [1]=>
  string(4) "e0e8"
  [2]=>
  string(4) "e0e8"
}

我会跳过utf8_decode(),因为它的名称非常令人困惑(没有人查看手册来查看它的实际作用)。其他的主要区别在于它们如何处理丢失的字符:

$utf8 = "€";
var_dump($utf8);

$latin1 = [
    iconv('UTF-8', 'ISO-8859-1', $utf8), # Notice: iconv(): Detected an illegal character in input string
    iconv('UTF-8', 'ISO-8859-1//IGNORE', $utf8),
    iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $utf8),
    mb_convert_encoding($utf8, 'ISO-8859-1', 'UTF-8'),
];
var_dump(array_map('bin2hex', $latin1));
string(3) "€"
array(4) {
  [0]=>
  string(0) ""
  [1]=>
  string(0) ""
  [2]=>
  string(6) "455552" ------> EUR
  [3]=>
  string(2) "3f" ----------> ?
}
于 2022-01-11T17:54:57.460 回答