ずっとUTF-8

Nov 11 2008

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

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

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

回答

1044 chazomaticus Nov 11 2008 at 04:43

データストレージ

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

  • 古いバージョンの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ように適用されます。

出力

  • アプリケーションが他のシステムにテキストを送信する場合は、文字エンコードについても通知する必要があります。Webアプリケーションでは、データが送信されるエンコーディングをブラウザに通知する必要があります(HTTP応答ヘッダーまたはHTMLメタデータを介して)。

  • PHPでは、default_charsetphp.iniオプションを使用するかContent-Type、自分でMIMEヘッダーを手動で発行できます。これは手間がかかりますが同じ効果があります。

  • を使用して出力をエンコードする場合は、2番目のパラメーターとしてjson_encode()追加JSON_UNESCAPED_UNICODEします。

入力

  • 残念ながら、受信したすべての文字列を保存したり、どこでも使用したりする前に、有効なUTF-8であることを確認する必要があります。PHPmb_check_encoding()がそのトリックを実行しますが、それを忠実に使用する必要があります。悪意のあるクライアントは任意のエンコーディングでデータを送信できるため、これを回避する方法は実際にはありません。PHPにこれを確実に実行させるためのトリックは見つかりませんでした。

  • 現在のHTML仕様を読んだところ、次のサブ箇条書きは不要であるか、最新のHTMLではもはや有効ではありません。私の理解では、ブラウザはドキュメントに指定された文字セットでデータを処理して送信します。ただし、古いバージョンのHTML(XHTML、HTML4など)をターゲットにしている場合は、次の点が役立つ場合があります。

    • HTML5より前のHTMLの場合のみ:ブラウザーから送信されるすべてのデータをUTF-8にする必要があります。残念ながら、これを確実に行う唯一の方法は、accept-charsetすべての<form>タグに属性を追加することです<form ... accept-charset="UTF-8">
    • HTML5より前のHTMLの場合のみ:W3C HTML仕様では、クライアントはデフォルトでサーバーが提供する文字セットでフォームをサーバーに返送する必要があると規定されていますが、これは明らかに推奨事項にすぎないため、すべての文字を明示する必要があります。<form>鬼ごっこ。

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

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

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

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

  • 何をしているのかを知るには(読んでください:混乱させないでください)、UTF-8とそれが可能な限り低いレベルでどのように機能するかを本当に知る必要があります。あなたが知る必要があるすべてを学ぶためのいくつかの良いリソースについては、utf8.comからのリンクのいずれかをチェックしてください。

157 mercator Nov 13 2008 at 02:27

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

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

<meta charset="utf-8">

それは些細なことのように思えますが、IE7は以前にそれに関する問題を私に与えました。

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

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

編集:

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

  • FAQ:(X)HTMLページのエンコーディングをUTF-8に変更する
  • HTMLでの文字エンコードの宣言
  • チュートリアル:XHTML、HTML、CSSの文字セットとエンコーディング
  • HTTP文字セットパラメータの設定

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

66 chroder Nov 11 2008 at 04:30

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

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

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

チェックインするのに適したライブラリはphputf8です。これにより、すべての「不良」関数が書き換えられるため、UTF8文字列で安全に作業できます。mbstring拡張機能のように、これを実行しようとする拡張機能もありますが、移植性が高いため、ライブラリを使用することをお勧めします(ただし、マスマーケット製品を作成しているので、それは私にとって重要です)。しかし、phputf8は、とにかく、パフォーマンスを向上させるために舞台裏でmbstringを使用できます。

37 JimW. Sep 11 2012 at 22:40

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キャッシュを使用して取得できました。

25 JDelage Feb 24 2012 at 05:20

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

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

23 JimmyKane Jan 27 2014 at 16:16

まず第一に、5.3PHP未満の場合は、いいえ。取り組むべき問題がたくさんあります。

ユニコード書記素文字列操作ローカリゼーションなどを適切にサポートするintlライブラリについて言及している人がいないことに驚いています。以下を参照してください。

PHPBenelux'14でのElizabethSmithの スライドによるPHPでのUnicodeサポートに関する情報を引用します。

INTL

良い:

  • ICUライブラリのラッパー
  • 標準化されたロケール、スクリプトごとにロケールを設定
  • 数値の書式設定
  • 通貨のフォーマット
  • メッセージのフォーマット(gettextを置き換えます)
  • カレンダー、日付、タイムゾーン、時間
  • 文字変換器
  • なりすましチェッカー
  • リソースバンドル
  • コンバーター
  • IDNサポート
  • 書記素
  • 照合
  • イテレータ

悪い:

  • zend_multibiteをサポートしていません
  • HTTP入出力変換をサポートしていません
  • 関数のオーバーロードをサポートしていません

mb_string

  • zend_multibyteサポートを有効にします
  • 透過的なHTTP入力/出力エンコーディングをサポート
  • strtoupperなどの機能性のためのいくつかのラッパーを提供します

ICONV

  • 文字セット変換のプライマリ
  • 出力バッファハンドラ
  • MIMEエンコーディング機能
  • 変換
  • 一部の文字列ヘルパー(len、substr、strpos、strrpos)
  • ストリームフィルター stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')

データベース

  • mysql:テーブルおよび接続(照合ではない)での文字セットと照合。また、mysqlを使用しないでください--msqliまたはPDO
  • postgresql:pg_set_client_encoding
  • sqlite(3):ユニコードとintlのサポートでコンパイルされていることを確認してください

他のいくつかの落とし穴

  • 3番目の部分の拡張子を使用しない限り、PHPおよびWindowsでUnicodeファイル名を使用することはできません。
  • exec、proc_open、およびその他のコマンドライン呼び出しを使用している場合は、すべてをASCIIで送信します
  • プレーンテキストはプレーンテキストではなく、ファイルにはエンコーディングがあります
  • iconvフィルターを使用してその場でファイルを変換できます

追加された機能が変更された場合などに備えて、この回答を更新します。

15 PuertoAGP Sep 10 2014 at 10:39

これらの驚くべき答えに追加する唯一のことは、ファイルを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マルチバイトを使用するように文字列関数を変更します同等の文字列関数。

14 MiguelStevens Jan 13 2014 at 16:37

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

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

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

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

10 AbdulSadikYalcin May 06 2015 at 04:36

私はちょうど同じ問題を経験し、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());
}

ソースを見る

9 JW. Nov 11 2008 at 04:29

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

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

7 jalf Nov 11 2008 at 04:48

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

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

7 BudimirGrom Feb 12 2015 at 06:52

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

これにより、UTF8以外を使用している場合に問題が発生する可能性があります。

6 commonpike Jan 14 2011 at 23:13

一番の答えは素晴らしいです。これが私が通常の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

それがすべてでした!

2 castro_pereira Mar 25 2019 at 02:27

mysqlソリューションが必要な場合は、サーバーの移行後、2つのプロジェクトで同様の問題が発生しました。多くの解決策を検索して試した後、私はこれに出くわしました/これが機能する前に何もありません):

mysqli_set_charset($con,"utf8");

この行を設定ファイルに追加すると、すべて正常に機能します。

私はこの解決策を見つけました https://www.w3schools.com/PHP/func_mysqli_set_charset.asp HTMLクエリからの挿入を解決しようとしていたとき

がんばろう!

Accountantم Aug 24 2019 at 02:10

注:

ラテン文字以外の文字が?????????次のように表示されるという問題に直面しています。質問をしたところ、この正規の質問を参照して終了しました。何をしていても、すべてを試し??????????ましたMySQL

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

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

IjazAhmedBhatti Sep 27 2020 at 13:24

connection.php内:mysqli_set_charset($ con、“ utf8”); SQL照合ではutf = 8