php.de

Zurück   php.de > php.de Intern > Beitragsarchiv > Adventskalender 2009

 
 
LinkBack Themen-Optionen Thema bewerten
Alt 23.12.2009, 00:00  
Adventskalenderöffner
 
Benutzerbild von Nikolaus 2.0
 
Registriert seit: 27.11.2008
Beiträge: 72
PHP-Kenntnisse:
Fortgeschritten
Nikolaus 2.0 ist einfach richtig nettNikolaus 2.0 ist einfach richtig nettNikolaus 2.0 ist einfach richtig nettNikolaus 2.0 ist einfach richtig nettNikolaus 2.0 ist einfach richtig nett
Standard 27: Der ultimative Megakick der Superlative

27:
…oder wie bringe ich meiner Datenbank UTF-8 bei?
Wie auch dieses Türchen nutzen mittlerweile die meisten Webanwendungen UTF-8 und das aus gutem Grund. In einem internationalen Raum muss auch für jede Sprache und deren Zeichen Platz sein und jeden Benutzer erst einstellen zu lassen, welchen Zeichensatz er gern hätte, ist eine unsägliche Methode. Einerseits fände dies der Benutzer sicherlich nicht so lustig wie vielleicht der Programmierer, andererseits bedeutete es einen enormen Aufwand, der sich nicht rechnet. Folglich wird auf Unicode gesetzt, im Speziellen auf UTF-8.
In Verbindung mit MySQL gab es aber seit jeher Probleme mit diesem Zeichensatz, sicherlich deshalb, weil er erst mit MySQL 4.1 eingeführt wurde, welches auch erst im März 2005 released wurde… also praktisch gestern Abend.
Intern nutzt MySQL für die Metadaten zwar ausschließlich UTF-8, aber irgendwie wird stets angenommen, dass der Programmierer, der MySQL benutzen soll, zu dämlich dafür sei, weshalb der Standardzeichensatz stets Latin1 ist.
Um dem garstigen MySQL nun endlich UTF-8 beizubringen, bietet sich das allseits bekannte
Code:
SET NAMES 'utf8';
an, das meist mit mysql_query() an die Datenbank gesendet wird.
Doch halt! So sicher diese Methode zu sein scheint, umso tückischer ist sie, denn auch hier lauern diverse Stolpersteine, über die der eine oder andere sicherlich schon unglücklich gefallen ist.
Um diese zu umgehen, muss man zunächst verstehen, wie MySQL arbeitet und mit SET NAMES umgeht.
SET NAMES 'xyz' ist ein Shortcut für die folgenden Verbindungsparameter:
Code:
SET character_set_client = xyz;
SET character_set_results = xyz;
SET character_set_connection = xyz;
Damit wird MySQL erzählt, dass alle vom Client kommenden Daten im Zeichensatz xyz kodiert sind, dass alle Daten, die der Server zurückgibt, ebenfalls xyz-kodiert sein sollen und der vom Server selbst genutzte Zeichensatz auch xyz sein soll (dazu später mehr). Jetzt ist es aber am Client, dafür zu sorgen, dass die Daten auch wirklich im Zeichensatz xyz vorliegen, da MySQL hier nicht nachhelfen kann. Ist also die Verbindung bspw. auf UTF-8 gesetzt, im Query werden aber tatsächlich Latin1-kodierte Daten gesendet, dann nimmt der Server dennoch an, dass es sich um UTF-8 handelt. Ebenso verhält es sich umgekehrt, wenn Latin1 eingestellt, aber UTF-8 gesendet wird. Da UTF-8 die Zeichen mit 1 bis 4 Bytes speichert, ergeben sich bei Multibyte-Zeichen die allseits beliebten Doppelzeichen mit allerlei Buchstaben- und Tildensalat. Aber Vorsicht: ein Zeichensatzmischmasch kann auch vorkommen, ohne dass man es direkt merkt. Nämlich dann, wenn der Client den Server anweist, Zeichensatz A zu verwenden, Daten im Zeichensatz B sendet und vom MySQL-Server zurückbekommene Daten wieder als Zeichensatz A ausgibt. Die Verwunderung ist dann groß, wenn man phpMyAdmin öffnet und die seltsamen Zeichensatzfehler bemerkt.
Wofür genau jetzt character_set_connection steht, ist schnell erklärt. Da der Zeichensatz des Clients nicht unbedingt mit dem Zeichensatz der Datenbank übereinstimmen muss, nimmt MySQL intern eine Konvertierung vor. Es nimmt Daten im Zeichensatz character_set_client an und wandelt diese in character_set_connection um, ehe sie gespeichert werden (soll keine Konvertierung vorgenommen werden, kann dieser Parameter übrigens auch auf NULL gesetzt werden).

