開発者として PHP または MySQL 快適な英語のみの文字セットの範囲を超えると、UTF-8の素晴らしく奇妙な世界にすぐに巻き込まれます。
クイックルックUTF-8入門書で 作業 これに先立ち、世界中のアーティストの経歴を表示するときに、データエンコーディングの問題に遭遇し始めました。データが正しくエンコードされている場合とされていない場合があるため、保存されたデータに問題があることがすぐに明らかになりました。
これにより、プログラマーは、JavaScript、HTML文字セットメタタグ、PHPなどを使用してパッチを組み合わせて実装するようになりました。間もなく、60万人のアーティストの経歴のリストが作成され、情報はダブルコードまたはトリプルコードになり、データは、機能をプログラムした人やパッチを適用した人に応じて、さまざまな方法で保存されました。古典的な技術的なネズミの巣。
実際、UTF-8データエンコーディングの問題をナビゲートすることは、苛立たしい経験になる可能性があります。この投稿は、実際の経験と学んだ教訓に基づいて(そして、部分的には発見された情報に感謝して)、特にPHPとMySQLを使用するときにこれらの問題に取り組むための簡潔な「クックブック」を提供します ここに Y ここに パス内)。
具体的には、この投稿で次のことを取り上げます。
最初に行う必要があるのは、デフォルトの文字セットとしてUTF-8を使用するように「php.ini」ファイルを変更することです。
default_charset = 'utf-8';
(( 注意: 後でphpinfo()を使用して、正しく設定されていることを確認できます )。
さて、PHPとUTF-8は一緒に正常に動作するはずです。真実?
まあ、正確ではありません。実際、彼らはそうすることにさえ近づいていません。
この変更により、PHPは常にUTF-8を文字エンコード(タイプヘッダー-ブラウザー応答コンテンツ)として出力しますが、UTF-8文字を正しく処理および生成するには、PHPコードにいくつかの変更を加える必要があります。 。
関連: ApeeScape開発者によるPHPのベストプラクティスとヒントPHPコードがUTF-8データエンコーディングサンドボックスで適切に処理されるようにするには、次のことを行う必要があります。
PHPコードによるすべてのヘッダー出力の文字セットとしてUTF-8を設定します。
各PHP出力ヘッダーで、エンコードとしてUTF-8を指定します。
header( ‘Content-Type:text / html; charset = utf-8’);
XMLのエンコードタイプとしてUTF-8を指定します
function utf8_for_xml($string) { return preg_replace('/[^x{0009}x{000a}x{000d}x{0020}-x{D7FF}x{E000}-x{FFFD}]+/u', ' ', $string); }
サポートされていない文字をXMLから削除する
すべてのUTF-8文字がXMLドキュメントで受け入れられるわけではないため、生成するXMLからすべてのタイプの文字を削除する必要があります。これを行うのに便利な関数(ここで見つけました)は次のとおりです。
$safeString = utf8_for_xml($yourUnsafeString);
コードでこの関数を使用する方法は次のとおりです。
htmlspecialchars($str, ENT_NOQUOTES, 'UTF-8')
すべてのHTMLコンテンツの文字セットとしてUTF-8を指定します
HTMLコンテンツの場合、エンコーディングとしてUTF-8を指定します。
default_charset
HTMLフォームでは、エンコーディングとしてUTF-8を指定します。
htmlspecialchars
htmlspecialcharsへのすべての呼び出しのエンコーディングとしてUTF-8を指定します
例えば:
htmlentities
注意: PHP 5.6.0以降、値mysql_set_charset
デフォルトで使用されます。 PHP 5.4.0の時点では、UTF-8がデフォルトでしたが、PHP 5.4.0より前では、ISO-8859-1がデフォルトとして使用されていました。したがって、この引数は技術的にオプションですが、安全のために、常にUTF-8を明示的に指定することをお勧めします。
また、UTF-8の場合、$link = mysql_connect('localhost', 'user', 'password'); mysql_set_charset('utf8', $link);
Y mysql_set_charset
それらは交換可能に使用できます。
mysqli::set_charset
を使用して、MySQLデータベースとデータを交換するときに使用するデフォルトの文字セットとしてUTF-8を指定します。
$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'test'); /* check connection */ if (mysqli_connect_errno()) { printf('Connect failed: %s
', mysqli_connect_error()); exit(); } /* change character set to utf8 */ if (!$mysqli->set_charset('utf8')) { printf('Error loading character set utf8: %s
', $mysqli->error); } else { printf('Current character set: %s
', $mysqli->character_set_name()); } $mysqli->close();
PHP 5.5.0以降、iconv
は非推奨であり、iconv_strlen
代わりに使用する必要があります:
mbstring
文字表現に1バイト以上が必要な場合(UTF-8のように)、失敗するか、少なくとも期待どおりに動作しないPHP関数がいくつかあります。例として、文字数ではなくバイト数を返すstrlen関数があります。
これに対処するために利用できる2つのオプションがあります。
機能 [mysql] default-character-set=UTF-8 [mysqld] character-set-client-handshake = false #force encoding to uft8 character-set-server=UTF-8 collation-server=UTF-8_general_ci [mysqld_safe] default-character-set=UTF-8
PHPでデフォルトで使用可能で、これらの関数の多くの互換性のあるマルチバイトバージョンを提供します(たとえば、my.ini
など)。ただし、これらの関数に提供する文字列は、正しくエンコードする必要があることに注意してください。
どこでC ++を学ぶことができますか
拡張子もあります mysql> show variables like 'char%';
PHPへ(アクティベーションと構成に関する情報が利用可能です ここに )。この拡張機能は、マルチバイトエンコーディングに適切に対応する機能の完全なセットを提供します。
MySQL / UTF-8側では、my.iniファイルを次のように変更する必要があります。
対応する各タグの後に次の構成パラメーターを設定します。[client] default-character-set = UTF-8
| character_set_client | UTF-8 | character_set_connection | UTF-8 | character_set_database | UTF-8 | character_set_filesystem | binary | character_set_results | UTF-8 | character_set_server | UTF-8 | character_set_system | UTF-8 | character_sets_dir | /usr/share/mysql/charsets/
set names UTF-8;
ファイルに上記の変更を加えた後、MySQLデーモンを再起動します。
UTF-8エンコーディングを使用するようにすべてが正しく構成されていることを確認するには、次のクエリを実行します。
sphinx.conf
結果は次のようになります。
charset_type = utf-8
代わりに、これらのいずれかにlatin1がリストされている場合は、構成をチェックして、MySQLデーモンが正常に再起動されたことを確認してください。
MySQL UTF-8は、実際にはUTF-8文字セットの部分的な実装です。 具体的には、MySQL UTF-8データエンコーディングは最大3バイトを使用しますが、UTF-8文字のフルセットをエンコードするには4バイトが必要です。これは言語のすべての文字に問題ありませんが、アストラルシンボル(コードポイントの範囲がU +010000からU + 10FFFF)をサポートする必要がある場合は、MySQLUTF-8ではサポートできない4バイトのエンコーディングが必要です。 MySQL 5.5 0.3では、これは文字セットのサポートを追加して議論されました utf8mb4 、 これは、文字ごとに最大4バイトを使用するため、完全なUTF-8文字セットをサポートします。したがって、MySQL 5.5.3以降を使用している場合は、データベース/テーブル/行の文字セットとしてUTF-8の代わりにutf8mb4を使用してください。詳細については、こちらをご覧ください。
接続しているクライアントにMySQLとの通信のエンコーディングを指定する方法がない場合、接続が確立されたら、次のコマンド/クエリを実行する必要があります。
sql_query_pre = SET CHARACTER_SET_RESULTS=UTF-8
データベースをモデル化するときにvarcharフィールドのサイズを決定するときは、UTF-8文字が1文字あたり最大4バイトを必要とする可能性があることを忘れないでください。
Sphinx構成ファイル(つまり、sql_query_pre = SET NAMES UTF-8
):
インデックス定義を次のように設定します。
charset_table
スタートアップの市場戦略に行く
フォント定義に以下を追加します。
ALTER SCHEMA `your-db-name` DEFAULT CHARACTER SET UTF-8;
mysql> show variables like 'char%';
エンジンを再始動し、すべてのインデックスをやり直します。
CcĆćĈĉĊċČčのような文字が検索目的で同じように扱われるようにSphynxを構成する場合は、mysqldump -u USERNAME -pDB_PASSWORD --opt --skip-set-charset --default-character-set=latin1 --skip-extended-insert DATABASENAME --tables TABLENAME > DUMP_FILE_TABLE.sql
を構成する必要があります。 (文字の折りたたみとも呼ばれます)これは基本的に文字間のマッピングです。詳細情報が利用可能です ここに 。
latin1で既にエンコードされている既存のデータベースがある場合、latin1をUTF-8に変換する方法は次のとおりです。
上記のように、my.iniファイルの構成設定にすべての変更を加えたことを確認してください。
次のコマンドを実行します。
mysqldump -u root --opt --skip-set-charset --default-character-set=latin1 --skip-extended-insert artists-database --tables tbl_artist > tbl_artist.sql
コマンドラインから、UTF-8用にすべてが正しく構成されていることを確認します
perl -i -pe 's/DEFAULT CHARSET=latin1/DEFAULT CHARSET=UTF-8/' DUMP_FILE_TABLE.sql
変換するテーブルのダンプファイルをlatin1エンコーディングで作成します。
mysql> source 'DUMP_FILE_TABLE.sql';
例:
mysql> select count(*) from MY_TABLE where LENGTH(MY_FIELD) != CHAR_LENGTH(MY_FIELD);
グローバル検索を実行し、ダンプファイル内の文字セットをlatin1からUTF-8に置き換えます。
たとえば、Perlの使用:
create table temptable ( select * from MY_TABLE where LENGTH(MY_FIELD) != CHAR_LENGTH(MY_FIELD));
Windowsユーザーへの注意: この文字セット置換文字列(latin1からUTF-8)は、ワードパッド(またはvimなどの他のテキストエディター)で検索と置換を使用して実行することもできます。必ずファイルをそのまま保存してください(Unicodeテキストファイルとしてではありません!)。
この時点から、データベースデータをいじり始めるので、まだ行っていない場合は、データベースをバックアップすることをお勧めします。次に、データベース内のダンプを復元します。
alter table temptable modify temptable.ArtistName varchar(128) character set latin1;
正しく変換されなかったレコードを見つけて修正します。非ASCII文字は設計上マルチバイトであるため、バイト長を文字長と比較することで見つけることができます(つまり、二重UTF-8文字を含む可能性のある行を識別します)。エンコードされているため、修正する必要があります。
マルチバイト文字を含むレコードがあるかどうかを確認します(このクエリがゼロを返す場合、テーブルにマルチバイト文字を含むレコードがないはずなので、手順8に進むことができます)。
ArtistName
マルチバイト文字を含む行を一時テーブルにコピーします。
alter table temptable modify temptable.ArtistName blob; alter table temptable modify temptable.ArtistName varchar(128) character set UTF-8;
二重にエンコードされたUTF-8文字を適切なUTF-8文字に変換します。
これは実際には少し注意が必要です。ダブルエンコード文字列は、UTF-8として適切にエンコードされた文字列です。ただし、MySQLは、列をUTF-8エンコーディングに設定したときに、(latin1と考えられていたものから)再びUTF-8に変換するという誤った支持をしました。したがって、これを解決するには、MySQLがこの「好意」を実行しないようにするために、MySQLを「ごまかす」2段階のプロセスが必要です。
まず、列のエンコードタイプをlatin1に戻し、二重エンコードを排除します。
例:
delete from MY_TABLE where LENGTH(MY_FIELD) = CHAR_LENGTH(MY_FIELD);
注意: テーブルに正しいフィールドタイプを使用してください。上記の例では、テーブルの場合、 replace into MY_TABLE (select * from temptable);
の正しいフィールドタイプvarchar(128)でしたが、テーブルフィールドはテキストまたはその他のタイプにすることができます。正しく指定してください。
問題は、列のエンコードをUTF-8に戻すと、MySQLがlatin1からUTF-8のデータエンコードを再度実行し、最初の場所に戻ることです。これを回避するには、列タイプをblobに変更してから、UTF-8に設定します。これは、MySQLがblobのエンコードを試みないという事実を利用しています。したがって、二重エンコーディングの問題を回避するために、MySQL文字セット変換を「ごまかす」ことができます。
例:
|_+_|
(ここでも、上記のように、テーブルに適切なフィールドタイプを使用してください。)
一時テーブルに属する1バイト文字のみの行を削除します。
固定行を元のテーブルに再挿入します(これを行う前に、予防措置として、一時テーブルでいくつかの選択を実行して、正しく修正されていることを確認する必要があります)。
|_+_|
覚えておくべきもう1つのことは、ソースコードファイルやリソースファイルなどがUTF-8データエンコーディングで正しく保存されていることです。そうしないと、これらのファイル内のすべての「特殊」文字が正しく処理されない可能性があります。
たとえば、Netbeansでは、プロジェクトを右クリックしてプロパティを選択すると、[ソース]の下にデータエンコーディングオプションが表示されます(通常、デフォルトではUTF-8ですが、確認することをお勧めします)。
または、Windowsのメモ帳で、[ファイル]メニューの[名前を付けて保存...]オプションを使用し、ダイアログボックスの下部にある[UTF-8エンコード]オプションを選択します。 (メモ帳が提供する「Unicode」オプションは実際にはUTF-16であり、それはあなたが望むものではないことに注意してください。)
やや面倒かもしれませんが、MySQLおよびPHP UTF-8データエンコーディングの問題に体系的に対処するためにこれらの手順を確認する時間をとることで、時間を大幅に節約できます。長期的には、この種の系統的なアプローチは、システムにパッチを適用する一般的な傾向よりもはるかに優れています。
このガイドで、プロジェクト環境を最初にセットアップし、テキストと文字列の操作で文字エンコードを考慮したソフトウェアプロジェクト環境で作業するときに、データセットの定義を考慮することの重要性が強調されることを願っています。
関連: 動作しないPHPをデバッグする前に、PHP開発者が犯す最も一般的な10の間違いのリストを参照してください。動作しないPHPをデバッグする前に、PHP開発者が犯す最も一般的な10の間違いのリストを確認してください。