Webentwicklung auf UTF-8
simon margulies
- zur info
Problem:
Umlaute werden auf HTML Seiten nicht richtig dargestellt nach Eingabe in ein Formular.
Technologie:
Seite des Clients HTTP und xmlhttprequest(Ajax), Serverseitig: PHP und eine mySql-DB.
Ziel:
korrekte Darstellung von Zeichen in utf-8 encoding (insbes. Umlauten usw) auf html Seiten, die über PHP oder xmlhttprequest geladen werden.
Lösung:
ich habe ziemlich geschwitzt an dem ganzen - besonders weil ich nirgendwo eine verständliche Doku zu diesem Problem gefunden habe. Ich hoffe, anderen mit diesem Post behilflich sein zu können:
PHP unterstützt Unicode leider nur mit den Funktionen utf8_encode() und utf8_decode() - dennoch ist das Ziel ohne zusätzliche Libraries erreichbar. html-seiten mit dem header tag:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
versehen.
Zur Sicherheit, besonders für das Laden durch einen xmlhttprequest (Safari hat utf-8 nicht als default) von php generierten Antworten vom Server vor jeglichem Output (sofern es sich nicht um xml sondern um html handelt):
<?php header("Content-type:text/html; charset=utf-8"); ?>
ausgeben.
Formulare können wie folgt definiert werden:
<form name="form1" id="form1" method="post" action="post-end.php" enctype="application/x-www-form-urlencoded" accept-charset="utf-8">
oder
<form name="form1" id="form1" method="post" action="post-end.php" enctype="multipart/form-data" accept-charset="utf-8">
Die 2. Möglichkeit wird benötigt, falls files mit dem Formular mitgeschickt werden. Die Attribute enctype und accept-charset haben aber bei praktisch keinem Browser einen Einfluss: das encoding wird vom weiter oben festgelegten header bestimmt.
Wird nun ein solches Formular via HTTP verschickt, so erreicht es den Webserver und damit PHP in der x-www-form-urlencoded Form. Um nun die mitgeschickten Werte in der mySql-DB zu speicher müssen diese decodiert werden:
<?php
$str = utf8_decode($_POST['formularfeld1']);
$sql = "UPDATE mytable SET myfield='{$str}' WHERE ...";
?>
Die 'Collation' der felder in der mytable auf der mySQL-DB sollte auf 'utf8_unicode_ci' gesetzt sein. Siehe phpMyAdmin.
Beim Auslesen der Werte aus der DB und ihrer Darstellung über PHP auf einem Webbrowser, sind erst die oben genannten header-infos zu schicken und dann der Wert der aus der DB zu enkodieren:
<?php header("Content-type:text/html; charset=utf-8"); ?>
...
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
...
<?php
echo utf8_encode($res['myfield']);//$res hat die ergebnisse der Datenbankabfrage gespeichert.
?>
und schon hat man eine funktionierende utf-8 Umgebung.
Sollen die Formular-Werte über xmlhttprequest an den Server verschickt werden, können sie der xmlhttprequest.send() als String-parameter übergeben werden:
Kommentare sind direkt in den Code geschrieben.
Formularbutton irgendwo zwischen <form></form>:
<input type="button" name="Submit" value="Bestellen" onClick="ajax.formstart('zielskript.php', myCallback, this.form);">
JavaScript:
<script type="text/javascript">
<!--
var ajax;
ajax = new JSLRequest();
function myCallback (req) {//wird ausgeloest, wenn xmlhttprequest seine antwort gekriegt hat: antwort des php-skriptes auf dem server.
if(document.getElementById){
var ele = document.getElementById('zielort');//<span id="zielort"></span> im html-body.
ele.innerHTML = req.responseText;
}
}
function JSLRequest () {//klasse mit dem xmlhttprequest objekt
var reqobj;//xmlhttprequest objekt
var callback;
this.handler = function () {
if (reqobj.readyState == 4) {
if (reqobj.status == 200) {
callback(reqobj);
}
else {
callback(reqobj);
}
}
}
this.formstart = function(hostfunc, callback_func, form){//wird vom button im form ausgeloest
try{
reqobj = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(Error){
try{
reqobj = new ActiveXObject("MSXML2.XMLHTTP");
}
catch(Error){
try{
reqobj = new XMLHttpRequest();
}
catch(Error){
//hier auf die alternative verweisen
}
}
}
var str = getFormValues(form);//str wird saemtliche form-werte beinhalten in der form var1=wert1&var2=wert2&var3=wert3 ...
//form ist das dom-form objekt in welchem sich der form-button ausgelöst wurde.
callback = callback_func;
reqobj.onreadystatechange = this.handler;
reqobj.open ("POST", hostfunc, true);
reqobj.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");//sonst wird str nicht zum server geschickt.
reqobj.send (str);
}
getFormValues = function(fobj){//diese funktion setzt die variablen und werte aus dem form zusammen
var str = "";
var valueArr = null;
var val = "";
var cmd = "";
for(var i = 0;i < fobj.elements.length;i++){
switch(fobj.elements[i].type){//cases nicht vollständig, es kann noch andere form-element geben als die unten abefangenen, hier nur z Bsp:
case "hidden":
str += fobj.elements[i].name + "=" + escape(fobj.elements[i].value) + "&";
break;
case "text":
str += fobj.elements[i].name + "=" + escape(fobj.elements[i].value) + "&";
break;
case "select-one":
str += fobj.elements[i].name + "=" + fobj.elements[i].options[fobj.elements[i].selectedIndex].value + "&";
break;
}
}
str = str.substr(0,(str.length - 1));
return encodeURI(str);//encodeURI damit auf der php-seite utf8_decode angewandt werden kann:
//mitencodeURIComponent sind bei mir dann keine Werte gesendet worden... ???
}
}
</script>
hi,
klingt irgendwie ein bisschen verworren und unausgereift ...
PHP unterstützt Unicode leider nur mit den Funktionen utf8_encode() und utf8_decode()
Was soll das bedeuten?
PHP hat zwar bisher keine native Unicode-Unterstützung - aber Erweiterungen wie die mbstring-Funktionen oder iconv existieren trotzdem.
Zur Sicherheit, besonders für das Laden durch einen xmlhttprequest (Safari hat utf-8 nicht als default) von php generierten Antworten vom Server vor jeglichem Output (sofern es sich nicht um xml sondern um html handelt):
<?php header("Content-type:text/html; charset=utf-8"); ?>
ausgeben.
Das sollte doch wohl sowieso selbstverständlich sein.
Formulare können wie folgt definiert werden:
<form name="form1" id="form1" method="post" action="post-end.php" enctype="application/x-www-form-urlencoded" accept-charset="utf-8">
oder
<form name="form1" id="form1" method="post" action="post-end.php" enctype="multipart/form-data" accept-charset="utf-8">
Die 2. Möglichkeit wird benötigt, falls files mit dem Formular mitgeschickt werden.
Die erste dürfte hingegen kontraproduktiv sein, da nicht alle Browser enctype="application/x-www-form-urlencoded" korrekt umsetzen. Da also lieber auf die enctype-Angabe verzichten.
Wird nun ein solches Formular via HTTP verschickt, so erreicht es den Webserver und damit PHP in der x-www-form-urlencoded Form. Um nun die mitgeschickten Werte in der mySql-DB zu speicher müssen diese decodiert werden:
Wieso das denn?
<?php
$str = utf8_decode($_POST['formularfeld1']);
$sql = "UPDATE mytable SET myfield='{$str}' WHERE ...";
?>Die 'Collation' der felder in der mytable auf der mySQL-DB sollte auf 'utf8_unicode_ci' gesetzt sein. Siehe phpMyAdmin.
Wenn deine MySQL-DB schon UTF-8 verarbeiten und entgegennehmen mag - wieso bitte willst du dann die UTF-8-Daten vorher "dekodieren"?
Beim Auslesen der Werte aus der DB und ihrer Darstellung über PHP auf einem Webbrowser, sind erst die oben genannten header-infos zu schicken und dann der Wert der aus der DB zu enkodieren:
[...]
echo utf8_encode($res['myfield']);//$res hat die ergebnisse der Datenbankabfrage gespeichert.
Auch wieder unnötig kompliziert.
Dekodieren zum Eintragen in die DB, und wieder kodieren bei der Ausgabe? Das ist doch Humbug.
und schon hat man eine funktionierende utf-8 Umgebung.
Hättest du auch einfacher haben können.
Sollen die Formular-Werte über xmlhttprequest an den Server verschickt werden, können sie der xmlhttprequest.send() als String-parameter übergeben werden:
[...]
return encodeURI(str);//encodeURI damit auf der php-seite utf8_decode angewandt werden kann:
Den Kommentar halte ich auch wieder für unsinnig.
Dass Daten vor der Übertragung URL-gerecht kodiert werden, ist das normalste von der Welt - und dass sie dir in PHP bereits "dekodiert" zur Verfügung stehen, sofern du nicht explizit für Gegenteiliges sorgst, auch.
Wofür du also ständig Daten aus UTF-8 heraus "dekodieren" willst, wenn du doch eigentlich deine Datenhaltung in UTF-8 haben willst, erschließt sich mir nicht.
gruß,
wahsaga
klingt irgendwie ein bisschen verworren und unausgereift ...
wie du meinst.
http://www.php.net/manual/de/language.types.string.php
zur unterstützung von unicode in php. mein bsp ist explizit dazu gedacht, dass utf-8 auch ohne erweiterung funktioniert.
utf8_decode() brauchts damit die unicode-infos durch php (http://www.php.net/manual/de/language.types.string.php) beim übertrag in die db bestehen bleiben.
Das sollte doch wohl sowieso selbstverständlich sein.
vielleicht geht das ja nicht allen so?
Wenn deine MySQL-DB schon UTF-8 verarbeiten und entgegennehmen mag - wieso bitte willst du dann die UTF-8-Daten vorher "dekodieren"?
dazwischen ist liegt noch php... somit kann man nicht direkt in die mySql einspeisen..
Dekodieren zum Eintragen in die DB, und wieder kodieren bei der Ausgabe? Das ist doch Humbug.
wie du meinst.
ich rate dir mal zu überprüfen, was deine php-skripts tatsächlich in der db speichern: nur weil man die collation auf utf-8 einstellt, heisst das noch lange nicht, das auch welches drin ist.
hi,
utf8_decode() brauchts damit die unicode-infos durch php (http://www.php.net/manual/de/language.types.string.php) beim übertrag in die db bestehen bleiben.
Nö, brauche ich nicht.
Wenn deine MySQL-DB schon UTF-8 verarbeiten und entgegennehmen mag - wieso bitte willst du dann die UTF-8-Daten vorher "dekodieren"?
dazwischen ist liegt noch php... somit kann man nicht direkt in die mySql einspeisen..
Komisch, ich kann.
Dekodieren zum Eintragen in die DB, und wieder kodieren bei der Ausgabe? Das ist doch Humbug.
wie du meinst.
ich rate dir mal zu überprüfen, was deine php-skripts tatsächlich in der db speichern: nur weil man die collation auf utf-8 einstellt, heisst das noch lange nicht, das auch welches drin ist.
Fein erkannt - eine Collation bezieht sich im großen und ganzen darauf, wie Sortierungen und Vergleiche vorgenommen werden.
gruß,
wahsaga
Hi,
Die erste dürfte hingegen kontraproduktiv sein, da nicht alle Browser enctype="application/x-www-form-urlencoded" korrekt umsetzen. Da also lieber auf die enctype-Angabe verzichten.
So daß der default-Wert für enctype greift? Der ist "application/x-www-form-urlencoded" ...
Ach ja, welche Browser haben denn Probleme damit?
cu,
Andreas
echo $begrüßung;
Erst einmal ist es sehr löblich, dass du dir die Mühe gemacht hast, den Artikel zu verfassen. Jedoch ist er, was die Datenbankgeschichte angeht verbesserungswürdig.
Wird nun ein solches Formular via HTTP verschickt, so erreicht es den Webserver und damit PHP in der x-www-form-urlencoded Form. Um nun die mitgeschickten Werte in der mySql-DB zu speicher müssen diese decodiert werden:
Das ist weder generell nötig, noch ist es prinzipiell sinnvoll. Sinn des Verwendens von UTF-8 ist ja hauptsächlich, dass du mehr Zeichen verarbeiten kannst, als mit ISO-8859-x dargestellet werden können. Wenn du jetzt also wieder von 1.048.576 möglichen Zeichen auf 256 "decodierst" ("umwandeln"/"umkodieren" wären bessere Wörter, da sowohl Ausgangsdaten als auch Ergebnis kodierte Daten sind), schränkst du die Zahl der verwendbaren Zeichen massiv ein.
Die 'Collation' der felder in der mytable auf der mySQL-DB sollte auf 'utf8_unicode_ci' gesetzt sein. Siehe phpMyAdmin.
"Collation" steht eigentlich nur für einen Wert, der für die Sortierung zuständig ist. phpMyadmin ist hier etwas ungenau, da es den Charset-Anteil (hier: 'utf8') unterschlägt. Der Collation-Anteil ist auch für das Kodierungsproblem weniger relevant. Das nur am Rande.
Wichtiger ist, dass es noch mehr Einstellmöglichkeiten für Zeichensätze gibt. Neben der Default-Einstellung des Servers (character-set-server) sind vor allem die Werte der Verbindung maßgebend (character_set_client, character_set_connection und character_set_results). Vermutlich stehen diese bei dir auf latin1, weil vielleicht der Server-Default-Wert ebenso eingestellt ist. Das machen die Provider gern wegen der "Rückwärtskompatibilität". In dem Fall, oder besser in jedem Fall, sollte man den Zeichensatz der Verbindung explizit einstellen, damit es keine Unklarheiten und Differenzen zwischen Server und Client gibt. Die Folge wäre Umbrauchbarkeit wegen Datenmüll. Hat man erst einmal Müll, lässt sich daraus der Ausgangswert nicht wieder oder zumindst nicht einfach wieder herstellen. Der gewünschte Zeichensatz lässt sich mit einem SET NAMES ... direkt nach dem Connect einstellen.
Man muss auch noch erwähnen, dass erst seit MySQL 4.1 die Sache mit den Zeichensätzen gilt. Vorher waren die Möglichkeiten MySQLs eingeschränkt. UTF-8 wurde nicht unterstützt (bei Stringoperationen wie Sortieren, Vergleichen etc. ist eine Unterstüzung des Zeichensatzes notwendig), man konnte aber UTF-8-kodierte Daten ablegen und abfragen - mehr aber auch nicht (jedenfalls nicht sinnvoll).
und schon hat man eine funktionierende utf-8 Umgebung.
Nun, in deinem Fall hat man dann eine nicht immer funktionierende ISO-8859-1-Umgebung im UTF-8-Gewand. Nicht immer, weil es bei deiner Methode zu Datenverlust kommt, wenn die Client-Kommunikationswerte des Servers per default auf UTF-8 eingestellt sind und du ihm "dekodierte" ISO-8859-1-Daten sendest.
echo "$verabschiedung $name";
Moin!
Ziel:
korrekte Darstellung von Zeichen in utf-8 encoding (insbes. Umlauten usw) auf html Seiten, die über PHP oder xmlhttprequest geladen werden.Lösung:
Alles, was du bezüglich HTML schreibst, ist korrekt. Es ist, um sicher zu gehen (manche Browser machen sonst möglicherweise Mist), für die Formularverarbeitung an den drei Stellen (HTTP-Header, Metatag, accept-encoding-Attribut) die Angabe "utf-8" notwendig.
Aber in dem entscheidenden Punkt irrst du: Die Verarbeitung von UTF-8 mit PHP und Datenbank erfordert KEINESFALLS (!!!) die Verwendung von utf8_decode() oder utf8_encode()!
Wird nun ein solches Formular via HTTP verschickt, so erreicht es den Webserver und damit PHP in der x-www-form-urlencoded Form. Um nun die mitgeschickten Werte in der mySql-DB zu speicher müssen diese decodiert werden:
<?php
$str = utf8_decode($_POST['formularfeld1']);
$sql = "UPDATE mytable SET myfield='{$str}' WHERE ...";
?>
Mit utf8_decode() wandelst du den UTF-8-codierten String in einen ISO-8859-1-String.
Dabei gehen dir unwiderruflich Zeichen verloren. Darunter so wichtige Zeichen wie das Eurozeichen, welches in ISO-8859-1 nicht definiert ist.
Dann wandert der String in eine UTF-8-fähige Datenbank.
Und wird wieder ausgelesen und mit utf8_encode() wieder von ISO-8859-1 in UTF-8 gewandelt (verlorene Zeichen werden NICHT wiederhergestellt).
Offensichtlich hat die Verbindung zur Datenbank bei dir keine Ahnung davon, dass UTF-8 gesendet und gelesen werden soll, sondern benutzt ISO-8859-1.
Und das kriegt man ganz simpel geändert, indem man als allerersten SQL-Befehl folgendes macht:
<?php mysql_query("SET NAMES UTF-8"); ?>
Damit wird MySQL mitgeteilt, dass alle Querystrings, die die Datenbank erhält, im UTF-8-Schema codiert sind, und das alle Ergebnisse in dieser Codierung zurüchgegeben werden sollen.
Und schon erspart man sich die Zeichenverluste durch die sinnlose Konvertierung in ISO-8859-1.
Sorry, dass ich es so deutlich formuliere, aber dein Posting ist leider absolut nicht fachlich hilfreich, weil deine Lösung erhebliche Mängel aufweist und das Problem nicht grundsätzlich löst. Du arbeitest eben gerade NICHT in einer UTF-8-Umgebung, sondern schränkst diese auf Zeichen ein, die in ISO-8859-1 vorkommen. Und das sind verdammt wenige.
Datenbankenversionen, die UTF-8 noch nicht kennen, arbeiten auch ohne den zusätzlichen SQL-Befehl korrekt, da UTF-8 in 8-Bit-Systemen transparent verarbeitet werden kann.
- Sven Rautenberg
Moin!
Und das kriegt man ganz simpel geändert, indem man als allerersten SQL-Befehl folgendes macht:
<?php mysql_query("SET NAMES UTF-8"); ?>
Im MySQL-Handbuch nachlesen kann man das übrigens hier:
<http://dev.mysql.com/doc/refman/5.1/de/charset-connection.html>
- Sven Rautenberg
--
"Love your nation - respect the others."
habe d'ehre Sven
Sorry, dass ich es so deutlich formuliere, aber dein Posting ist leider absolut nicht fachlich hilfreich, weil deine Lösung erhebliche Mängel aufweist und das Problem nicht grundsätzlich löst.
Das ist nun ein schoenes Beispiel fuer die Crux, dass der Zaehler fuer "nicht hilfreich" unterdrueckt wird.
Nehmen wir mal - rein hypothetisch - KleinWilhelm gruebelt ueber ein aehnliches Problem, sieht die "2 x fachlich hilfreich", kopiert - faul wie er ist - den ganzen Codesums in seinen Editor und probiert rum. Die anderen Beitraege list er erst mal gar nicht.
Nun stellt er fest, hoppla irgenwas ist schraeg. Da koennen natuerlich schon ein paar Stunden rumfummeln vorbei sein, also tappelt er wieder ins Forum und faengt an zu lesen, stoesst auf Dein fundiertes Posting und kann u.U. die richtigen Schluesse daraus ziehen. Waere jetzt "1 x nicht hilfreich" erschienen, haette er wahrscheinlich gleich gelesen. Waere ja auch eigentlich vernuenftig, aber wie eingangs gesagt: KleinWilhelm ist ein fauler Hund. :-)
man liest sich
Wil*pro nicht hilfreich*helm
Hallo.
also tappelt er wieder ins Forum und faengt an zu lesen
[...]
KleinWilhelm ist ein fauler Hund. :-)
Faule Hunde lesen nicht, sondern fragen in einem Doppelposting nach.
MfG, at
habe d'ehre at
also tappelt er wieder ins Forum und faengt an zu lesen
KleinWilhelm ist ein fauler Hund. :-)
Faule Hunde lesen nicht, sondern fragen in einem Doppelposting nach.
KleinWilhelm will die Doppelpostingpolizisten nicht fuettern.
man liest sich
Wilhelm
Hallo.
KleinWilhelm will die Doppelpostingpolizisten nicht fuettern.
Dabei sind die doch so zahm. Die fressen dir sicher aus der Hand.
MfG, at