PHP文字列はバイトシーケンスであり、タグ付けされたエンコーディングは一切ありません。文字列値は、クライアント(HTTP経由)、データベース、ファイル、またはソースコードの文字列リテラルなど、さまざまなソースから取得できます。PHPはこれらすべてをバイトシーケンスとして読み取り、エンコード情報を抽出しません。
すべてのデータソースと宛先が同じエンコーディングを使用している限り、PHPが文字ではなくバイトをカウントするため、起こりうる最悪の事態は文字列の位置が間違っていることです(マルチバイトエンコーディングを使用する場合)。
ただし、エンコードが一致しない場合(たとえば、UTF-8として保存されたソースファイルに文字列リテラルを記述し、Latin-1を予期するデータベースに送信する場合)、PHPは変換を実行しません。幸いにもraw経由でバイトをコピーします。
最も簡単な解決策は次のとおりです。
- PHPの内部エンコーディングをUTF-8に設定します。
- すべてのソースファイルをUTF-8として保存します。
- 出力エンコードとしてUTF-8を使用します(適切な
Content-type
ヘッダーを送信することを忘れないでください)。
- UTF-8を使用するようにデータベース接続を設定します(
SET NAMES UTF8
MySQLで)。
- 可能な限り、他のすべてをUTF-8に構成します。
- 制御できないもの(サードパーティのWebサービスなど)については、エンコードを確認し、できるだけ早くUTF-8に変換し、できるだけ遅く他のエンコードに戻します。
なぜUTF-8なのか?すべてのUnicode文字を表現できるため、既存のすべての7ビットおよび8ビットエンコーディングに取って代わり、ASCIIとバイナリ互換性があるため、つまり、すべての有効なASCII文字列は有効なUTF-8文字列でもあります(vvではありません) 。)。
あなたの例では、これが起こります。
まず、ソースファイルを保存します。テキストエディターはおそらくUTF-8を使用するように構成されているため、文字列リテラルはディスク上でエンコードされたUTF-8になります。PHPはこのファイルを読み取り、文字列を一連のバイトとして解釈します。$original
UTF-8でエンコードされた7文字の文字列を保持するようになりました。これは単なるバイトシーケンスです(ただし、各文字は2バイト以上で表されるため、7バイト以上含まれています)。次にを呼び出すecho $original
と、エンコードされた文字列がそのままクライアントに送信されます。クライアントにUTF-8を期待するように指示した場合、すべては問題ありませんが、そうでない場合、PHPは違いを伝える方法がなく、ブラウザでゴミが発生します。実験として、これを試してください:
$original = "शक्नोम्यत्तुम्";
echo strlen($original);
strlen
はエンコードに依存せず、固定幅の8ビットエンコード、つまり文字ごとに1バイトを想定しているため、文字ではなくバイトをカウントします。