PHP 和 Linux utf-8 文件系统名称

PHP and Linux filesystem names in utf-8

我为 Windows 机器人找到了很多关于此的答案,对 Linux 没有什么有用的,我还没有检查过。

我的服务器是CentOS6,ext4文件系统,PHP版本是5.4.39,MySQL5.5.42.

全部设置为使用UTF8,从LANG环境变量到数据库,mysql客户端连接,php等

但是使用下面的代码我无法读取带有 èàòì 等特殊字符的文件

相同的代码适用于我的 Mac(php 和 mysql 从 ports 安装)。

正如您在代码中看到的那样,有一些带注释的测试。 mb_detect_encoding($track,'auto') returns UTF-8.

    $db->bind("id",$this->request->get(1));
    $file = $db->row("select f.name from file f where f.id = :id and f.type = 'mp3';");
    $track = realpath(__DIR__ . '/../') . $file['name'];
    //$track = mb_convert_encoding(realpath(__DIR__ . '/../' . $file['name']), "UTF-8");
    //$track = iconv('utf-8', 'cp1252', realpath(__DIR__ . '/../' . $file['name']));
    //echo mb_detect_encoding($track,'auto');

    if (file_exists($track)) {
        header("Content-Transfer-Encoding: binary"); 
        header("Content-Type: audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3");
        header('Content-length: ' . filesize($track));
        header('Cache-Control: no-cache');
        readfile($track);
    }

有什么建议吗?

更新

看起来这个问题与 php 和文件相关的函数有关,这些函数似乎不使用 UTF-8 和文件名.. 出于某种原因。

我使用了一个简单的 php 脚本和 shell 中的 运行 并且我有相同的行为甚至直接在 php 脚本中指定文件名(所以没有数据库涉及)。

PHP 设置:


    $ php -i | grep UTF
    default_charset => UTF-8 => UTF-8
    LANG => en_US.UTF-8
    LC_CTYPE => en_US.UTF-8
    _SERVER["LANG"] => en_US.UTF-8
    _SERVER["LC_CTYPE"] => en_US.UTF-8

    $ php --version
    PHP 5.4.39 (cli) (built: Mar 19 2015 06:25:23)


需要说明的是,这样的事情是行不通的:


    $track = "/path/to/existsing/file/with/spechialchars";
    echo "-> " .$track . "\n";
    if (file_exists($track)) {
        echo "OK " .$track . "\n";
    }

要记住的重要一点是,在 Linux 中,文件名没有字符编码,而只是一个 8 位字符串。

例如,如果您通过FTP上传文件,而FTP服务器使用Windows-1252字符编码,则文件名将为8位Windows-1252 .尝试使用 UTF-8 字符打开文件将失败,无论区域设置或 LANG 是什么。

这不同于 OS X,其中文件名始终为 UTF-8,而 Windows 其中文件名始终为 UTF-16。

您可能会发现 PHP 中的字符串也只是 8 位字符串,因此无法确定字符串使用的是什么编码 - 您可以轻松地将两个字符串编码为不同的字符集。

我的建议是确保您知道您读取或输出的任何字符串的编码,包括表单字段和文件名。

因此,请确保磁盘上的文件名是 UTF-8,并且您输入数据库的文件名值是 UTF-8。然后,当您从数据库中提取值时,文件变量应该已经是 UTF-8 编码的,并准备好传递给 fopen 命令。