Zeichenkodierung zwischen PHP und MySQL
Pierre
- datenbank
0 Teufelchen0 dedlfix0 Pierre
Hallo,
ich habe ein merkwürdiges Problem mit Zeichenkodierungen beim Speichern eines Strings in MySQL mit PHPs PDO.
Ich verwende PHP 5.2.0 und MySQL 5.0.51a
Ich mache folgenden Insert mittels PDO:
insert into table (text) values ('1:0 Ä')
Als Ergebnis steht dann in der Datenbank "1? Ä". Wenn ich das mit irgendeinem anderen Zeichen als "Ä" mache, steht korrekt "1:0" in der Datenbank, aber bei Ä nicht. Die Daten sollten in UTF-8 vorliegen.
Wenn ich die gleiche insert-Anweisung übrigens per CocoaMySQL (bin auf 'nem Mac) ausführe, dann steht das korrekte Ergebnis in der Datenbank.
Also ist das wahrscheinlich ein Zeichensatzproblem, oder? Ich bin damit leider nicht so bewandert. Aber nach dem Connecten und vor dem Insert setze ich die folgenden Anweisung an die Datenbank ab:
"SET NAMES utf8"
"SET CHARACTER SET utf8"
Also sollte die Kommunikation zwischen Script und Server eigentlich laufen dachte ich.
Meine Zeichensatzdefinitionen sind:
character_set_client utf8
character_set_connection utf8
character_set_database latin1
character_set_filesystem binary
character_set_results utf8
character_set_server latin1
character_set_system utf8
collation_connection utf8_general_ci
collation_database latin1_swedish_ci
collation_server latin1_swedish_ci
Das Problem, dass ":zahl", also z.B. ":3", zu einem Fragezeichen konvertiert wird, tritt auch auf, wenn ich einen HTML-Link im String habe:
<a href="http://www.seite.de/index.php?var1=irgendwas&var2=irgendwas" target="blank">irgendwohin</a>
Was vielleicht noch wichtig ist in Verbindung mit dem Link: Der String ist mit magic_quotes escaped. Ich habe versucht mysql_real_escape_string() zu verwenden, aber da erhalte ich einen leere String zurück.
Wenn ich mit PHPs stripslashes()-Funktion alle Slashes entferne, tritt das Problem übrigens nicht mehr auf, aber das ist natürlich alles andere als sicher um es in einer SQL-Anweisung zu verwenden.
Noch eine Kleinigkeit: Wenn ich einen Text mit mehreren Absätzen (zwei Zeilenumbrüche gelten für mich jetzt mal als neuer Absatz) habe, tritt das Problem "1:0" -> "1?" IMMER NUR im ersten Absatz auf.
Ich wäre froh, wenn mir jemand helfen könnte, ich weiß nämlich nicht mehr so recht weiter.
Danke und beste Grüße,
Hadubard
Ich mache folgenden Insert mittels PDO:
insert into table (text) values ('1:0 Ä')Als Ergebnis steht dann in der Datenbank "1? Ä". Wenn ich das mit irgendeinem anderen Zeichen als "Ä" mache, steht korrekt "1:0" in der Datenbank, aber bei Ä nicht.
Woran erkennst du, was in der Datenbank steht? Über mysql (Befehlszeile), über ein Hilfsprogramm wie phpMySQL oder fragst du selbst per PHP ab?
Gib doch mal per PHP alle Zeichen, die du aus der Datenbank erhältst, einzeln aus, etwa so:
header("Content-Type: text/plain; charset=iso-8859-1");
…
$s = Betroffenes_Datum_aus_der_Datenbank;
for ($i = 0; $i < strlen($s); $i++) {
echo s{$i} . " " . ord(s{$i}) . " ";
}
Das Problem, dass ":zahl", also z.B. ":3", zu einem Fragezeichen konvertiert wird, tritt auch auf, wenn ich einen HTML-Link im String habe:
<a href="http://www.seite.de/index.php?var1=irgendwas&var2=irgendwas" target="blank">irgendwohin</a>
In dieser Adresse steht kein ":3", und wenn's drin wäre, wo träte das Problem dann auf? Im HTML-Code? In der Adresszeile des Browsers?
Wenn ich mit PHPs stripslashes()-Funktion alle Slashes entferne, tritt das Problem übrigens nicht mehr auf
Wie sieht denn der von stripslashes() unveränderte Text, also mit Rückstrichen aus?
echo $begrüßung;
Ich mache folgenden Insert mittels PDO:
insert into table (text) values ('1:0 Ä')
Wie genau machst du das? Ist dir die Sonderbedeutung des : im Zusammenhang mit Prepared Statements in PDO bekannt?
Die Daten sollten in UTF-8 vorliegen.
Prüfe sowas bitte nach. Kontrollausgaben mittels var_dump() zeigen schonmal eine String-Länge in Bytes an. Bei einem UTF-8-Ä wären das 2 Bytes. Mit bin2hex() kann man die Bytewerte direkt kontrollieren.
Aber nach dem Connecten und vor dem Insert setze ich die folgenden Anweisung an die Datenbank ab:
"SET NAMES utf8"
"SET CHARACTER SET utf8"
Beide Anweisungen setzen die gleichen drei Werte, tun dies jedoch auf unterschiedliche Weise. Die zuletzt ausgeführte Anweisung überschreibt das, was die erste geamcht hat. Ich nehme an, du willst nur SET NAMES ausführen und bist dir nicht über die Auswirkungen von SET CHARACTER SET bewusst. (Connection Character Sets and Collations)
Das Problem, dass ":zahl", also z.B. ":3", zu einem Fragezeichen konvertiert wird, tritt auch auf, wenn ich einen HTML-Link im String habe:
Ich tippe auf Prepared Statements.
Was vielleicht noch wichtig ist in Verbindung mit dem Link: Der String ist mit magic_quotes escaped. Ich habe versucht mysql_real_escape_string() zu verwenden, aber da erhalte ich einen leere String zurück.
Wie sieht es mit Fehlermeldungen aus? Steht error_reporting auf E_ALL (und display_errors auf on)? mysql_real_escape_string() benötigt eine mit mysql_connect() hergestellte Verbindung bzw. erstellt sie sich automatisch selbst. Wenn du PDO verwendest solltest du auch nur Funktionen von PDO verwenden und nicht Dinge von anderen Extensions. PDO::quote() übernimmt das Maskieren _und_ das Quotieren. Noch besser wäre gleich das korrekte Verwenden von Prepared Statements. Da erübrigt sich das Quotieren und Maskieren (Magic Quotes ausschalten, die werden nicht benötigt und sind kontraproduktiv).
Wenn ich mit PHPs stripslashes()-Funktion alle Slashes entferne, tritt das Problem übrigens nicht mehr auf, aber das ist natürlich alles andere als sicher um es in einer SQL-Anweisung zu verwenden.
Magic Quotes sind nicht für SQL-Anweisungen geeignet. Ach? Ja. Nicht alle Systeme haben die gleichen Quotier- und Maskier-Regeln. Magic Quotes hilft vielleicht bei MySQL, doch wirkt es auf alle Eingabedaten, nicht nur auf die Daten, die zur Datenbank gesendet werden. Und aus beispielsweise Dateien kommende Daten wirkt es gar nicht.
Noch eine Kleinigkeit: Wenn ich einen Text mit mehreren Absätzen (zwei Zeilenumbrüche gelten für mich jetzt mal als neuer Absatz) habe, tritt das Problem "1:0" -> "1?" IMMER NUR im ersten Absatz auf.
Eins nach dem anderen, vielleicht klärt sich dieses Problem, wenn du die obigen geklärt hast.
echo "$verabschiedung $name";
Wie genau machst du das? Ist dir die Sonderbedeutung des : im Zusammenhang mit Prepared Statements in PDO bekannt?
Eigentlich, ja, hatte ich aber ausgeblendet.
Die Daten sollten in UTF-8 vorliegen.
Prüfe sowas bitte nach. Kontrollausgaben mittels var_dump() zeigen schonmal eine String-Länge in Bytes an. Bei einem UTF-8-Ä wären das 2 Bytes. Mit bin2hex() kann man die Bytewerte direkt kontrollieren.
Hab's überprüft, die Daten liegen in UTF-8 vor. Habs allerdings mit mb_check_encoding() geprüft.
Aber nach dem Connecten und vor dem Insert setze ich die folgenden Anweisung an die Datenbank ab:
Das Problem, dass ":zahl", also z.B. ":3", zu einem Fragezeichen konvertiert wird, tritt auch auf, wenn ich einen HTML-Link im String habe:
Ich tippe auf Prepared Statements.
Tja, ich habe gar keine prepared statements benutzt. Jetzt mache ich's und es funktioniert wunderbar. Kein Problem mehr.
Ich danke Euch beiden herzlichst,
beste Grüße,
Pierre