Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder einen alternativen Browser verwenden.
Soweit funktionieren die Sonderzeichen auch, aber wehe irgendwas läuft anders.
Beispielsweise sehen meine Datenbankeinträge so aus: (Das Script, dass die Daten in die Datenbank schreibt ist ein reines PHP-Script)
Code:
Bahnhofsstraße
Im HTML-Dokument wird das zwar wieder richtig zurückgebastelt, aber schön ist das nicht, wenn es in der DB falsch drin steht. Außerdem kann das ja irgendwann mal Probleme geben. Probleme gibt es aber jetzt schon, wenn ich in einem reinen PHP-Script eine Variable mit Sonderzeichen verwende. Dann kann das Ergebnis so aussehen:
Code:
Der Eintrag wurde gel�scht.
Früher, als ich meine HTML-Dokumente noch so aufbaute war alles toll, aber irgendwie ist das ja veraltet.
HTML:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Blubber</title>
<link rel="stylesheet" type="text/css" href="../css/style.css">
<link rel="stylesheet" type="text/css" href="../css/print.css" media="print">
</head>
[...]
Sagt mir jemand, wie ich das Problem in den Griff bekomme?
PHPMyAdmin -> Allgemeine Einstellungen (Startseite) -> Zeichensatz/Kollation der MySQL-Verbindung: utf8_general_ci
um zukünftige Tabellen gleich mit UTF-8-Kodierung anzulegen. Und wenn du eine neue Tabelle anlegst, die Varchar oder Text als Typ hat, kannst du die Kollation ebenfalls auf utf8_general_ci setzen. Zumindest glaub ich mich zu erinnern, dass die auf ISO 8859-1 gesetzt wurde.
Sorge dafür, dass du durchgehend UTF-8 nutzt. Dass Umlaute aus String-Literalen in deinen PHP-Skripten als Replacement Character dargestellt werden, weist darauf hin, dass du die PHP-Skripte wohl in einer Legacy-Kodierung (mutmasslich ISO-8859-1 oder Windows-1252) statt als UTF-8 speicherst. Wähle in deinem Editor aus, dass die Skripte als UTF-8 ohne BOM gespeichert werden.
Über den von musv erwähnten Weg kannst du den Zeichensatz der Datenbank ändern. Dieser sollte ebenfalls UTF-8 sein, mit einer von dir gewählten Kollation (z.B. general_ci, german_ci, unicode_ci, ...). Ausserdem solltest du die Zeichencodierung der Datenbankverbindung auf UTF-8 setzen - verwendest du PHP/MySQL und die MySQL(i)-Erweiterung durch mysql(i)_set_charset() oder durch Ausführen des Querys
Nein, die Kodierung ist bei jeder utf8-Kollation UTF-8 und die Daten werden immer in derselben Weise übertragen (die zusätzlich durch die Zeichencodierung der Datenbankverbindung bestimmt wird, weshalb sie ebenfalls UTF-8 sein sollte). Unterschiede ergeben sich bei der Frage, welche Zeichen bei Vergleichen gleich sind und was die natürliche Reihenfolge der Zeichen ist - siehe
. Die bin-Kollation sortiert und vergleicht die Zeichen strikt anhand ihres Unicode-Codepoints, inklusive Unterscheidung zwischen Gross- und Kleinschreibung, wogegen in anderen Kollationen einige Zeichen als gleich gelten, die nicht identisch sind, so z.B. o=O=ö=Ö in der general_ci-Kollation.
Dann melde ich mich auch mal wieder.
Also intern klappt die Sache bereits, aber mit der Datenbank ist das so eine Sache. Muss man wirklich jedes mal SET NAMES utf8 machen? Was ist das den für ein bescheuerter Standard?
Außerdem funktioniert es bei mir nicht. In der Datenbank stehen trotzdem hässliche Zeichen. Habe
PHP:
$db_result = mysql_query("SET NAMES 'utf8'", $db_write, $db_connect) or die (mysql_error());
es reicht aus, die Query zu Beginn des Skripts einmal auszuführen. Die gilt dann für sämtliche Abfragen an die entsprechende Ressource.
Hast du die Kollation bei den vorhandenen Tabellen aktualisiert? Sind deine PHP-Skripts als UTF-8 ohne BOM gespeichert?
MySQL würde ich eher als proprietär bezeichnen, aber was daran bescheuert sein soll, kann ich unabhängig davon nicht erkennen. Wegen der Angabe in HTML beschwerst du dich ja offenbar auch nicht. Klar, man hätte sicherlich als Stanardeinstellung festlegen können, dass in Zukunft ohne jegliche abweichende Angabe UTF-8 verwendet wird. Aber damit würde man sowohl bei MySQL als auch bei HTML (und vielen anderen Systemen, die mit Zeichenkodierungen umgehen müssen) die Kompatibilität zu bestehenden Implementierungen verlieren, die teilweise noch aus Zeiten stammen, als die Nutzung von UTF-8 nicht üblich war.
Bei mir schon ... Mangels Angaben kann man dir schlecht weiterhelfen. Wie hast du überhaupt festgestellt, dass "hässliche Zeichen" in der Datenbank stehen? Wenn durchgehend UTF-8 verwendet wird, sollte es zumindest für neu eingefügte Daten problemlos funktionieren. Bestehende Daten wurden möglicherweise durch falsche Einstellungen/Kodierungen in der Vergangenheit tatsächlich nicht korrekt gespeichert. Da wären die (letztlich binär gespeicherten) Daten dann noch umzukodieren, sodass die Kodierung tatsächlich wie angegeben UTF-8 ist.
Der Forenbeitrag ist von 2008 und man hat das bis jetzt nicht vernünftig in MySQL gelöst bekommen? Respekt!
Gemäß dem Eingangsbeitrag dort wurde das Problem der mangels korrekter Kodierungsangaben falschen Interpretation doch gelöst? Da auch viele große Websites MySQL erfolgreich einsetzen, kann man außerdem wohl kaum davon sprechen, dass man das Problem nicht gelöst hat, nur weil du ein Problem damit hast.
Wenn ich das richtig verstanden habe, muss man dieses SET NAMES nicht direkt in die Verbindung packen, sondern kann das auch noch vorher machen. Nach der Verbindung zur Datenbank zum Beispiel
Das heißt, wenn ich eine include-Datei habe, in der die Verbindung zur Datenbank hergestellt wird, kann ich einfach folgendes druntersetzen:
PHP:
mysql_query("SET NAMES 'utf8'");
mysql_query("SET CHARACTER SET 'utf8'");
Dann füge ich das einmal ein und muss nie mehr darauf achten, weil die Datei ja per include-Befehl jedesmal eingefügt wird.
Kann das jemand bestätigen oder verbessern? :P
das stimmt nur, falls du nur eine einzige MySQL-Verbindung offen hast. Öffnest du mehrere Verbindungen zum MySQL-Server, musst du die Ressource der Query-Funktion übergeben. Ansonsten liegst du mit dem Include natürlich richtig, du musst nur darauf achten, dass du vor jeglichen Abfragen inkludierst.
Wenn ich das richtig verstanden habe, muss man dieses SET NAMES nicht direkt in die Verbindung packen, sondern kann das auch noch vorher machen. Nach der Verbindung zur Datenbank zum Beispiel
Was denn nun, vorher oder nachher? Ohne bestehende Verbindung kann es jedenfalls nicht funktionieren.
Das heißt, wenn ich eine include-Datei habe, in der die Verbindung zur Datenbank hergestellt wird, kann ich einfach folgendes druntersetzen:
PHP:
mysql_query("SET NAMES 'utf8'");
mysql_query("SET CHARACTER SET 'utf8'");
Dann füge ich das einmal ein und muss nie mehr darauf achten, weil die Datei ja per include-Befehl jedesmal eingefügt wird.
Kann das jemand bestätigen oder verbessern? :P
Ehm ja ersetze "Verbindung" mit "Abfrage" so war es ursprünglich gemeint.
Danke für die Verbesserung und den Hinweis mit den mysql_*-Funktionen. Wenn man das so anfangs gelernt hat und sich nicht immer auf dem Laufenden hält, passiert sowas.
Ich verstehe nur Bahnhof. Kann mir mal jemand bitte nen vernünftiges Code einstellen, der das alles verdeutlicht?
Ich bleibe aber dabei, dass UTF-8 ein scheiß Standard ist und weigere mich, es als Standard zu betrachten. Wäre es Standard, dann würde es einfach funktionieren und man bräuchte keine workarounds.
Gibt es Alternativen, die man verwenden kann?
Dein Problem wird nicht durch UTF-8 verursacht, sondern durch einen noch scheisseren anderen Standard. Wenn Du Deine Daten mit Iso-schlagmichtot-0815 in die DB kippst, dann musst Du es eben auch mit Iso-schlagmichtot-0815 auslesen, wenn Dir das Gehakel nicht passt.
Im übrigen wird alles was nicht UTF-8 heisst verboten wenn ich endlich Dikator bin. Es sei denn es heisst UTF-16. Also hurtig, die Anregungen hier im Thread nochmal lesen, steht schon alles da.
Sofern du wie empfohlen durchgehend UTF-8 nutzen willst, musst du entweder die my.cnf anpassen, sodass MySQL standardmäßig UTF-8 nutzt oder aber in Umgebungen, wo dir das nicht möglich ist oder aber in alten, parallel betriebenen Anwendungen Probleme macht, eben die zu nutzende Kodierung beim Verbinungsaufbau angeben. Das geht allgemein mit SET NAMES utf8, in PHP verwendet man aber eben besser mysql(i)_set_charset(), wie von Kugelfisch bereits erwähnt.
Kompliziert wird es erst, wenn Server, Datenbank, Tabelle und ggf. sogar Spalten unterschiedliche Kodierungen verwenden sind und dann noch für die Ein- und Ausgabe jeweils noch andere Kodierungen gewünscht sind. MySQL kann mit solchen Situationen durchaus umgehen, allerdings sollte man sie nach Möglichkeit vermeiden. Neben dem unnötigen Rechenaufwand ist eine Konvertierung zwischen verschiedenen Nicht-Unicode-Kodierungen in aller Regel nicht verlustfrei möglich, da es je nach Zeichenkodierung auch unterschiedliche Zeichenvorräte gibt, die sich nicht decken. In dem früher oft genutzten ISO-8859-1 lässt sich z. B. kein €-Zeichen darstellen, dieses Zeichen geht daher z. B. verloren, wenn man von UTF-8 nach ISO-8859-1 konvertiert. Das gleiche gilt natürlich auch für andere Zeichen, etwa typografische Anführungszeichen.
Wenn du bereits bestehende Datenbanken/Tabellen/Spalten hast, in denen die Daten falsch (weil abweichend von der jeweiligen Kodierungsangabe) hinterlegt wurden, sind diese Daten natürlich zu korrigieren, bevor du sie korrekt verwenden kannst. Am einfachsten geht das wohl, indem man die gesamte Datenbank exportiert, die Kodierungsangaben korrigiert und sie dann wieder importiert. Anschließend solltest du sinnvollerweise diese Datenbanken/Tabellen/Spalten noch nach UTF-8 konvertieren. Sonst muss MySQL Strings immer wieder umwandeln, was neben der unnötigen Rechenleistung eben auch zu dem Verlust von bestimmten Zeichen führen kann. Da wir deine Datenbank-Struktur und -Inhalte nicht kenen, kann man schlecht konkretere Hinweise geben.
Ich bleibe aber dabei, dass UTF-8 ein scheiß Standard ist und weigere mich, es als Standard zu betrachten.
Das ist dem Standard und dem Rest der Welt ziemlich egal. Es steht dir natürlich frei, eine alternative Zeichenkodierung zu entwerfen, die deiner Ansicht nach besser ist. Das Problem wird dann bloß sein, dass praktisch niemand außer dir einen Grund sehen wird, deine Kodierung zu implementieren, sofern sie keine gewichtigen Vorteile gegenüber UTF-8 hat. Du müsstest also auch entspechende Software bereitstellen, aber da stellt sich wieder dir Frage, weshalb man sie nutzen sollte. Du müsstest also auch Inhalte bereitstellen, die so attraktiv sind, dass man auch noch deine Software nutzen will. Am besten baust du wohl ein Paralleluniversum auf, in dem UTF-8 nicht existiert, das dürfte für die Akzeptanz deiner Kodierung am einfachsten sein ...
Wäre es Standard, dann würde es einfach funktionieren
Das ist eine seltsame Argumentation, hast du jemals irgendeinen Standard gelesen? Die sind selten "einfach". Sicherlich gibt es immer wieder mal die Erkenntnis, dass man aus heutiger Sicht etwas damals lieber anders hätte spezifizieren sollen, aber aus Kompatibilitätsgründen bleibt man dann halt lieber dabei. UTF-8 ist z. B. insofern kompatibel, dass alle Zeichen aus dem ASCII-Zeichenvorrat exakt so kodiert werden, wie in der ASCII-Kodierung. Das bedeutet z. B. dass man einen ASCII-kodierten Text ohne Umwandlung als UTF-8 verarbeiten kann. Ebenso kann man einen UTF-8-kodierten Text in lateinischer Schrift in einem nur ASCII-tauglichen Programm zumindest teilweise noch lesen.
UTF-8 funktioniert doch, das kannst du auf tausenden Websites jeden Tag live erleben. Auch hier im Board. Welche Workarounds meinst du? Dass Zeichen falsch interpretiert werden, wenn die Kodierung von der Kodierungsangabe abweichen, ist doch kein spezifisches UTF-8-Problem. Im deutschsprachigen Raum fällt das einem Windows-Nutzer vielleicht nicht so auf, weil MySQL standardmäßig latin-1 (= ISO-8859-1) verwendet, was sich mit dem von Windows im deutschsprachigen Raum verwendeten windows-1252 weitgehend deckt, sodass zumindest die Umlaute zufällig(!) korrekt verarbeitet werden, auch wenn man sich keine Gedanken über die Zeichenkodierung macht. Nutzt man hingegen ein modernes GNU/Linux-System (wo UTF-8 verwendet wird), so wird man bereits dort auf Probleme stoßen. Andersherum wird man aber auch auf Probleme stoßen, wenn man planlos windows-1252-kodierte Strings an ein System sendet, das UTF-8 erwartet. UTF-8 bietet gegenüber den Legacy-Kodierungen immerhin den großen Vorteil, dass man sich nach der erfolgreichen Umstellung keine Gedanken mehr machen muss. Bei den Legacy-Kodierungen gibt es schließlich je nach Sprache/Schrift eine andere und sie sind eben auch nicht verlustfrei ineinander umwandelbar.
Um Unicode-Zeichen und nicht nur eine kleine Auswahl daraus zu verwenden? Dann nur eine andere Unicode-Kodierung. Sowohl UTF-16 als auch UTF-7 sind allerdings in der Handhabung tatsächlich nicht unbedingt einfach (oder auch nur effizient). Falls du mit einer Legacy-Kodierung wie ISO-8859-1 auskommst, kannst du die natürlich auch weiterhin verwenden. Aber jammere dann nicht, wenn Daten verloren gehen, wenn doch mal Zeichen gespeichert werden sollen, die nicht im Zeichenvorrat enthalten sind. In HTML könnte man die Beschränkung auf den Zeichenvorrat teilweise durch die Nutzung von Entitäten oder Zeichenreferenzen aufheben. Spätestens bei der Verarbeitung von Formulardaten ist das aber nicht mehr möglich.
Das ist eine ganz schlechte Idee. Zum einen existieren nur zu sehr wenigen Unicode-Codepunkten überhaupt Entitäten, sodass die Ersetzung schnell unvöllständig wird, zum anderen bleibt das oben angesprochene Problem der Formulardaten. Auch ist es kaum sinnvoll, in HTML-Entitäten außerhalb einses HTML-Kontexts (wie MySQL) zu verwenden, denn dort haben diese eben keine besondere Bedeutung. Spätestens, wenn man auf die Daten zugreift, um sie in einem anderen Kontext (wie hier im Board z. B. bei Mails zu abonnierten Themen) auszugeben, ist das unklug. Allein schon weil eine Abfrage scheitern kann, wenn man die Strings darin nicht wieder exakt wie zuvor bei der Speicherung behandelt. Man dürfte also die vorgeschlagene unvollständige Umwandlung mit htmlentities nicht einmal nachträglich korrigieren, weil das die Integrität der Daten gefährdet. Auch würden dann die String-Funktionen in MySQL nur noch eingeschränkt brauchbar sein. Weder LENGTH(), noch CHAR_LENGTH() liefern dann z. B. noch die korrekten Werte.
Solange man die Möglichkeit hat, eine geeignete Zeichenkodierung zu verwenden, sollte man solche unnötig fehleranfälligen Zeichenreferenzen oder Entitäten daher besser vermeiden. Man kann ja auch hier im Board sehen, dass es damit Probleme gibt, da vBulletin offenbar beim Zitieren die Entitäten fälschlicherweise auflöst.
Ich bleibe aber dabei, dass UTF-8 ein scheiß Standard ist und weigere mich, es als Standard zu betrachten. Wäre es Standard, dann würde es einfach funktionieren und man bräuchte keine workarounds.
UTF-8 funktioniert einfach, man braucht auch nichts zu konfigurieren und auch keinerlei Workarounds, sofern einfach jede Komponente UTF-8 per default verwendet. Das ist in Deiner Konfiguration nicht der Fall. Allerdings meckerst du über die falsche Komponente.
Ja, gibt es. Nimm Linux statt Windows. Dann hast du kein's Deiner genannten Probleme.
Da in der BWLer-Welt Linux noch weitgehend unbekannt ist, haben wir auf Arbeit ähnliche Probleme mit der Business-Software (kein Web), die wir entwickeln. Unser Produkt arbeitet intern mit UTF-8. Natürlich muss der ganze Scheiß, den Windows liefert, erst nach UTF-8 konvertiert werden.
Jetzt könntest du wieder sagen, das UTF-8 Müll wäre, weil man es von Windows aus erst konvertieren muss. Dummerweise wird unser Produkt weltweit verkauft. Und ein chinesisches Windows nutzt eine andere Codepage als ein deutsches oder ein arabisches. Wäre Windows nativ UTF-8 könnten wir uns die ganzen Konvertierungen sparen. Durch die dämlichen Windows-Codepages müssen wir aber für jede Region die entsprechenden Zeichensätze beachten, was ein ziemlich großer Testaufwand ist.
Allgemein wird das zwar meist korrekt sein, im Speziellen bei MySQL aber nicht unbedingt. Zumindest läuft MySQL selbst unter Debian Wheezy standardmäßig noch mit Server- und Datenbankkodierung latin1. Diese Konstallation ist sogar noch tückischer, denn durch die tatsächlich auf UTF-8 umgestellte Verbindungskodierung bemerkt man bei vielen im deutschsprachigen Raum genutzten Zeichen nicht, dass die Datenbank im Hintergrund noch mit latin1 arbeitet und MySQL die Anfragen und Antworten jeweils umkodiert, wenn man die tatsächlich gewünschte UTF-8-Kodierung beim Erstellen der Tabelle nicht explizit angegeben hat. Bei Zeichen außerhalb des latin1-Zeichenvorrats kommt es dann aber zu Datenverlust bzw. zumindest unerwarteten Reaktionen.