1298

新しいサーバーをセットアップしていて、Web アプリケーションで UTF-8 を完全にサポートしたいと考えています。過去に既存のサーバーでこれを試したことがありますが、常に ISO-8859-1 にフォールバックする必要があるようです。

エンコーディング/文字セットを正確にどこに設定する必要がありますか? これを行うには、Apache、MySQL、および PHP を構成する必要があることを認識しています。従うことができる標準的なチェックリストはありますか、または不一致が発生する場所をトラブルシューティングできますか?

これは、MySQL 5、PHP、5、および Apache 2 を実行する新しい Linux サーバー用です。

4

15 に答える 15

1093

データストレージ:

  • データベース内のすべてのテーブルとテキスト列に文字セットを指定しutf8mb4ます。これにより、MySQL は UTF-8 でネイティブにエンコードされた値を物理的に格納および取得します。照合順序が指定されている場合 (明示的な文字セットなし) 、MySQL は暗黙的にutf8mb4エンコードを使用することに注意してください。utf8mb4_*

  • 古いバージョンの MySQL (< 5.5.3) では、残念ながらutf8、Unicode 文字のサブセットのみをサポートする単に を使用する必要があります。冗談だったらいいのに。

データ アクセス:

  • アプリケーション コード (PHP など) では、どのような DB アクセス方法を使用する場合でも、接続文字セットを に設定する必要がありますutf8mb4。このように、MySQL はアプリケーションにデータを渡すときにネイティブ UTF-8 からの変換を行わず、その逆も行いません。

  • 一部のドライバーは、接続文字セットを構成するための独自のメカニズムを提供します。これにより、独自の内部状態が更新され、接続で使用されるエンコーディングが MySQL に通知されます。これは通常、推奨される方法です。PHP の場合:

    • PHP ≥ 5.3.6 でPDO抽象化レイヤーを使用している場合charsetは、DSNで指定できます。

       $dbh = new PDO('mysql:charset=utf8mb4');
      
    • mysqliを使用している場合は、次を呼び出すことができますset_charset()

        $mysqli->set_charset('utf8mb4');       // object oriented style
        mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • 単純なmysqlで行き詰まっているが、たまたま PHP ≥ 5.2.3 を実行している場合は、 を呼び出すことができますmysql_set_charset

  • ドライバが接続文字セットを設定するための独自のメカニズムを提供しない場合は、クエリを発行して、接続上のデータがエンコードされることをアプリケーションがどのように期待するかを MySQL に伝える必要がある場合がありますSET NAMES 'utf8mb4'

  • utf8mb4/に関しては、上記と同じ考慮事項utf8が適用されます。

出力:

  • などの HTTP ヘッダーに UTF-8 を設定する必要がありますContent-Type: text/html; charset=utf-8。これは、php.iniで設定するかdefault_charset(推奨)、関数を使用して手動で行うことができheader()ます。
  • アプリケーションがテキストを他のシステムに送信する場合は、文字エンコーディングも通知する必要があります。Web アプリケーションでは、(HTTP 応答ヘッダーまたはHTML メタデータを介して) データが送信されるエンコーディングをブラウザーに通知する必要があります。
  • を使用して出力をエンコードする場合は、2 番目のパラメーターとしてjson_encode()追加します。JSON_UNESCAPED_UNICODE

入力:

  • ブラウザーは、ドキュメントに指定された文字セットでデータを送信するため、入力に対して特に何もする必要はありません。
  • リクエストのエンコーディングに疑いがある場合 (改ざんの可能性がある場合) は、受け取ったすべての文字列が有効な UTF-8 であることを確認してから、保存したり、どこでも使用したりできます。PHPmb_check_encoding()はこのトリックを実行しますが、宗教的に使用する必要があります。悪意のあるクライアントは、好きなエンコーディングでデータを送信できるため、これを回避する方法は実際にはありません.PHPにこれを確実に実行させるトリックは見つかりませんでした.

その他のコードに関する考慮事項:

  • 明らかに、提供するすべてのファイル (PHP、HTML、JavaScript など) は、有効な UTF-8 でエンコードする必要があります。

  • UTF-8 文字列を処理するたびに、安全に処理する必要があります。残念ながら、これは難しい部分です。mbstringおそらく、PHP の拡張機能を多用したくなるでしょう。

  • PHP の組み込み文字列操作は、デフォルトでは UTF-8 セーフではありません。 通常の PHP 文字列操作 (連結など) で安全に実行できることがいくつかありますが、ほとんどの場合、同等のmbstring関数を使用する必要があります。

  • 自分が何をしているのかを知るには (読んでください: めちゃくちゃにしないでください)、UTF-8 とそれが可能な限り低いレベルでどのように機能するかを知る必要があります。utf8.comのリンクをチェックして、知っておくべきことをすべて学ぶための優れたリソースを確認してください。

