我需要将上传的文件名与未知编码转换为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-1
和ISO-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