Bernd: Langen Srting in Datenbank schreiben ->Fatal error: Uncaught PDOException: SQLSTATE[22007]

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

akzeptierte Antworten

  1. 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.

    1. 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

      1. Das habe ich auch gedacht. Aber so ist es nicht.

        Dann verschluckt sich die Datenbank eben am übergebenen String, den Du falsch behandelt hast.

        1. 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

          1. 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

            1. 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

              --
              200 ist das neue 35.
              1. Hallo Auge,

                Schrub er doch.

                Das Feld ist longtext, utf8_general_ci

                Rolf

                --
                sumpsi - posui - obstruxi
                1. 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

                  --
                  200 ist das neue 35.
                  1. 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 ?

                    1. 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:

                      • 1292 - ER_TRUNCATED_WRONG_VALUE - hm.
                      • 1367 - ER_ILLEGAL_VALUE_FOR_TYPE - 😀⚡💡

                      Was wir aber bekommen, ist

                      • 1366 - ER_TRUNCATED_WRONG_VALUE_FOR_FIELD

                      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

                      --
                      sumpsi - posui - obstruxi
                      1. 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

                        1. 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

                          --
                          sumpsi - posui - obstruxi
                          1. 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...

                            1. 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

                              --
                              Es gibt soviel Sonne, nutzen wir sie.
                              www.Solar-Harz.de
                              S☼nnige Grüße aus dem Oberharz
      2. 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

        --
        sumpsi - posui - obstruxi
        1. 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

          --
          Dass Dr. Oetker in Amerika eine Puddingmine entdeckt und damit seine ersten Millionen gemacht hat, ist nur ein Gerücht.
          1. 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

            --
            sumpsi - posui - obstruxi
  2. 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

    --
    Dass Dr. Oetker in Amerika eine Puddingmine entdeckt und damit seine ersten Millionen gemacht hat, ist nur ein Gerücht.
  3. 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']));

    • Für die Übergabe in einen SQL-Kontext ist diese Behandlung falsch.
    • Die Verschachtelung von 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

    --
    200 ist das neue 35.
    1. 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

      --
      sumpsi - posui - obstruxi
      1. 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

        --
        200 ist das neue 35.
  4. 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