于 2008-11-10T21:43:05.257 に答える
160

chazomaticus の優れた回答に 1 つ追加したいと思います。

METAタグも忘れないでください(このように、またはHTML4またはXHTMLバージョンのように):

<meta charset="utf-8">

それは些細なことのように思えますが、IE7 では以前に問題が発生しました。

私はすべてを正しく行っていました。データベース、データベース接続、および Content-Type HTTP ヘッダーはすべて UTF-8 に設定されており、他のすべてのブラウザーでは問題なく動作しましたが、Internet Explorer は依然として「西ヨーロッパ」エンコーディングの使用を主張していました。

ページに META タグがないことが判明しました。それを追加すると問題が解決しました。

編集:

W3C には、実際にはI18N 専用のかなり大きなセクションがあります。この問題に関連する多くの記事があり、HTTP、(X)HTML、および CSS の側面について説明しています。

HTTP ヘッダーと HTML メタ タグ (XML として提供される XHTML の場合は XML 宣言) の両方を使用することをお勧めします。

于 2008-11-12T19:27:00.723 に答える
67

php.ini での設定に加えて、出力の前にコード内からdefault_charset使用して正しい文字セットを送信できます。header()

header('Content-Type: text/html; charset=utf-8');

ほとんどの文字列関数は Unicode では機能せず、一部の関数は文字列を完全に破壊する可能性があることを理解していれば、PHP で Unicode を操作するのは簡単です。PHP は、「文字」の長さを 1 バイトと見なします。これで問題ない場合もあります (たとえば、explode()バイト シーケンスのみを検索し、それをセパレータとして使用するため、検索する実際の文字は問題になりません)。しかし、実際には関数が文字で動作するように設計されている場合、PHP はテキストに Unicode で検出されるマルチバイト文字が含まれていることを認識できません。

チェックインするのに適したライブラリはphputf8です。これにより、すべての「悪い」関数が書き直され、UTF8 文字列を安全に操作できるようになります。mbstring 拡張機能のような拡張機能もありますが、移植性が高いため、ライブラリを使用することを好みます (しかし、私はマスマーケット製品を作成しているので、それは私にとって重要です)。しかし、phputf8 は、バックグラウンドで mbstring を使用して、パフォーマンスを向上させることができます。

于 2008-11-10T21:30:36.420 に答える
37

警告:この回答は PHP 5.3.5 以下に適用されます。PHP バージョン 5.3.6 (2011 年 3 月リリース) 以降では使用しないでください。

PDO + MySQLおよび壊れたUTF-8エンコーディングに対するPalecの回答と比較してください。


PDO を使用している人に問題が見つかりました。その答えは、これを PDO 接続文字列に使用することでした。

