PHP编码转换为Windows-1252,同时保持UTF-8兼容性


PHP Encoding Conversion to Windows-1252 whilst keeping UTF-8 Compatibility

我需要将上传的文件名与未知编码转换为Windows-1252,同时保持UTF-8兼容性。

当我将这些文件传递给控制器(我对其没有任何影响)时,这些文件必须是Windows-1252编码的。然后,该控制器再次生成一个有效文件(名称)列表,这些文件(名称)通过MySQL存储到数据库中—因此我需要UTF-8兼容性。传入控制器的文件名和写入数据库的文件名必须匹配。到目前为止一切顺利。

在某些罕见的情况下,当转换为"Windows-1252"(如字符"ï")时,该字符被转换为UTF-8中无效的内容。MySQL然后删除这些无效字符——结果磁盘上的文件名和存储到数据库中的文件名不再匹配。这种转换有时会失败,可以通过简单的重新编码来实现:

$sEncoding       = mb_detect_encoding($sOriginalFilename);
$sTargetFilename = iconv($sEncoding, "Windows-1252//IGNORE", $sOriginalFilename);

为了防止转换生成无效字符,我可以再次从重新编码的字符串中删除所有无效的UTF-8字符:

ini_set('mbstring.substitute_character', "none");
$sEncoding       = mb_detect_encoding($sOriginalFilename);
$sTargetFilename = iconv($sEncoding, "Windows-1252//TRANSLIT", $sOriginalFilename);
$sTargetFilename = mb_convert_encoding($sTargetFilename, 'UTF-8', 'Windows-1252');

但是这将完全删除/重新编码字符串中剩下的任何特殊字符。例如,我失去了所有的"äöüÄÖÜ"等,这在德语中是相当常规的。

如果你知道一个更干净更简单的编码到Windows-1252的方法(不丢失有效的特殊字符),请告诉我。

任何帮助都非常感激。提前感谢!

我认为主要的问题是mb_detect_encoding()不完全做你认为它做什么。它尝试检测字符编码,但它从相当有限的预定义编码列表中进行检测。默认情况下,这些编码是由mb_detect_order()返回的编码。在我的电脑里它们是:

    ASCII utf - 8

所以这个函数是完全无用的,除非你负责编译一个候选编码列表并将其提供给函数。

此外,基本上没有可靠的方法来猜测任意输入字符串的编码,即使您将自己限制为编码的一小部分。在你的情况下,Windows-1252是如此接近ISO-8859-1ISO-8859-15,你没有办法区分它们,除了视觉检查关键字符,如& current;或€。

字符串不能同时是Windows-1252和UTF-8。字符集对于前128个字符是相同的(例如,它们包含基本的拉丁字母),但当它超出此范围时(如Umlauts),它要么是其中之一,要么是另一个。它们在UTF-8中的代码点与在Windows-1252中的代码点不同。

在文件系统中保持ASCII -如果您需要在文件名中支持ASCII以外的字符,那么有可以用来表示unicode字符同时保持ASCII的方案。

例如,百分比编码:

äöüÄÖÜ.txt <-> %C3%A4%C3%B6%C3%BC%C3%84%C3%96%C3%9C.txt

当然,这将很快达到文件名限制,并不是很理想。

那么punycode呢?

äöüÄÖÜ.txt <-> xn--4caa7cb2ac.txt