Es existiert aber noch eine zweite Variante neben SET NAMES, nämlich
Code:
SET CHARACTER SET 'utf8';
Die Verwirrung ist oft groß, da kaum jemandem die Unterschiede in allen Einzelheiten bekannt sind. Dabei ist der Unterschied gar nicht so kompliziert, wie er anmutet. Er besteht in den Systemvariablen, die gesetzt werden. Im Großen und Ganzen ist SET CHARACTER SET zum vorigen Statement identisch, besitzt aber einen entscheidenden Unterschied:
Code:
SET character_set_client = xyz;
SET character_set_results = xyz;
SET collation_connection = @@collation_database; 
wobei SET collation_connection = @@collation_database;implizit auch ein SET character_set_connection = @@character_set_database durchführt. Doch was heißt das nun? Um das zu verstehen, ist es zuerst wichtig, zu wissen, was eine Kollation (Collation) ist. Auch das ist sehr einfach zu erklären. Der Zeichensatz (Character Set) legt die Zuordnungen der Zeichen fest. Bis jetzt ist jedes Zeichen aber vollkommen einzigartig ohne jeden Bezug zu einem anderen Zeichen, also case-sensitive. Um jetzt festzulegen, dass A der gleiche Buchstabe ist wie a und ä ebenfalls dem a entspricht, muss eine Kollation her, welche diese Informationen bereitstellt.
MySQL nutzt Kollationen, um Literale miteinander vergleichen zu können. collation_connection legt dabei fest, in welchem Zeichensatz dies geschieht (wird allerdings ein Vergleich mit einer Spalte vorgenommen, so wird unabhängig von der Vorgabe auf jeden Fall die Kollation dieser Spalte genutzt, also bitte nie UTF-8-Daten mit einer Latin1-Spalte vergleichen!).
Bei SET CHARACTER SET wird die Kollation nun auf den Wert von collation_database, also die Kollation der Datenbank gesetzt anstatt auf den übergebenen Wert.
Dies kann aber zu Informationsverlusten führen, wenn Vergleiche mit Unicode-Zeichen vorgenommen werden, die Datenbank aber auf Latin1 eingestellt ist. SET CHARACTER SET sollte also nur eingesetzt werden, wenn die Kodierung der Datenbank definitiv bekannt ist.

Fassen wir somit zusammen. Um MySQL erfolgreich mit UTF-8 zu quälen, muss Folgendes gegeben sein:
  • Der Client selbst muss UTF-8 sprechen (heißt konkret: die PHP-Datei muss unbedingt in UTF-8 kodiert werden und vom Benutzer kommende Daten müssen ebenfalls in UTF-8 vorliegen)
  • SET NAMES 'utf8' muss an die Datenbank gesendet werden (auf der Kommandozeile wird dafür der Parameter --default-character-set=UTF8 genutzt)
  • Die Datenbank sowie deren Tabellen und Spalten müssen auf UTF-8 gestellt sein
  • Die von MySQL zurückgegebenen Werte sind UTF-8 und müssen auch als solche behandelt werden.

