1

PHP が現在のスクリプトと同じディレクトリに他のすべてのファイルを収集し、これからメニューを生成する Web サイトがあります (このメニューには、スクリプトが実行されている現在のファイルが含まれます)。

このファイル名のリストからこのメニューの 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_dumps を使用した文字列の比較です。

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でそれらを強制しようとすると、フランス語のアクセントをどのように処理するかを確認すると、アクセントの変換が異なりますが、何が原因かわかりません. fileanmes( __ FILE __, readdir()) を取得するために使用したメソッドですか?

これが重要な場合に備えて、私の HTML ファイルは utf-8 です。私のPHPを特にUTF-8に設定しても問題は解決しません。

編集

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

結果:

323031305f4b616c796d6e6f732c5f477265cc8063652e706870
323031305f4b616c796d6e6f732c5f4772c3a863652e706870

2 つのうち、最初の 16 進文字列が正しいものです。

4

1 に答える 1

1

16 進数でエンコードされた出力から、2 つの文字列がどのように異なるかがわかります。最初のもの65cc80は 2 番目の読み取り場所を読み取りますc3a8これは、正規化されていない Unicode 文字列の被害者であることを示しています。

最初のシーケンスは、2 つの Unicode 文字U+0065( LATIN SMALL LETTER E ) とU+0300( COMBINING GRAVE ACCENT ) に対応します。ご覧のとおり、UTF-8 でエンコードされた形式を連結すると、16 進数でエンコードされたバイト シーケンスが得られます0x65cc80

2 番目のシーケンスは、単一の Unicode 文字U+00E8( LATIN SMALL LETTER E WITH GRAVE ) に対応し、 にエンコードされ0xc3a8ます。

ここで起こっていることは、ビットが同一ではないが、Unicode 規則によって論理的に同等である 2 つのバイト シーケンスがあるということです。文字列を比較したい場合は、エンコーディングと正規化を認識する比較関数が必要か、事前に文字列を正規化する必要があります (その後、文字列等価などのダム比較関数を使用できます)。

残念ながら、PHP で論理的等価比較を行う方法がわかりません。したがって、解決策は intl 拡張機能をインストールし、Normalizerクラスを使用して両方の文字列を正規化フォーム C に変換することNormalizer::normalizeです。

于 2013-09-19T20:35:15.993 に答える