如何在PHP中编码多字节文件名并在JavaScript中解码?

10

以下是一些文件名的示例:

漢語.jpg (Chinese)
Федерация.jpg (Russian)
AbÇöişÜĞ.jpg (Turkish, ISO-8859-9)
...

我尝试了rawurlencode(mb_convert_encoding($file, "UTF-8", mb_detect_encoding($file))),但这并不起作用,所有的中文和俄语字符都被打印成了%3F(普通问号),所有土耳其字符都被删除。

我在Windows、PHP 5.3上测试。

我找到的唯一解决方案是显式输入编码:rawurlencode(mb_convert_encoding($file, "UTF-8", "ISO-8859-9")),这仅对土耳其字符有效。

顺便说一下,对于以上文件,mb_detect_encoding($file)始终返回"UTF-8"。

编辑:
运行下面的代码后,我认为mb_convert_encoding()无法解决我的问题:

$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("mp", FilesystemIterator::UNIX_PATHS));
$iterator = new RegexIterator($iterator, '/^.+\.(gif|jpg|jpeg|png)$/i', RegexIterator::GET_MATCH);

foreach ($iterator as $file)
{
    foreach (mb_list_encodings() as $encoding)
        var_dump(rawurlencode(mb_convert_encoding($file[0], "UTF-8", $encoding)) . " : " . $encoding);
}

我猜这可能与编码有关,但我不知道该怎么做。


mb_detect_encoding()并不是全知全能的,它经常会失败,因为很难确定一段文本使用的确切编码方式。 - Marc B
1个回答

1

所以,最重要的是大多数传输(网络、文件、rpc)都希望字符最多只有一个字节。URL编码(%FF)也期望输入数据每个字符都是一个字节。

因此,您需要使用UTF8。它将多字节字符转换为由1个字节字符组成的字符串。从这个字符串中,您可以像通常使用ASCII一样进行操作。

您需要做的是明确设置php的编码:

mb_internal_encoding("UTF-8");

现在你所有的内部字符串和文件名等都将是UTF-8(单字节)编码的。 从这里,您可以按原样回显文件名,它将作为编码数据传输。从JavaScript中,您只需要使用AJAX发送请求,它将自动整齐地解码,准备在浏览器中使用 :) 只需确保在html文件中设置您的内容类型,因为这将用作默认的JS编码。

<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />

如果我在代码顶部使用 mb_internal_encoding("UTF-8");,仍然会得到错误的编码 rawurlencode(mb_convert_encoding($file[0], "UTF-8"));(例如,仍然将俄语字符编码为%3F(?))。 - ahk
如果你只是回显数据(PHP默认会将所有字符串转换为UTF-8),那么你不必使用mb_convert_encoding($file[0], "UTF-8")甚至rawurlencoding。 - Colin Godsey
起初我没有使用它们,但是当我只是回显文件名时出现了奇怪的字符。HTML文件编码为UTF-8无BOM,内容类型也是UTF-8。我找到的唯一解决方案是上面这个:rawurlencode(mb_convert_encoding($file, "UTF-8", "ISO-8859-9")) 但这仅适用于土耳其字符,因为"ISO-8859-9"是针对土耳其的:http://en.wikipedia.org/wiki/ISO/IEC_8859-9 - ahk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接