Frage UTF-8 den ganzen Weg


Ich richte einen neuen Server ein und möchte UTF-8 vollständig in meiner Webanwendung unterstützen. Ich habe in der Vergangenheit versucht, auf bestehenden Servern und immer wieder auf ISO-8859-1 zurückgreifen müssen.

Wo genau muss ich die Kodierung / Zeichensätze einstellen? Ich bin mir bewusst, dass ich dafür Apache, MySQL und PHP konfigurieren muss - gibt es eine Standard-Checkliste, die ich befolgen kann, oder vielleicht, wo die Missverhältnisse auftreten?

Dies ist für einen neuen Linux-Server mit MySQL 5, PHP 5 und Apache 2.


986
2017-11-10 21:04


Ursprung


Antworten:


Datenspeicher:

  • Präzisiere das utf8mb4 Zeichensatz für alle Tabellen und Textspalten in Ihrer Datenbank. Dadurch speichert und ruft MySQL nativ in UTF-8 kodierte Werte ab. Beachten Sie, dass MySQL implizit verwendet wird utf8mb4 Codierung wenn a utf8mb4_* Sortierung wird angegeben (ohne expliziten Zeichensatz).

  • In älteren Versionen von MySQL (<5.5.3) werden Sie leider gezwungen sein, einfach zu verwenden utf8, die nur eine Teilmenge von Unicode-Zeichen unterstützt. Ich wünschte, ich mache Witze.

Datenzugriff:

  • In Ihrem Anwendungscode (z. B. PHP) müssen Sie bei jeder von Ihnen verwendeten DB-Zugriffsmethode den Verbindungszeichensatz festlegen utf8mb4. Auf diese Weise führt MySQL keine Konvertierung von seinem nativen UTF-8 durch, wenn Daten an Ihre Anwendung übergeben werden und umgekehrt.

  • Einige Treiber bieten ihren eigenen Mechanismus zum Konfigurieren des Verbindungszeichensatzes, der sowohl seinen eigenen internen Status aktualisiert als auch MySQL über die für die Verbindung zu verwendende Codierung informiert - dies ist normalerweise der bevorzugte Ansatz. In PHP:

    • Wenn du das benutzt PDO Abstraktionsschicht mit PHP ≥ 5.3.6, können Sie angeben charset in dem DSN:

      $dbh = new PDO('mysql:charset=utf8mb4');
      
    • Wenn du es benutzt mysqli, Du kannst anrufen set_charset():

      $mysqli->set_charset('utf8mb4');       // object oriented style
      mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • Wenn Sie mit schlicht fest sind mysql aber wenn PHP PHP 5.2.3 läuft, kannst du anrufen mysql_set_charset.

  • Wenn der Treiber keinen eigenen Mechanismus zum Festlegen des Verbindungszeichensatzes bereitstellt, müssen Sie möglicherweise eine Abfrage ausgeben, um MySQL mitzuteilen, wie Ihre Anwendung erwartet, dass Daten über die Verbindung codiert werden: SET NAMES 'utf8mb4'.

  • Die gleiche Überlegung bezüglich utf8mb4/utf8 gilt wie oben.

Ausgabe:

  • Wenn Ihre Anwendung Text an andere Systeme überträgt, müssen diese auch über die Zeichencodierung informiert werden. Bei Webanwendungen muss der Browser über die Codierung informiert werden, in der die Daten gesendet werden (über HTTP-Response-Header oder HTML-Metadaten).

  • In PHP können Sie die default_charset php.ini Option, oder manuell die Content-Type MIME-Header selbst, das ist nur mehr Arbeit, hat aber den gleichen Effekt.

Eingang:

  • Leider sollten Sie jede empfangene Zeichenfolge als gültiges UTF-8 überprüfen, bevor Sie versuchen, sie zu speichern oder an einem anderen Ort zu verwenden. PHPs mb_check_encoding() macht den Trick, aber Sie müssen es religiös verwenden. Es gibt wirklich keinen Weg, bösartige Clients können Daten in der von Ihnen gewünschten Kodierung senden, und ich habe keinen Trick gefunden, um PHP dazu zu bringen, dies zuverlässig für Sie zu tun.

  • Von meinem Lesen der Strömung HTML-SpezifikationDie folgenden Sub-Bullets sind für modernes HTML nicht mehr notwendig oder sogar noch gültig. Nach meinem Verständnis werden Browser mit dem für das Dokument angegebenen Zeichensatz arbeiten und Daten senden. Wenn Sie jedoch auf ältere HTML-Versionen (XHTML, HTML4 usw.) abzielen, können diese Punkte dennoch nützlich sein:

    • Nur für HTML vor HTML5: Sie möchten, dass alle Daten, die Ihnen von Browsern gesendet werden, UTF-8 sind. Leider, wenn Sie an dem einzigen Weg gehen, um dies zuverlässig zu tun, fügen Sie die hinzu accept-charset Attribut für alle Ihre <form> Stichworte: <form ... accept-charset="UTF-8">.
    • Nur für HTML vor HTML5: Beachten Sie, dass die W3C-HTML-Spezifikation besagt, dass Clients "Formulare" standardmäßig an den Server zurücksenden sollten, egal welcher Zeichensatz der Server bedient. Dies ist jedoch offensichtlich nur eine Empfehlung, daher muss jeder explizit angegeben werden <form> Etikett.