Ab PHP 5.2.3 existiert übrigens die Funktion mysql_set_charset(), welche statt einem manuellen SET NAMES genutzt werden sollte, da hier noch verifiziert wird, ob der gewünschte Zeichensatz vom Client überhaupt unterstützt wird. Darüberhinaus wird das interne Feld mysql->charset auf den entsprechenden Zeichensatz gesetzt, was bei der manuellen Variante ebenfalls nicht gegeben wäre.
Zu bedenken ist aber, dass neben der richtigen PHP-Version auch eine MySQL-Version 5.0.7 oder höher benötigt wird.
Nikolaus 2.0 ist offline  
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 23.12.2009, 01:50  
¯\_(ツ)_/¯
 
Benutzerbild von Flor1an
 
Registriert seit: 18.06.2008
Beiträge: 8.814
PHP-Kenntnisse:
Fortgeschritten
Flor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer AnblickFlor1an ist ein wunderbarer Anblick
Standard

Kann ich die Standardwerte für für die Verbindung in der Config direkt auf UTF8 setzen? Damit ich mir den Query mit SET NAMES sparen kann? Bzw. welche Einstellungen sind das?
Flor1an ist offline  
Alt 23.12.2009, 11:00  
Supermoderator HD
 
Benutzerbild von Manko10
 
Registriert seit: 16.03.2008
Beiträge: 8.425
PHP-Kenntnisse:
Fortgeschritten
Manko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende Zukunft
Standard

Geht in der my.cnf über default-xxx = abc; Siehe auch buildblog | MySql-Server auf UTF-8 umstellen
Mit init-connect = "SET NAMES 'utf8'" kannst du auch noch ein SET NAMES ausführen.
__________________
Refining Linux Advent Calendar series “24 Outstanding ZSH Gems
Manko10 ist offline  
Alt 23.12.2009, 11:02  
Benutzer
 
Registriert seit: 06.12.2009
Beiträge: 43
PHP-Kenntnisse:
Anfänger
Optimist befindet sich auf einem aufstrebenden Ast
Standard

Sicherheitshalber noch folgende Anmerkung:

Als ich eine deutsch-russische Seite erstellt habe, gab es für die deutschen Umlaute auch nach
PHP-Code:
SET NAMES 'utf8'
immer wieder Zeichensalat.

Abhilfe brachte erst ein Hinweis den ich nach tagelanger Suche im Internet fand:
Dieses Kommando sollte unmittelbar nach der Verbindung zur DB als erstes Query gesendet werden.

Und tatsächlich: Ich hatte davor noch ein anderes Query stehen.

Nach dem Platztausch lief dann alles so, wie ich das haben wollte.
Optimist ist offline  
Alt 23.12.2009, 11:14  
Supermoderator HD
 
Benutzerbild von Manko10
 
Registriert seit: 16.03.2008
Beiträge: 8.425
PHP-Kenntnisse:
Fortgeschritten
Manko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende ZukunftManko10 hat eine strahlende Zukunft
Standard

Um so etwas zu vermeiden gibt es in der my.cnf ja die Direktive init-connect.
Darüber hinaus eben auch die PHP-Funktion mysql_set_charset() (wobei die wahrscheinlich wieder der gleichen Idiotenunsicherheit wie header() und session_start() unterworfen ist).
__________________
Refining Linux Advent Calendar series “24 Outstanding ZSH Gems
Manko10 ist offline  
 


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Die ultimative Umfrage: Spinnen Off-Topic Diskussionen 15 28.07.2004 02:05

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
alles muss utf-8 sein, ultimative megakick, der ultimative kick der superlative, utf-8 tildensalat, set names php, php set names utf8, php.de ultimativer megakick, megakick der superlative, megakick der suüerlative, adventskalender - unicode (utf - 8), der ultimative megakick der superlative php, ultimative megakick der superlative, ultimative mega kick, ultimative 27, formular utf-8, ultimative megakick superlative, default website fragezeichen php, set names, superlative ultimative, ä in abfrage

Alle Zeitangaben in WEZ +1. Es ist jetzt 18:58 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum