比较readdir()和__FILE__之间的文件名 - 与法语口音的复杂化

时间:2013-09-19 20:17:38

标签: php character-encoding

我有一个网站,他的PHP收集与当前脚本位于同一目录中的所有其他文件,并从中生成一个菜单(此菜单包含运行脚本的当前文件)。

当我从这个文件名列表生成此菜单的HTML时,我会检查每个文件名是否等于当前文件的名称(通过__ FILE __)。如果是这样,我会应用一种样式来突出显示菜单中的该项目。

我的文件名有法语口音,因为文件名也在页面标题中使用。这在Chrome和Firefox中运行良好,但Safari和IOS不起作用;法语口音使这个过程混乱,因为从我的文件名中删除法语口音可以解决问题。

这是我的代码:

从当前目录中获取所有相关文件

if ($handle = opendir(getcwd())) {
    $albums = array();
    while (false !== ($entry = readdir($handle))) {
        if(is_numeric(substr($entry, 0, 4))) array_push($albums, $entry);
    }
    closedir($handle);
}

这是我的字符串比较,用它们的var_dump来减弱:(文件名清除没有添加,假设两个vars都给出了名称文件名结构)

for($i=0; $i < count($albums); $i++){
    echo var_dump($albums[$i]); echo var_dump(basename(__FILE__));
}

产生回声:

string(26) "2010_Kalymnos,_Grèce.php" 
string(25) "2010_Kalymnos,_Grèce.php" 

当我尝试用UTF_8或ASCII强制它们时,为了看看它们如何处理法国口音,他们以不同的方式转换口音,但我不知道是什么导致了这一点。它是我用来获取文件的方法(__ FILE __,readdir())?

我的HTML文件是utf-8,如果这很重要的话。将我的PHP专门设置为UTF-8也无法解决问题。

修改

<?php echo bin2hex($albums[$i]); echo '<br/>'.bin2hex($originFilename);?>

结果:

323031305f4b616c796d6e6f732c5f477265cc8063652e706870
323031305f4b616c796d6e6f732c5f4772c3a863652e706870

在这两个中,第一个十六进制字符串是正确的。

1 个答案:

答案 0 :(得分:1)

给定十六进制编码输出,我们可以看到两个字符串的不同之处。第一个读取65cc80,其中第二个读取c3a8。这表明您是non-normalized Unicode strings的受害者。

第一个序列对应于两个Unicode字符U+0065LATIN SMALL LETTER E)和U+0300COMBINING GRAVE ACCENT)。如您所见,连接它们的UTF-8编码形式会给出十六进制编码的字节序列0x65cc80

第二个序列对应于单个Unicode字符U+00E8LATIN SMALL LETTER E WITH GRAVE),其编码为0xc3a8

这里发生的是你有两个字节序列,它们不是位相同的,但在逻辑上等同于Unicode规则。当您想要比较字符串时,您需要一个编码和标准化感知比较函数,您需要预先规范化字符串(然后您可以使用哑比较函数,如字符串相等)。 / p>

不幸的是我不知道在PHP中进行逻辑等效比较的任何方法,因此解决方案是安装intl扩展并使用Normalizer类将两个字符串转换为标准化表单C {{ 3}}