Andere Code Überlegungen:

  • Offensichtlich sollten alle Dateien, die Sie bereitstellen (PHP, HTML, JavaScript usw.), in gültigem UTF-8 codiert sein.

  • Sie müssen sicherstellen, dass Sie jedes Mal, wenn Sie eine UTF-8-Zeichenfolge verarbeiten, dies sicher tun. Dies ist leider der schwierige Teil. Wahrscheinlich möchten Sie PHP intensiv nutzen mbstring Erweiterung.

  • Die integrierten String-Operationen von PHP sind nicht Standardmäßig UTF-8 sicher.  Es gibt einige Dinge, die Sie mit normalen PHP-String-Operationen (wie Verkettungen) sicher tun können, aber für die meisten Dinge sollten Sie das Äquivalent verwenden mbstring Funktion.

  • Um zu wissen, was Sie tun (lesen Sie: nicht durcheinander), müssen Sie wirklich UTF-8 wissen und wie es auf dem niedrigsten möglichen Niveau funktioniert. Sieh dir einen der Links von an utf8.com für einige gute Ressourcen, um alles zu lernen, was Sie wissen müssen.


861
2017-11-10 21:43



Ich möchte etwas hinzufügen Chazomaticus 'ausgezeichnete Antwort:

Vergessen Sie nicht das META - Tag (wie dieses oder die HTML4- oder XHTML-Version davon):

<meta charset="utf-8">

Das scheint trivial zu sein, aber IE7 hat mir damit schon Probleme bereitet.

Ich habe alles richtig gemacht; Die Datenbank, die Datenbankverbindung und der Content-Type-HTTP-Header wurden alle auf UTF-8 gesetzt, und es funktionierte in allen anderen Browsern einwandfrei, aber Internet Explorer bestand immer noch darauf, die "westeuropäische" Codierung zu verwenden.

Es stellte sich heraus, dass auf der Seite das META-Tag fehlte. Das Hinzufügen hat das Problem gelöst.

Bearbeiten:

Das W3C hat eigentlich eine ziemlich große Abschnitt gewidmet I18N. Sie haben eine Reihe von Artikeln zu diesem Thema - die HTTP, (X) HTML und CSS Seite der Dinge beschreiben:

Sie empfehlen, sowohl den HTTP-Header als auch das HTML-Metatag zu verwenden (oder XML-Deklaration, wenn XHTML als XML bereitgestellt wird).


134
2017-11-12 19:27



Zusätzlich zur Einstellung default_charset In php.ini können Sie den korrekten Zeichensatz mit verwenden header() aus Ihrem Code vor jeder Ausgabe:

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

