Zeichensätze, ein komplexes und oft auch verwirrendes Thema, in das ein klein wenig Licht gebracht werden soll. Zuallererst müssen wir festhalten, dass wir bei PHP strikt die Multibyte-Codierung von UTF-8 verwenden. Um mehr über die Internas von UTF-8 zu erfahren, besuche einfach Wikipedia - UTF-8
Beides, UTF-8 und UTF-8MB4 aus mySQL ist 100% kompatibel zu UTF-8 aus PHP.
In diesem Dokument sind die Schreibweisen utf8||utf-8 sowie utf8mb4||utf-8mb4 gleichbedeutend.
Aber keine Sorge, das ganze Kapitel mit Zeichensätzen, Sortierungen und so weiter ist eigentlich nur halb so kompliziert, wie es auf den ersten Blick aussehen mag.
Die Kenntnisse über die Zeichensätze in der Datenbank sind nur wirklich wichtig, wenn man selbst neue Datenbanktabellen entwirft.
Für Programmierer ist es wichtiger, den Umgang mit den Multibyte-Stringfunktionen von PHP zu beherrschen. Denn wenn man diese nicht richtig verstanden hat, kann es durchaus in schweren Fehlern enden.
PHP selbst kennt weder 'Kollationen' noch 'UTF-8MB4' noch ähnliches! Diese Dinge können bei PHP vergessen werden! PHP kennt jedoch UTF-8. Und zwar jenes, das exakt den Definitionen in RFC 3629 / ISO/IEC 10646-1:2000 Annex D entspricht und welches aus 1 bis 4 Bytes für jedes Zeichen besteht. UTF-8 (wie auch alle Latin_xxx Zeichensätze) ist in den ersten 128 Zeichen identisch zu der originalen ASCII Zeichentabelle.
Da in UTF-8 ein Zeichen mit 1, 2, 3 oder 4 Bytes dargestellt wird, funktionieren viele der 'alten' Stringfunktionen nicht mehr korrekt!
Bitte benutzt stattdessen die jeweils korrespondierenden Multibyte Funktionen! z.B. mb_strlen() anstatt strlen()
Beispiele:
Zeichen | Codepunkt | UTF-8 (bin) | Benennung |
---|---|---|---|
a | U+0061 | 01100001 | LATIN SMALL LETTER A |
á | U+00E1 | 11000011 10100001 | LATIN SMALL LETTER A WITH ACUTE |
ä | U+00E4 | 11000011 10100100 | LATIN SMALL LETTER A WITH DIAERESIS |
🤩 | U+1F929 | 11110000 10011111 10100100 10101001 | GRINNING FACE WITH STAR EYES |
<PHP> echo strlen('a'); ⇒ 1 || echo mb_strlen('a'); ⇒ 1 echo strlen('á'); ⇒ 2 || echo mb_strlen('á'); ⇒ 1 echo strlen('ä'); ⇒ 2 || echo mb_strlen('ä'); ⇒ 1 echo strlen('🤩'); ⇒ 4 || echo mb_strlen('🤩'); ⇒ 1 </PHP>
Im Gegensatz zu PHP implementiert mySQL nicht die vollständige RFC 3629 Definition von UTF-8.
In mySQL kann ein UTF-8 Zeichen nur maximal 3 Bytes groß sein. Daher kann mySQL keine 4-Byte Zeichen als UTF-8 speichern.
Um dieses Problem zu lösen, wurde jetzt nicht die UTF-8 Implementierung an die RFC angepasst, sondern es wurde ein neuer, zusätzlicher Zeichensatz 'UTF-8MB4' eingeführt. Dieser Zeichensatz kann jetzt auch 4-Byte Zeichen speichern.
Aber jetzt bitte nicht denken, UTF-8(PHP) und UTF-8MB4 wären das selbe!
Da gibt es weiterhin einen wichtigen Unterschied, der sich speziell bei größeren Datenbanken auswirken kann.
Der kleine aber feine Unterschied besteht im Speicherverbrauch dieser beiden Zeichensätze.
Während UTF-8 dynamisch nur genau soviel Speicherplatz reserviert, wie ein Zeichen benötigt, beschlagnahmt UTF-8MB4 für jedes Zeichen grundsätzlich immer volle 4 Bytes. Sowohl im Arbeitsspeicher als auch in der Datenbank.Das erhöht natürlich den Speicherbedarf und beeinflusst sowohl die Verarbeitungszeit als auch die mögliche Genauigkeit von Indizes, die Größe der Indextabellen und dadurch auch die Zugriffszeiten.
Beispiel Speicherverbrauch
Zeichensatz | Speicherbedarf |
---|---|
„This is a little text in english, containing 54 signs.“ | |
UTF-8: | 54 Byte |
UTF-8MB4: | 216 Byte |
„This is a big text in english, containing 16.000 signs.“ | |
UTF-8: | 16.000 Byte |
UTF-8MB4: | 64.000 Byte |
oops, Dein Text ist um die 200.000 Zeichen groß? Du hast viele solcher Texte?
Heutzutage sind alle modernen Browser in der Lage, UTF-8 codierte Zeichen darzustellen. Es gibt -fast- keinen Grund mehr, Sonderzeichen im HTML-Entity-Format auszugeben. Die wichtigste Ausnahme sind hier direkt anzeigbare Benutzereingaben,bei denen aus Sicherheitsgründen bestimmte Zeichen/Zeichenfolgen maskiert (escaped) werden sollten, damit hier kein Schadcode eingeschleust werden kann.
Auf jeden Fall ist es für den Browser hilfreich, wenigstens eins der folgenden Metatags im Head-Abschnitt eines HTML-Dokumentes auszugeben. <PHP><meta http-equiv=„content-type“ content=„text/html;charset=utf-8“>
<meta charset=„UTF-8“></PHP>
Collations existieren nicht in PHP. Diese sind nur Eigenschaften von Textfeldern in Datenbanktabellen!
Eine Collation hat mit Codierung und Speicherung erst einmal nichts zu tun. Sie bestimmt nur die Regeln, nach denen Texte für die Ausgabe sortiert und verglichen werden.
Nun, wenn wir auf die Auswahliste der möglichen Collations schauen, dann finden wir für praktisch jeden Zeichensatz eine lange Liste an Möglichkeiten. Einerseits sind da Collations die auf eine einzelne Sprache optimiert sind, andererseits finden wir auch Werte wie _unicode_ci und _general_ci, welche sprachübergreifend arbeiten.
Der Unterschied zwischen _unicode_ci und _general_ci ist hauptsächlich eine deutlich unterschiedliche Verarbeitungsgeschwindigkeit.
Auch die Sortierung ist unterschiedlich. 'unicode_ci' berücksichtig die wesentlichen Eigenheiten vieler Sprachen, während 'general_ci' rein Buchstabenorientiert arbeitet. Die Sortierung mit 'general_ci' ist deutlich schneller, aber auch viel weniger sprachbezogen und daher ungenauer als 'unicode_ci'.
Da unsere Datenbanken (auch die größten) relativ klein sind (10.000 Datensätze ist in der Welt der Datenbanken fast nichts) und auch im Hinblick auf die Mehrsprachigkeit, benutzen wir normalerweise immer die 'unicode_ci' Collation um die UTF-8MB4 Texte zu sortieren.