Langen Srting in Datenbank schreiben ->Fatal error: Uncaught PDOException: SQLSTATE[22007]
Bernd
- pdo
- php
Hallo,
ich habe einen langen Text den ich über einem Formular eingebe und diesen mittels pdo in eine sql Datenbank schreibe.
Den String behandele ich so: htmlspecialchars(htmlentities($_POST['text']));
Ich denke das ich das ein oder andere Sonderzeichen in meinem eingegebenen Text habe.
Folgende Meldung bekomme ich:
Fatal error: Uncaught PDOException: SQLSTATE[22007]: Invalid datetime format: 1366 Incorrect string value:
Ich muss gestehen, ich komme mit der Fehlermeldung nicht klar, und finde auch nichts im Netz was ich verstehe.
Über eine Hilfe würde ich mich freuen.
Bernd
Den String behandele ich so: htmlspecialchars(htmlentities($_POST['text']));
Beware. Entweder PDO::quote oder PDO::prepare
Invalid datetime format: 1366 Incorrect string value:
Du versuchst offenbar den Text in eine Spalte zu schreiben, welche eine Datums/Zeitangabe aber keine Gedichte, Romane oder sonstige Prosa erwartet.
Das ist so, also versuchst Du die Papiertonne mit Sperrmüll zu füllen und scheiterst am Schlitz.
Das habe ich auch gedacht. Aber so ist es nicht.
Das Feld ist longtext, utf8_general_ci
wenn im Text so ein Sonderzeichen vorkommt
👥
kommt diese Fehlermeldung
Das habe ich auch gedacht. Aber so ist es nicht.
Dann verschluckt sich die Datenbank eben am übergebenen String, den Du falsch behandelt hast.
Jetzt habe ich alles rausgenommen:
$statement = $pdo->prepare("UPDATE tab1 SET inhalt =:inhalt WHERE id =:id");
$result = $statement->execute(array('inhalt' => $_POST['inhalt'],
'id' => $id));
Es funktioniert einbandfrei, bis besagtes Sonderezeichen 👥 vorkommt
Fatal error: Uncaught PDOException: SQLSTATE[22007]: Invalid datetime format: 1366 Incorrect string value: '\xF0\x9F\x91\xA5 B...'
Aber es ist kein DATE Feld
Moin Bernd,
$statement = $pdo->prepare("UPDATE tab1 SET inhalt =:inhalt WHERE id =:id"); $result = $statement->execute(array('inhalt' => $_POST['inhalt'], 'id' => $id));
Es funktioniert einbandfrei, bis besagtes Sonderezeichen 👥 vorkommt
Fatal error: Uncaught PDOException: SQLSTATE[22007]: Invalid datetime format: 1366 Incorrect string value: '\xF0\x9F\x91\xA5 B...'
Wie sieht denn das gesamte, generierte SQL-Statement aus, welches versucht wird dort auszuführen?
Viele Grüße
Robert
Hallo
$statement = $pdo->prepare("UPDATE tab1 SET inhalt =:inhalt WHERE id =:id"); $result = $statement->execute(array('inhalt' => $_POST['inhalt'], 'id' => $id));
Es funktioniert einbandfrei, bis besagtes Sonderezeichen 👥 vorkommt
Wie sieht denn das gesamte, generierte SQL-Statement aus, welches versucht wird dort auszuführen?
… und wie sieht die Tabellendefintion, speziell die Definition des Feldes inhalt
aus?
Tschö, Auge
Hallo Auge,
Schrub er doch.
Das Feld ist longtext, utf8_general_ci
Rolf
Hallo
Schrub er doch.
Das Feld ist longtext, utf8_general_ci
Nicht, dass er sich verguckt hat. Deshalb hätte ich es gut gefunden, die Info noch einmal, us einem anderen Blickwinkel geprüft, zu bekommen. Wir sind ja alle gern mal betriebsblind.
Davon abgesehen musste ich mir erst einmal „ersuchen“, was für ein Datentyp longtext
ist. 4GB Textdaten. Da bekommt man doch eine ganze Kleinstadtbibliothek rein. 😆
Tschö, Auge
Ich habe alles auf utf8mb_unicode_ci umgestellt.
Das Feld ist
longtext utf8mb4_unicode_ci
Ich bekomme immer diese Fehlermeldung, wenn ich es eingebe:
Fatal error: Uncaught PDOException: SQLSTATE[22007]: Invalid datetime format: 1366 Incorrect string value: '\xF0\x9F\x91\xA5 B...'
wenn ich es über die phpmyadmin eingebe funktioniert es.
über :
$statement = $pdo->prepare("UPDATE tab1 SET inhalt =:inhalt WHERE id =:id");
$result = $statement->execute(array('inhalt' => $_POST['inhalt'],
'id' => $id));
und es ist dieses Symbol:
👥
Bernd
PS: wer schrubt wo ?
Hallo Bernd,
vorab: herzlichen Dank für diese Fehlermeldung. Sie hat eine wichtige Erkenntnis hervorgebraucht. Zur Belohnung kriegst Du auch eine Lösung 😀
Ich hab jetzt mal mein Mariechen zusammen mit Tante Heidi angeworfen.
In einer Testtabelle, die ich eh noch hatte und wo ein varchar-Feld drin war, habe ich 😆 (\u1f606) eingetragen.
Erstes Ergebnis 🙄: /* #26: Access violation at address 00000000 in module 'heidisql.exe'. Read of address 00000000 Message CharCode:13 Msg:256 */
Aber das kommt bei jeder Änderung an der Tabelle. Blödes HeidiSQL. Über einen "invalid string" beschwert sie sich dagegen nicht?!
Zweites Ergebnis - INSERT mit PHP: /* SQL Fehler (1366): Incorrect string value: '\xF0\x9F\x98\x86' for column test
.namen
.name
at row 1 */
Sehr interessant: Keine Rede vom Timestamp. Aber das war mysqli.
Jetzt mit PDO:
Fatal error: Uncaught PDOException: SQLSTATE[22007]: Invalid datetime format: 1366 Incorrect string value: '\xF0\x9F\x98\x86' for column test
.namen
.demo
at row 1 in D:\phpweb\local_sql.php:11
Ei da isser ja! D.h. das ist ein PDO Bug (oder ein misslungenes Feature), es versucht, den SQLSTATE 22007 zu interpretieren, nehme ich an. Der Hinweis auf den Timestamp ist schlichtweg Müll, bzw. vermutlich die häufigste Ursache für diesen SQLState. Nimmt man die PDOException auseinander, steht der Timestamp-Hinweis nicht in der errorInfo. Das scheint von PDO dazugedichtet zu sein.
Wenn man im MariaDB-Handbuch nach Fehlercodes sucht, findet man SQLState 22007 zweimal. Aber das Merkwürdige ist die Kombi, die man hier findet: 22007 zusammen mit Errorcode 1366. Laut Handbuch gehören zum SQLSTATE 22007 zwei Fehlercodes:
Was wir aber bekommen, ist
und dazu gehört SQState HY000. Der Meldungstext passt aber zum Format bei 1366. Mir scheint, die Datenbank schickt hier den falschen SQLState. Oder schert sich nicht um ihre eigene Doku.
Aber wie nun lösen?
Recherchieren geh
Okay, PDO bringt die Meldung auch dann, wenn man DB, Table und Spalten auf utf8mb4 setzt. Aber es gibt noch was: den Connection-Zeichensatz. PDO verwendet per Default den Server Defaultzeichensatz. Und der ist ab Werk utf8mb3. Sagt das MariaDB Handbuch.
Wenn Du es darfst, konfiguriere deine Datenbank in der my.cnf (Windows: my.ini) so, dass sie utf8mb4 als Serverdefault hat (Unter MariaDB die Sektion [server], Option character_set_server). PDO folgt dem und der Fehler ist nach einem Restart des Serverdienstes weg. Bei mir zumindest!
Oder, wenn Du da nicht 'randarfst, gib im DSN ein Charset an:
$dsn = "mysql:host=...;port=...;dbname=test;charset=utf8mb4";
$user = "...";
$pass = "...";
$db = new PDO($dsn, $user, $pass);
Mann mann mann, das ist ja ein Gewürge.
Find ich...
Ich hab's mal in der Geheimabteilung des Wiki vermerkt.
Rolf
Vielen Dank für deine Hilfe.
Und wie soll ein AMATUER bitte auf so etwas kommen.
Jedenfalls Danke auch an Mariechen und Tante Heidi wer immer auch das ist, vielleicht sollte ich bei weitere fragen, immer gleich die beiden kontaktieren-
Danke
Bernd
Hallo Bernd,
Mein Mariechen ist eine MariaDB 10.6 - die meisten Hoster verwenden diesen MySQL Klon an Stelle des veralteten MySQL 5.7 oder des von Oracle einkassierten MySQL 8.
HeidiSQL ist ein freies Clientprogramm für MariaDB. Sozusagen MyPhpAdmin für Windows.
Und wie soll ein AMATUER bitte auf so etwas kommen.
Ich bin auch so ein Tuer. Ich verdiene mit PHP keinen Cent Geld.
Lesen, Lesen, Lesen…
Rolf
Ich verdiene mit PHP keinen Cent Geld.
Stimmt. Kursnachfrage zum Thema „PHP“ ist derzeit mau. Verdiene ich eben mit „Linux-Admin in verschiedene Geschmacksrichtungen“ und Python ein paar Groschen...
Hello,
Stimmt. Kursnachfrage zum Thema „PHP“ ist derzeit mau. Verdiene ich eben mit „Linux-Admin in verschiedene Geschmacksrichtungen“ und Python ein paar Groschen...
Ich hätte noch ein paar Groschen im Budget, wenn Du mir bei MODBUS und Raspberry helfen könntest. Mehr bei Gelegenheit per eMail.
Glück Auf
Tom vom Berg
Hallo Bernd,
utf8_general_ci
utf8 ist ein Alias für utf8mb3 und seit MySQL 8 missbilligt. Man soll utf8mb4 verwenden. Leider haben sie es nicht gewagt, utf8 einfach intern auf utf8mb4 zu mappen. Das hätte vermutlich Kompatibilitätsprobleme gemacht.
Problem bei utf8/utf8mb3 ist, dass sie nur die Basic Multilingual Plane (Plane 0) von Unicode unterstützen, also Codepoints unter \x10000. Dein Codepoint ist in Plane 1 und deswegen weist der Server das ab. Man sieht das auch in der Fehlermeldung - da werden 4 Bytes angemeckert, und die sind die UTF-8 Darstellung deines Zeichens \u1f465
Das Wissen darum scheint nicht so verbreitet zu sein.
Ein Character Set und eine Collation sind ein Attribut der Datenbank. Beginne dort (sofern Du das darfst) und ändere das CHARACTER SET auf utf8mb4 und die Collation auf utf8mb4_general_ci.
Danach schau Dir die Tables an. Ich glaub's zwar nicht, aber vielleicht haben sie die DB-Einstellungen als Default gehabt und wurden automatisch angepasst. Wenn nicht, ändere auch CHARACTER SET und COLLATION der Tables.
Danach dann die Spalten. Wo nötig, ändere CHARACTER SET und COLLATION in allen Textspalten.
Rolf
Hallo Rolf,
utf8_general_ci
utf8 ist ein Alias für utf8mb3 und seit MySQL 8 missbilligt. Man soll utf8mb4 verwenden.
das ist in der Tat interessant!
Das Wissen darum scheint nicht so verbreitet zu sein.
Scheint so. Bei mir war es beispielsweise noch nicht angekommen - was aber nichts heißen muss.
Danach dann die Spalten. Wo nötig, ändere CHARACTER SET und COLLATION in allen Textspalten.
Das erklärt aber alles noch nicht, warum die Meldung 22007 Invalid timestamp format kommt, obwohl Bernd behauptet, da sei kein Timestamp im Spiel.
Einen schönen Tag noch
Martin
Hallo Martin,
stimmt, das erklärt es nicht. Wenn das Feld Text ist, sollte das nicht kommen. Aber wer weiß ob da noch ein Bug im PDO oder SQL Server lauert und einfach die Meldung falsch ist.
Oder das SQL ist eigentlich umfangreicher und es gibt noch einen zweiten Fehler.
Rolf
Hallo Bernd,
Den String behandele ich so: htmlspecialchars(htmlentities($_POST['text']));
warum das denn? Siehe Antwort vom Raketenwilli. htmlspecialchars() ist, wie der Name schon sagt, die richtige Escaping-Funktion, um einen String in den Kontext HTML zu bringen, aber nicht SQL.
Ich denke das ich das ein oder andere Sonderzeichen in meinem eingegebenen Text habe.
Das ist kein Problem, wenn man es richtig macht.
Einen schönen Tag noch
Martin
Hallo
ich habe einen langen Text den ich über einem Formular eingebe und diesen mittels pdo in eine sql Datenbank schreibe.
Den String behandele ich so: htmlspecialchars(htmlentities($_POST['text']));
htmlentities
in htmlspecialchars
ist prinzipiell mindestens unsinnig.Für die Übergabe der Eingabe in den SQL-Kontext hat Raketenwilli schon die korrekten Stichworte geliefert. Die Maskierung von kritischen Zeichen erfolgt bei der Ausgabe in HTML mit der Funktion htmlspecialchars
. Die maskiert alle Zeichen, die im HTML-Kontext einer Behandlung bedürfen.
Folgende Meldung bekomme ich:
Fatal error: Uncaught PDOException: SQLSTATE[22007]: Invalid datetime format: 1366 Incorrect string value:
Wie Raketenwilli schon sagte, ein Roman (Incorrect string value
) ist kein gültiges Datumsformat (Invalid datetime format
).
Tschö, Auge
Hallo Auge,
aber wie Martin schon sagte - ein Schreibvorgang in ein longtext Feld hat keinen Anlass, einen korrekten Timestamp zu überprüfen. Da ist noch mehr faul.
Rolf
Hallo
aber wie Martin schon sagte - ein Schreibvorgang in ein longtext Feld hat keinen Anlass, einen korrekten Timestamp zu überprüfen. Da ist noch mehr faul.
Das stimmt wohl, aber während ich das Posting schrieb, war das noch nicht klar. Die Klarstellung, dass es sich nicht um ein Feld des Typs datetime
handelt, habe ich erst nach dem absenden des Postings gesehen.
Tschö, Auge
Moin Bernd,
Den String behandele ich so:
htmlspecialchars(htmlentities($_POST['text']));
da ist doch etwas „doppelt gemoppelt“:
htmlentities
wandelt alle möglichen Zeichen in HTML-Entitäten um, d.h. z.B. ä
⇒ ä
.htmlspecialchars
wandelt alle HTML-Sonderzeichen in Entitäten um, d.h. z.B. &
⇒ &
Das heißt deine Verkettung der beiden Funktionen macht aus ä
⇒ &aml;uml;
.
Viele Grüße
Robert