Die Arbeit mit Unicode in PHP ist einfach, solange Sie wissen, dass die meisten Zeichenfolgenfunktionen funktionieren nicht mit Unicode und einige können Zeichenketten vollständig zerlegen. PHP betrachtet "Zeichen" als 1 Byte lang. Manchmal ist das in Ordnung (zum Beispiel explode() sucht nur nach einer Bytefolge und verwendet sie als Trennzeichen - es ist also egal, nach welchen Zeichen Sie suchen. Aber zu anderen Zeiten, wenn die Funktion tatsächlich darauf ausgelegt ist, weiter zu arbeiten Figuren, PHP hat keine Ahnung, dass Ihr Text Multibyte-Zeichen enthält, die mit Unicode gefunden werden.

Eine gute Bibliothek zum Einchecken ist phputf8. Dies überschreibt alle "schlechten" Funktionen, so dass Sie sicher an UTF8-Strings arbeiten können. Es gibt Erweiterungen wie die mbstring-Erweiterung, die das auch für dich tun, aber ich bevorzuge die Verwendung der Bibliothek, weil sie portabler ist (aber ich schreibe Massenprodukte, das ist wichtig für mich). Aber phputf8 kann mbstring hinter den Kulissen verwenden, um die Leistung zu erhöhen.


55
2017-11-10 21:30



Altes Thema, ich weiß. Es wurde ein Problem mit jemandem festgestellt, der PDO verwendet und die Antwort war, dies für die PDO-Verbindungszeichenfolge zu verwenden:

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

Die Seite, von der ich das gemacht habe, ist down, konnte es glücklicherweise mit Google Cache bekommen.


26
2017-09-11 15:40



In meinem Fall benutzte ich mb_split, die Regex verwendet. Daher musste ich manuell sicherstellen, dass die Regex-Codierung utf-8 war mb_regex_encoding('UTF-8');

Als Randnotiz habe ich auch durch Laufen entdeckt mb_internal_encoding() dass die interne Kodierung nicht utf-8 war, und ich habe das geändert, indem ich ausgeführt habe mb_internal_encoding("UTF-8");.


20
2018-02-23 22:20



Vor allem, wenn Sie in <5.3PHP sind, dann nein. Sie haben eine Menge Probleme zu bewältigen.

Ich bin überrascht, dass keiner das erwähnt hat intl Bibliothek, die eine gute Unterstützung für Unicode, Grapheme, String-Operationen , Lokalisierung und viele mehr, siehe unten.

Ich werde ein paar Informationen über Unicode-Unterstützung in PHP zitieren Elizabeth Smiths  Dias beim PHPBenelux'14

INTL

Gut:

  • Wrapper um die ICU-Bibliothek
  • Standardisierte Ländereinstellungen, Gebietsschema pro Skript festlegen
  • Zahlenformatierung
  • Währungsformatierung
  • Nachrichtenformatierung (ersetzt gettext)
  • Kalender, Daten, Zeitzone und Zeit
  • Transliterator
  • Spoofchecker
  • Ressourcenbündel
  • Konverter
  • IDN-Unterstützung
  • Grapheme
  • Kollation
  • Iteratoren

Schlecht:

  • Zend_Multibit wird nicht unterstützt
  • Unterstützt die Konvertierung der HTTP-Eingabe-Ausgabe nicht
  • Unterstützt das Überladen von Funktionen nicht

mb_string

  • Aktiviert zend_multibyte-Unterstützung
  • Unterstützt transparente HTTP-In / Out-Codierung
  • Bietet einige Wrapper für Funktionalität wie Strtoupper

ICONV

  • Primär für die Zeichensatzkonvertierung
  • Ausgabepufferhandler
  • Mime-Encoding-Funktionalität
  • Umwandlung
  • einige String-Helfer (len, substr, strpos, strrpos)
  • Stream-Filter stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')

Datenbanken

  • mysql: Charset und Kollation bei Tabellen und bei der Verbindung (nicht die Kollatierung). Verwenden Sie auch nicht mysql - msqli oder PDO
  • postgresql: pg_set_client_encoding
  • sqlite (3): Stellen Sie sicher, dass es mit Unicode- und Intl-Unterstützung kompiliert wurde

Einige andere Gotchas

  • Sie können Unicode-Dateinamen mit PHP und Windows nur verwenden, wenn Sie eine 3. Teilerweiterung verwenden.
  • Senden Sie alles in ASCII, wenn Sie exec, proc_open und andere Befehlszeilenaufrufe verwenden
  • Einfacher Text ist kein einfacher Text, Dateien haben Kodierungen
  • Sie können Dateien im laufenden Betrieb mit dem iconv-Filter konvertieren

Ich werde diese Antwort aktualisieren, wenn sich die Funktionen ändern und so weiter.


19
2018-01-27 09:16



Das habe ich kürzlich entdeckt strtolower() kann zu Problemen führen, wenn die Daten nach einem Sonderzeichen abgeschnitten werden.

Die Lösung war zu verwenden

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

mb_ verwendet MultiByte. Es unterstützt mehr Zeichen, ist aber im Allgemeinen etwas langsamer.


13
2018-01-13 09:37



Die einzige Sache, die ich zu diesen erstaunlichen Antworten hinzufügen würde, um zu betonen, Ihre Dateien in utf8 Codierung zu speichern, habe ich festgestellt, dass Browser diese Eigenschaft über die Einstellung utf8 als Code-Codierung akzeptieren. Jeder vernünftige Texteditor wird Ihnen dies zeigen, zum Beispiel hat Notepad ++ eine Menüoption für das Encodieren von Dateien, es zeigt Ihnen die aktuelle Kodierung und ermöglicht Ihnen, diese zu ändern. Für alle meine PHP-Dateien verwende ich utf8 ohne BOM.

Vor einiger Zeit bat mich jemand jemand, utf8 Unterstützung für eine php / mysql Anwendung hinzuzufügen, die von jemand anderem entworfen wurde. Ich bemerkte, dass alle Dateien in ANSI kodiert waren, also musste ich ICONV verwenden, um alle Dateien zu konvertieren, die Datenbanktabellen zu ändern utf8 charset und utf8_general_ci sortieren, nach der Verbindung 'SET NAMES utf8' zur Datenbankabstraktionsschicht hinzufügen (wenn Sie 5.3.6 oder früher verwenden, müssen Sie charset = utf8 in der Verbindungszeichenfolge verwenden) und die Zeichenfolgenfunktionen ändern, um den php multibyte zu verwenden String-Funktionen entsprechen.


11
2017-09-10 03:39



In PHP müssen Sie entweder die Multibyte-Funktionenoder einschalten mbstring.func_overload. Auf diese Weise funktionieren Dinge wie strlen, wenn Sie Zeichen haben, die mehr als ein Byte benötigen.

Sie müssen auch den Zeichensatz Ihrer Antworten identifizieren. Sie können entweder AddDefaultCharset wie oben verwenden oder PHP-Code schreiben, der den Header zurückgibt. (Oder Sie können Ihren HTML-Dokumenten einen META-Tag hinzufügen.)


8
2017-11-10 21:29