$pdo = new PDO(
    'mysql:host=mysql.example.com;dbname=example_db',
    "username",
    "password",
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

これを取得したサイトはダウンしていますが、幸運にも Google キャッシュを使用して取得できました。

于 2012-09-11T15:40:11.507 に答える
26

私の場合、mb_split正規表現を使用するを使用していました。したがって、正規表現エンコーディングがutf-8であることを手動で確認する必要もありました。mb_regex_encoding('UTF-8');

mb_internal_encoding()ちなみに、実行して内部エンコーディングがutf-8ではないことも発見し、を実行して変更しましたmb_internal_encoding("UTF-8");

于 2012-02-23T22:20:22.950 に答える
16

これらの素晴らしい回答に追加する唯一のことは、ファイルを utf8 エンコーディングで保存することを強調することです。ブラウザーは、コード エンコーディングとして utf8 を設定するよりもこのプロパティを受け入れることに気付きました。適切なテキスト エディターであれば、これが表示されます。たとえば、Notepad++ にはファイル エンコーディングのメニュー オプションがあり、現在のエンコーディングが表示され、それを変更できます。私のすべてのphpファイルでは、BOMなしでutf8を使用しています。

少し前に、他の誰かが設計した php/mysql アプリケーションに utf8 サポートを追加するよう依頼されました。すべてのファイルが ANSI でエンコードされていることに気付きました。そのため、ICONV を使用してすべてのファイルを変換し、データベース テーブルを変更してutf8 charset と utf8_general_ci を照合し、接続後に「SET NAMES utf8」をデータベース抽象化レイヤーに追加し (5.3.6 以前を使用している場合は、接続文字列で charset=utf8 を使用する必要があります)、文字列関数を変更して、php マルチバイトを使用します。文字列関数と同等です。

于 2014-09-10T03:39:22.387 に答える
15

strtolower()を使用すると、特殊文字の後にデータが切り捨てられるという問題が発生する可能性があることを最近発見しました。

解決策は使用することでした

mb_strtolower($string, 'UTF-8');

mb_ はマルチバイトを使用します。より多くの文字をサポートしますが、一般的に少し遅くなります。

于 2014-01-13T09:37:02.187 に答える
10

私はちょうど同じ問題を経験し、PHP マニュアルで適切な解決策を見つけました。

すべてのファイル エンコーディングを UTF8 に変更してから、接続のデフォルト エンコーディングに変更しました。これですべての問題が解決しました。

if (!$mysqli->set_charset("utf8")) {
    printf("Error loading character set utf8: %s\n", $mysqli->error);
} else {
   printf("Current character set: %s\n", $mysqli->character_set_name());
}

ソースを表示

于 2015-05-05T21:36:17.983 に答える
10

PHP では、マルチバイト関数を使用するか、 mbstring.func_overloadをオンにする必要があります。そうすれば、1バイト以上の文字がある場合、strlenのようなものが機能します。

また、応答の文字セットを特定する必要があります。上記のように AddDefaultCharset を使用するか、ヘッダーを返す PHP コードを記述できます。(または、HTML ドキュメントに META タグを追加することもできます。)

于 2008-11-10T21:29:21.867 に答える
7

クライアントとしてのPHPではなく、MySQLサーバーに文字セットを決定させたい場合(古い動作;私の意見では好ましい)、に追加skip-character-set-client-handshakeしてみてくださいmy.cnf、の下[mysqld]に、および再起動しmysqlます。

これは、UTF8 以外を使用している場合に問題を引き起こす可能性があります。

于 2015-02-11T23:52:55.773 に答える
7

PHP での Unicode サポートは、いまだに大混乱で​​す。ISO8859 文字列 (内部で使用) を utf8 に変換することはできますが、Unicode 文字列をネイティブに処理する機能がありません。つまり、すべての文字列処理関数が文字列を壊して破損させます。したがって、適切な utf8 サポートのために別のライブラリを使用するか、すべての文字列処理関数を自分で書き直す必要があります。

簡単な部分は、HTTP ヘッダーやデータベースなどで文字セットを指定するだけですが、PHP コードが有効な UTF8 を出力しない場合、それは問題ではありません。これは難しい部分であり、PHP は実質的に何の助けにもなりません。(PHP6 はこれの最悪の部分を修正することになっていると思いますが、それはまだしばらく先のことです)

于 2008-11-10T21:48:07.320 に答える
6

一番の答えは素晴らしいです。これが私が通常のdebian/php /mysqlセットアップでしなければならなかったことです:

// storage
// debian. apparently already utf-8

// retrieval
// the mysql database was stored in utf-8, 
// but apparently php was requesting iso. this worked: 
// ***notice "utf8", without dash, this is a mysql encoding***
mysql_set_charset('utf8');

// delivery
// php.ini did not have a default charset, 
// (it was commented out, shared host) and
// no http encoding was specified in the apache headers.
// this made apache send out a utf-8 header
// (and perhaps made php actually send out utf-8)
// ***notice "utf-8", with dash, this is a php encoding***
ini_set('default_charset','utf-8');

// submission
// this worked in all major browsers once apache
// was sending out the utf-8 header. i didnt add
// the accept-charset attribute.

// processing
// changed a few commands in php, like substr,
// to mb_substr

それがすべてでした!

于 2011-01-14T16:13:18.160 に答える
0

ただのメモ:

非ラテン文字が として表示されるという問題に直面しています。質問をしましたが、この正規の質問への参照で閉じられました。?????????すべてを試しましたが、何をしても.??????????MySQL

これは主に、間違った文字セットを使用してデータベースに挿入され、実際には疑問符文字に変換されて保存された古いデータをテストして?いるためです。つまり、元のテキストを永久に失い、何をしようとしても得られません???????

この質問の回答から学んだことを新しいデータに再適用すると、問題が解決する可能性があります。

于 2019-08-23T19:10:26.897 に答える