& (PHP) Feldwert: Resource id #2
Siechfred
- datenbank
Tag alle.
Ich habe folgendes (wahrscheinlich triviale) Problem mit mySQL:
Ich möchte in einer Tabelle einen URL speichern. Die Spalte hat folgende Attribute:
Name: url
Typ: VARCHAR(255)
Kollation: utf8_general_ci
Attribute: NOT NULL, kein Standardwert, keine Extras, Volltext
Versuche ich nun, 'http://www.example.org' zu speichern, enthält das Feld den Wert 'Resource id #2', ich möchte aber, dass wie in den anderen Feldern auch der URL im Klartext gespeichert wird. Das Einfügen geschieht mittels PHP, hier mal der relevante gekürzte Teil:
if(!isUTF8($_POST['link'])) {
$link = utf8_encode($_POST['link']);
}
else {
$link = $_POST['link'];
}
if(get_magic_quotes_gpc()) {
$link = addslashes($link);
}
$query = "INSERT INTO news SET url=_utf8'$link'";
Wie bekomme ich nun den URL in meine Datenbank? Oder steht er vielleicht sogar schon drin, ich weiß es nur nicht? Falls ja, wie greife ich dann auf diesen URL zu?
Es dankt im Voraus
Siechfred
Moin!
Ich möchte in einer Tabelle einen URL speichern. Die Spalte hat folgende Attribute:
Name: url
Typ: VARCHAR(255)
Kollation: utf8_general_ci
Attribute: NOT NULL, kein Standardwert, keine Extras, Volltext
Klingt alles normal - einzig die Feldlänge könnte dir mit 255 Zeichen eventuell zu kurz werden, URLs können durchaus auch länger sein. Das ist aber ein Detailproblem und kein grundsätzliches.
Versuche ich nun, 'http://www.example.org' zu speichern, enthält das Feld den Wert 'Resource id #2', ich möchte aber, dass wie in den anderen Feldern auch der URL im Klartext gespeichert wird.
Wie stellst du das fest? PhpMyAdmin?
Das Einfügen geschieht mittels PHP, hier mal der relevante gekürzte Teil:
Zuviel gekürzt, dein Code endet mit dem Erstellen des SQL-Statements, zeigt aber nicht, wie die Datenbank davon Kenntnis erhält.
> if(!isUTF8($_POST['link'])) {
> $link = utf8_encode($_POST['link']);
> }
> else {
> $link = $_POST['link'];
> }
// Das sieht irgendwie schrill aus. Weißt du nicht, ob du UTF-8 kriegst, dann solltest du das lieber exakt definieren - in deinem Formular. Alles andere ist ziemlich schwachsinnig. utf8_encode wandelt von ISO-8859-1 nach UTF-8 - was natürlich nur richtig funktioniert, wenn du wirklich ISO-8859-1 erhälst, ansonsten zerstört es dir so oder so den Textinhalt.
> if(get_magic_quotes_gpc()) {
> $link = addslashes($link);
> }
// Das ist nun mal komplett falsch. Wen magic_quotes_gpc gesetzt ist, willst du stripslashes() machen, um diesen Effekt wieder rückgängig zu machen. Und du willst das auch als allerallererstes machen, noch vor irgendeinem UTF-8-Gedöns.
> $query = "INSERT INTO news SET url=_utf8'$link'";
// Und hier fehlt noch mysql_escape_string() oder mysql_real_escape_string(), welches auf $link angewendet wird. DAS IST DAS WICHTIGSTE!
// Und wie erwähnt, fehlt der Code, um den SQL-String in die DB zu kriegen.
- Sven Rautenberg
Tag Sven.
Versuche ich nun, 'http://www.example.org' zu speichern, enthält das Feld den Wert 'Resource id #2', ich möchte aber, dass wie in den anderen Feldern auch der URL im Klartext gespeichert wird.
Wie stellst du das fest? PhpMyAdmin?
Nein, mittels einer SQL-Abfrage und anschließender Ausgabe des Ergebnisses mit Hilfe von mysql_fetch_assoc().
if(!isUTF8($_POST['link'])) {
$link = utf8_encode($_POST['link']);
}
else {
$link = $_POST['link'];
}
Das sieht irgendwie schrill aus. Weißt du nicht, ob du UTF-8 kriegst, dann solltest du das lieber exakt definieren - in deinem Formular.
Das habe ich getan. Die erste Zeile im PHP-Script lautet [code lang=PHP]<?php header("Content-type: text/html; charset=utf-8"); ?>
> Alles andere ist ziemlich schwachsinnig. utf8\_encode wandelt von ISO-8859-1 nach UTF-8 - was natürlich nur richtig funktioniert, wenn du wirklich ISO-8859-1 erhälst, ansonsten zerstört es dir so oder so den Textinhalt.
Hm, das Problem ist, wie ich den Zeichensatz herausbekomme. In <http://dev.mysql.com/tech-resources/articles/4.1/unicode.html> ist das nur für windows-1252 beschrieben, ich nahm fälschlicherweise an, dass utf8\_encode() die Umwandlung zu UTF-8 unabhängig vom Ausgangszeichensatz vornimmt.
> > if(get\_magic\_quotes\_gpc()) {
> > $link = addslashes($link);
> > }
> Das ist nun mal komplett falsch. Wen magic\_quotes\_gpc gesetzt ist, willst du stripslashes() machen, um diesen Effekt wieder rückgängig zu machen. Und du willst das auch als allerallererstes machen, noch vor irgendeinem UTF-8-Gedöns.
Okay, geändert.
> > $query = "INSERT INTO news SET url=\_utf8'$link'";
> Und hier fehlt noch mysql\_escape\_string() oder mysql\_real\_escape\_string(), welches auf $link angewendet wird. DAS IST DAS WICHTIGSTE!
Alles klar, ebenfalls geändert.
Aber du wirst es nicht glauben, ich habe es selber gefunden: ich habe einfach die Variable $link doppelt verwendet, einmal für den URL und einmal für mysql\_connect() - mannomann, wie blöd kann man eigentlich sein. Jedenfalls funktioniert es jetzt, wie es soll. Danke dir für deine kompetenten Hinweise.
Siechfred
PS: <flame>Mit Perl wäre das nicht passiert!</flame>
--
[Codeschnipsel gefällig?](http://sniplets.anaboe.net)
hi,
Das habe ich getan. Die erste Zeile im PHP-Script lautet
<?php header("Content-type: text/html; charset=utf-8"); ?>
. Zusätzlich habe ich noch<meta http-equiv="content-type" content="text/html; charset=UTF-8">
im Head stehen.
das erklärt immer noch nicht, was deine funktion isUTF8() prüft, und wie.
aber wenn du doch eh schon sicherstellst, dass du vom formular utf-8 bekommst (tipp: zusätzlich noch accept-charset im form angeben, gibt/gab browser, die ohne das die daten in der kodierung versenden, die ihnen passend erscheint) - wozu dann noch diese überprüfung? erwartest du daten auch aus anderen quellen, als aus deinem eigenem formular?
gruß,
wahsaga
Hallo wahsaga,
... - wozu dann noch diese überprüfung? erwartest du daten auch aus anderen quellen, als aus deinem eigenem formular?
vielleicht erwartet er sie nicht, befürchtet sie aber ;-)
Freundliche Grüße
Vinzenz
Tag wahsaga.
das erklärt immer noch nicht, was deine funktion isUTF8() prüft, und wie.
Geklaut von http://de.php.net/manual/de/function.utf8-encode.php#50796
aber wenn du doch eh schon sicherstellst, dass du vom formular utf-8 bekommst (tipp: zusätzlich noch accept-charset im form angeben, gibt/gab browser, die ohne das die daten in der kodierung versenden, die ihnen passend erscheint) - wozu dann noch diese überprüfung? erwartest du daten auch aus anderen quellen, als aus deinem eigenem formular?
Nicht aus anderen Quellen, aber evtl. von anderen Browsern, die mein Formular versenden könnten.
Siechfred
Moin!
if(!isUTF8($_POST['link'])) {
$link = utf8_encode($_POST['link']);
}
else {
$link = $_POST['link'];
}
Das sieht irgendwie schrill aus. Weißt du nicht, ob du UTF-8 kriegst, dann solltest du das lieber exakt definieren - in deinem Formular.Das habe ich getan. Die erste Zeile im PHP-Script lautet [code lang=PHP]<?php header("Content-type: text/html; charset=utf-8"); ?>
Man kann auch noch accept-charset als Attribut im <form> angeben. Alle drei Angaben zusammen sollten jeden noch so widerspenstigen Browser davon überzeugen, dass er sich tatsächlich mit UTF-8 beschäftigen sollte. :)
> > Alles andere ist ziemlich schwachsinnig. utf8\_encode wandelt von ISO-8859-1 nach UTF-8 - was natürlich nur richtig funktioniert, wenn du wirklich ISO-8859-1 erhälst, ansonsten zerstört es dir so oder so den Textinhalt.
>
> Hm, das Problem ist, wie ich den Zeichensatz herausbekomme. In [http://dev.mysql.com/tech-resources/articles/4.1/unicode.html](http://dev.mysql.com/tech-resources/articles/4.1/unicode.html) ist das nur für windows-1252 beschrieben, ich nahm fälschlicherweise an, dass utf8\_encode() die Umwandlung zu UTF-8 unabhängig vom Ausgangszeichensatz vornimmt.
Du kannst den Zeichensatz nicht herausbekommen, wenn der Browser dir nicht sagt, welchen Zeichensatz er verwendet.
Und leider sagen außer dem Opera-Browser die häufig verwendeten Browser IE und Mozilla/Firefox (andere nicht getestet) in ihrem POST-Request eben nur, dass die gesendeten Daten zu den Formularfeldern gehören, aber nicht, in welchem Zeichensatz sie gesendet wurden.
Es gibt also keine Möglichkeit, den benutzten Zeichensatz von hereinkommenden Formularen zu \_erkennen\_, bestenfalls kann man \_raten\_.
Eine etwas ausführlichere Diskussion zu dem Thema gibts im Bugtracker des Mozilla auf englisch: <https://bugzilla.mozilla.org/show_bug.cgi?id=228779>. Bemerkenswert: Die mangelhafte Behandlung des Formular-Encodings durch Mozilla wurde schon 2003 bemängelt, ist aber immer noch nicht abschließend erledigt.
Deshalb: Die einzige Möglichkeit, von Browsern egal welcher Bauart vernünftige Daten zu erhalten, ist die Verwendung von UTF-8 als \_einziger\_ Zeichencodierung (zumindest im Dokument, welches das Formular enthält - das dann in der Verarbeitung aber z.B. in ISO-8859-1 zu wandelt scheint mir absolut blödsinnig, weil man damit effektiv Zeichen verliert, die durchaus sinnvoll und häufiger sind, wie beispielsweise das Eurozeichen oder typographische Zeichen wie "deutsche Anführungszeichen" oder echte Binde- und Trennstriche anstelle des Minuszeichens).
Wenn du eine Funktion isUTF8() hast, dann sollte die einzig prüfen, ob die Bytefolge des Strings valides UTF-8 ist. Im Fehlerfall kannst du dann allerdings nichts weiter tun als die fehlerhaften Bytes bzw. Zeichen zu entfernen.
> PS: <flame>Mit Perl wäre das nicht passiert!</flame>
Aber sicher doch! ;)
- Sven Rautenberg
--
My sssignature, my preciousssss!
Tag Sven.
Man kann auch noch accept-charset als Attribut im <form> angeben. Alle drei Angaben zusammen sollten jeden noch so widerspenstigen Browser davon überzeugen, dass er sich tatsächlich mit UTF-8 beschäftigen sollte. :)
So sei es, habe ich noch ergänzt.
Du kannst den Zeichensatz nicht herausbekommen, wenn der Browser dir nicht sagt, welchen Zeichensatz er verwendet.
Ich fand die Idee mit dem versteckten Eingabefeld gar nicht so schlecht. Wenn ich allerdings mit der header()-Funktion, der META-Angabe und accept-charset die meisten Browser "kriegen" kann, dann ist wohl die Funktion in der Tat überflüssig.
Es gibt also keine Möglichkeit, den benutzten Zeichensatz von hereinkommenden Formularen zu _erkennen_, bestenfalls kann man _raten_.
Eben das versuchte ich anhand des versteckten Eingabefeldes, muss aber zugeben, dass meine PHP-Kenntnisse nicht so fortgeschritten sind, dass ich en detail verstehe, was die Funktion macht (den Link hatte ich in meiner Antwort an wahsaga gepostet).
PS: <flame>Mit Perl wäre das nicht passiert!</flame>
Aber sicher doch! ;)
Naja, klingt wie eine Ausrede, aber mit Perl ist mir so ein dummer Fehler noch nie unterlaufen. Ist schon doof, wenn der Provider für virtuelle Hosts keine Perlscripte erlaubt, da muss man sich doch tatsächlich mit PHP rumärgern, obwohl man die Lösung in Perl schon hat *grmpf*
Siechfred
Hallo,
Du kannst den Zeichensatz nicht herausbekommen, wenn der Browser dir nicht sagt, welchen Zeichensatz er verwendet.
Und leider sagen außer dem Opera-Browser die häufig verwendeten Browser IE und Mozilla/Firefox (andere nicht getestet) in ihrem POST-Request eben nur, dass die gesendeten Daten zu den Formularfeldern gehören, aber nicht, in welchem Zeichensatz sie gesendet wurden.
Naja, <input type="hidden" name="_charset_"> füllen Firefox und MSIE mit der benutzten Zeichenkodierung aus.
Was Firefox natürlich nicht daran hindert, die Zusatzzeichen von Windows 1252 gegenüber ISO 8859-1 Windows-1252-kodiert zu senden (Eurosymbol, typographische Anführungszeichen, Bindestriche usw.) und es gleichzeitig als ISO-8859-1 zu bezeichnen. MSIE hält sich zwar auch nicht an accept-charset="ISO-8859-1", aber schreibt zumindest Windows-1252 in _charset_.
Übrigens sendet mein Opera 8.02 / Linux kein charset-Parameter mehr im Content-Type-Header beim POST,
Eine etwas ausführlichere Diskussion zu dem Thema gibts im Bugtracker des Mozilla auf englisch: https://bugzilla.mozilla.org/show_bug.cgi?id=228779. Bemerkenswert: Die mangelhafte Behandlung des Formular-Encodings durch Mozilla wurde schon 2003 bemängelt, ist aber immer noch nicht abschließend erledigt.
Nö, das ist nicht bemerkenswert.
Solchen Umgang mit Bugs kennt man zu gut.
Aufgrund solcher Schnitzer ist das Firefox-Team bei mir unten durch, was das Melden von Fehlern angeht. Auf Granit beißen kann ich auch anderswo.
Mathias
Tag alle.
Das Problem von gestern ist gelöst. Da ich in Sachen PHP+mySQL+UTF-8 ein ziemlicher Anfänger bin, bitte ich euch, mal über den Code zu schauen, ob das so in Ordnung ist oder ob es hier Verbesserungen oder noch Fehler gibt:
$headline = htmlentities(trim($_POST['headline']), ENT_COMPAT, 'utf-8');
$quelle = htmlentities(trim($_POST['quelle']), ENT_COMPAT, 'utf-8');
$url = htmlentities(trim($_POST['link']), ENT_COMPAT, 'utf-8');
$nachricht = nl2br(htmlentities(trim($_POST['nachricht']), ENT_COMPAT, 'utf-8'));
if(!get_magic_quotes_gpc()) {
$headline = addslashes($headline);
$quelle = addslashes($quelle);
$url = addslashes($url);
$nachricht = addslashes($nachricht);
}
mysql_escape_string($headline);
mysql_escape_string($quelle);
mysql_escape_string($url);
mysql_escape_string($nachricht);
$query = "INSERT INTO tabelle SET feld1=_utf8'$headline',feld2=_utf8'$quelle',feld3=_utf8'$url',feld4=_utf8'$nachricht'";
Und schließlich noch die Frage:
Oben stehender Code speichert die Texte einschließlich HTML-Entities. Ist das sinnvoll oder sollte ich das lassen und htmlentities() erst bei Ausgabe der Ergebnisse eines SELECT-Statements ausführen?
Siechfred
Moin!
> $headline = htmlentities(trim($_POST['headline']), ENT_COMPAT, 'utf-8');
> $quelle = htmlentities(trim($_POST['quelle']), ENT_COMPAT, 'utf-8');
> $url = htmlentities(trim($_POST['link']), ENT_COMPAT, 'utf-8');
> $nachricht = nl2br(htmlentities(trim($_POST['nachricht']), ENT_COMPAT, 'utf-8'));
> if(!get_magic_quotes_gpc()) {
> $headline = addslashes($headline);
> $quelle = addslashes($quelle);
> $url = addslashes($url);
> $nachricht = addslashes($nachricht);
> }
// Falsch verstanden! Wenn magic_quotes_gpc gesetzt ist, mußt du stripslashes() anwenden. Wenn es nicht gesetzt ist, mußt du nichts anwenden. Und generell mußt du stripslashes als allererstes auf die POST-Daten anwenden, noch bevor du irgendwas mit trim, htmlentities etc. machst.
> mysql_escape_string($headline);
> mysql_escape_string($quelle);
> mysql_escape_string($url);
> mysql_escape_string($nachricht);
> $query = "INSERT INTO tabelle SET feld1=_utf8'$headline',feld2=_utf8'$quelle',feld3=_utf8'$url',feld4=_utf8'$nachricht'";
Oben stehender Code speichert die Texte einschließlich HTML-Entities. Ist das sinnvoll oder sollte ich das lassen und htmlentities() erst bei Ausgabe der Ergebnisse eines SELECT-Statements ausführen?
Das solltest du lassen. Der Speichervorgang sollte möglichst nur die reinen Daten speichern, ohne schon auf eine spezielle Ausgabeart Rücksicht zu nehmen. Entities sind eine spezielle Ausrichtung auf HTML - dahin zu wandeln sollte erst bei der Ausgabe in das HTML-Format passieren.
Dasselbe gilt für nl2br, das darf auch erst bei der Ausgabe angewendet werden.
- Sven Rautenberg
Tag Sven.
if(!get_magic_quotes_gpc()) {
[...]
Falsch verstanden! Wenn magic_quotes_gpc gesetzt ist, mußt du stripslashes() anwenden. Wenn es nicht gesetzt ist, mußt du nichts anwenden.
Aha, danke.
Der Speichervorgang sollte möglichst nur die reinen Daten speichern, ohne schon auf eine spezielle Ausgabeart Rücksicht zu nehmen. Entities sind eine spezielle Ausrichtung auf HTML - dahin zu wandeln sollte erst bei der Ausgabe in das HTML-Format passieren.
Dasselbe gilt für nl2br, das darf auch erst bei der Ausgabe angewendet werden.
Auch hier danke (ich hatte es mir fast gedacht, wollte aber sicher gehen).
Siechfred
Hello,
// Falsch verstanden! Wenn magic_quotes_gpc gesetzt ist, mußt du stripslashes() anwenden. Wenn es nicht gesetzt ist, mußt du nichts anwenden. Und generell mußt du stripslashes als allererstes auf die POST-Daten anwenden, noch bevor du irgendwas mit trim, htmlentities etc. machst.
Und mach es auch gleich rekursiv, dann klappts auch mit den Arrays...
siehe "strip(" im Archiv als Beispiel für die Funktion
http://forum.de.selfhtml.org/archiv/2004/1/t68384/#m392313
Harzliche Grüße vom Berg
esst mehr http://www.harte-harzer.de
Tom
echo $begrüßung;
[...] mal über den Code zu schauen, ob das so in Ordnung ist oder ob es hier Verbesserungen oder noch Fehler gibt:
Versuche doch mal, ob du die Magic Quotes in der Konfiguration ausschalten kannst. Wenn nicht, dann nimm am besten den Code aus dem Beispiel und schreib den an den Anfang deines Scripts. Damit werden die überflüssigen Backslashes erst einmal generell eliminiert. (Der Code kann eigentlich immer drin bleiben, dann klappts auch mit doofen Providern.)
$headline = htmlentities(trim($_POST['headline']), ENT_COMPAT, 'utf-8');
Bist du sicher, dass du HTML-Entities statt der UTF8-Zeichen in die Datenbank eintragen willst?
if(!get_magic_quotes_gpc()) {
Die Auswirkungen der M.Q. hast du ja oben schon beseitigt.
$headline = addslashes($headline);
addslashes() maskiert nur einige wenige Zeichen. Für MySQL ist mysql_real_escape_string() am besten geeignet, weil das auch den Zeichensatz der Verbindung berücksichtigt.
Wenn du generell in UTF-8 mit MySQL sprechen möchtest, kannst du das nach Öffnen der Verbindung einstellen mit:
SET NAMES utf8;
SET CHARACTER_SET utf8;
Somit kann auch das "real" in mysql_real_escape_string() richtig arbeiten.
mysql_escape_string($headline);
Das bringt so nichts, du musst das Rückgabeergebnis verwenden, also $headline = mysql_real_escape_string($headline); etc.
$query = "INSERT INTO tabelle SET feld1=_utf8'$headline',feld2=_utf8'$quelle',feld3=_utf8'$url',feld4=_utf8'$nachricht'";
Mit der obigen Einstellung kannst du nun das _utf8 weglassen.
Ich würde mich hier der Funktion sprintf bedienen, und auch gleich das Escaping mit unterbringen, weil mir das übersichtlicher aussieht und die Variablen für eine spätere Weiterverarbeitung nicht verändert werden. Aber das ist Geschmackssache... [*]
$query = sprintf("INSERT INTO tabelle SET feld1='%s',feld2='%s',feld3='%s',feld4='%s'",
mysql_escape_string($headline),
mysql_escape_string($quelle),
mysql_escape_string($url),
mysql_escape_string($nachricht));
Oben stehender Code speichert die Texte einschließlich HTML-Entities. Ist das sinnvoll
Nein, Rohdaten in der DB sind besser, weil die DB sie dann auch richtig berücksichtigen kann (suchen, sortieren, etc.).
oder sollte ich das lassen und htmlentities() erst bei Ausgabe der Ergebnisse eines SELECT-Statements ausführen?
Ja. Die aus der DB kommenden Rohdaten sind gemäß dem Ausgabemedium zu maskieren. htmlspecialchars() reicht für HTML aus, die UTF8-Zeichen werden ja schon berücksichtigt, wenn du HTTP-Header und/oder META-Angabe richtig einstellst.
echo "$verabschiedung $name";
[*] In meinen Projekten verwende ich PEAR_DB, das kümmert sich auch um die korrekte Maskierung und Quotierung.
$query = 'INSERT INTO tabelle SET feld1=?,feld2=?,feld3=?,feld4=?';
$result =& $db->query($query, array($headline, $quelle, $url, $nachricht));
Tag dedlfix.
$headline = htmlentities(trim($_POST['headline']), ENT_COMPAT, 'utf-8');
Bist du sicher, dass du HTML-Entities statt der UTF8-Zeichen in die Datenbank eintragen willst?
Das war ja meine Frage, hat sich aber glaube ich schon erledigt :-)
Wenn du generell in UTF-8 mit MySQL sprechen möchtest, kannst du das nach Öffnen der Verbindung einstellen mit:
SET NAMES utf8;
SET CHARACTER_SET utf8;
Auszuführen wie die anderen Statements auch, nehme ich an.
Das bringt so nichts, du musst das Rückgabeergebnis verwenden, also $headline = mysql_real_escape_string($headline); etc.
Öhm, tja, da liegt wohl offensichtlich ein Denkfehler meinerseits vor :-)
Ich würde mich hier der Funktion sprintf bedienen, und auch gleich das Escaping mit unterbringen, weil mir das übersichtlicher aussieht und die Variablen für eine spätere Weiterverarbeitung nicht verändert werden. Aber das ist Geschmackssache... [*]
Danke für den Hinweis.
Nein, Rohdaten in der DB sind besser, weil die DB sie dann auch richtig berücksichtigen kann (suchen, sortieren, etc.).
Da es mir u.a. auch darum geht, werde ich das mal besser so machen.
Siechfred
So, habe jetzt die mir gegebenen Hinweise berücksichtigt. Allerdings bekomme ich beim Ausführen von "SET CHARACTER_SET utf8" die Fehlermeldung, dass diese Systemvariable unbekannt sei, mit "SET NAMES utf8" funktioniert es. Scheint aber kein Problem zu sein, da die Daten in der Tat als UTF-8 in der DB gespeichert werden.
Danke jedenfalls an alle Helfer.
Siechfred