PHP/MySQL: Über ein Prepared Statement einen Wert in eine binary-Spalte eintragen schlägt fehl

  • PHP

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von Marcus Gräfe.

    PHP/MySQL: Über ein Prepared Statement einen Wert in eine binary-Spalte eintragen schlägt fehl

    Ich versuche schon seit Stunden, mit PHP 8.0 in eine MariaDB-Datenbank (10.5) einen Wert in eine Spalte mit dem Typ binary einzutragen. Die Tabellendefinition:

    SQL-Abfrage

    1. CREATE TABLE IF NOT EXISTS `customer` (
    2. `id` binary(16) NOT NULL,
    3. PRIMARY KEY (`id`)
    4. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_nopad_ci;

    Der PHP-Code:

    PHP-Quellcode

    1. $stmI = $db->prepare('INSERT INTO customer (id) VALUES (?)');
    2. $stmI->bind_param('b', $id);
    3. $id = '0x0002D124595984469DF191E5DA0D228B';
    4. $id = hex2bin(mb_substr($id, 2)); // ID binär machen
    5. $stmI->execute();

    Fehlermeldung: Column 'id' cannot be null

    Was mache ich falsch?

    Ich habe schon folgendes versucht:
    1.) $stmI->bind_param('s', $id); ("s" statt "b").
    2.) Unter der hex2bin-Anweisung $id = bin2hex($id); und bei der SQL-Anweisung 'INSERT INTO customer (id) VALUES (UNHEX(?))' ("UNHEX").

    Habt ihr noch mehr Ideen?
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum
    Ich war mal neugierig, und habe mal ein bisschen getestet. Mit deiner Methode konnte ich zwar Datensätze anlegen, die angelegte id war aber immer 0x000....
    Nach ein bisschen suchen bin ich hierrauf php.net/manual/en/mysqli-stmt.send-long-data.php gestoßen und habe das mal getestet. Was soll ich sagen, so gings...

    PHP-Quellcode

    1. $null = NULL;
    2. $statement = $db->prepare("INSERT INTO customer (id) VALUES (?);");
    3. $statement->bind_param('b', $null);
    4. $id = '0x0002D124595984469DF191E5DA0D228B';
    5. $id = hex2bin(mb_substr($id, 2));
    6. $statement->send_long_data(0, $id);
    7. $result = $statement->execute();
    8. var_dump($result);


    Ob das so "schön" ist, ich weiß es nicht :D
    Ich denke $id ist noch NULL beim binden. Versuch es in der Reihenfolge:

    PHP-Quellcode

    1. $query = "INSERT INTO customer (id) VALUES (:id)";
    2. $stmt = $db->prepare($query);
    3. $id = '0x0002D124595984469DF191E5DA0D228B';
    4. $id = hex2bin(mb_substr($id, 2));
    5. $stmt->bindParam(":id", $id);
    6. $stmt->execute();

    @Takafusa
    VALUES (:id) muss VALUES (?) und bindParam(":id", $id) muss bindParam("s", $id) (oder "b") heißen. Und der Variableninhalt darf leer sein vor dem Binden, denn das hier ist möglich (und einer der Vorteile von Prepared Statements):

    PHP-Quellcode

    1. $stmI = $db->prepare('INSERT INTO customer (id) VALUES (?)');
    2. $stmI->bind_param('i', $id);
    3. for ($id = 0; $id < 10; $id++) {
    4. $stmI->execute();
    5. }

    => Das fügt Datensätze mit den IDs 0 bis 9 ein.

    Aber: dein Posting hat mir dennoch weitergeholfen, denn tatsächlich sah mein Code wie folgt aus (man beachte das $col-Array):

    PHP-Quellcode

    1. $stmI = $db->prepare('INSERT INTO customer (id) VALUES (?)');
    2. $stmI->bind_param('b', $col[0]);
    3. $col = array();
    4. $col[0] = '0x0002D124595984469DF191E5DA0D228B';
    5. $col[0] = hex2bin(mb_substr($col[0], 2)); // ID binär machen
    6. $stmI->execute();

    Nach dem Entfernen von $col = array(); ging es dann. Bzw. nicht ganz, denn plötzlich gab es direkt ab dem 2. Datensatz ein "duplicate entry". Anscheinend wollte PHP oder MySQL nach einem Null-Char nicht weitermachen (und die ersten hundert Datensätze beginnen quasi mit einem Null-Char in der ID).

    Aber dafür gab es dann die Lösung von @ISliceUrPanties
    Das send_long_data funktioniert und ist hier wohl nötig. Dazu habe ich auch folgendes Posting gefunden, welches das bestätigt: stackoverflow.com/a/30019463
    Es ergibt für mich zwar überhaupt keinen Sinn, weil ich keine großen Binärdaten schicke, sondern nur eine 16-Byte-ID, aber wenn es PHP so haben will ...

    Insgesamt waren es also 2 Probleme, wobei sich danach direkt noch das nächste Problem bemerkbar machte, worauf ich nur kurz eingehe. Das Wort "Greåker" (in einer hier nicht erwähnten Spalte in der Kundentabelle) konnte nicht eingefügt werden. Ich musste alle Strings in meinem $col-Array noch mit utf8_encode() behandeln. Interessanterweise habe ich diese Lösung aus dem Artikel von send_long_data (php.net/manual/de/mysqli-stmt.send-long-data.php) aus den Kommentaren, wobei dieser Kommentar ausgegraut ist, weil er -8 Votes hat.

    Auf jeden Fall vielen Dank an euch beide!
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum
    Als kleine Ergänzung:

    Ich mache es mittlerweile ganz anders. Bezogen auf den PHP-Code vom 1. Post wäre das nun mein Weg:

    PHP-Quellcode

    1. $stmI = $db->prepare('INSERT INTO customer (id) VALUES (UNHEX(?))');
    2. $stmI->bind_param('s', $id);
    3. $id = '0x0002D124595984469DF191E5DA0D228B';
    4. $id = mb_substr($id, 2); // 0x abschneiden
    5. $stmI->execute();

    D. h. ich sende einen String und die Datenbank wandelt es in einen Binärwert um. Beim Abfragen mache ich sowas in der Art:

    SQL-Abfrage

    1. SELECT HEX(id) id FROM customer

    Inwieweit dies ein spürbarer Performanceunterschied ist, konnte ich bisher nicht prüfen. Gefunden habe ich dazu jedenfalls keine gehaltvollen Infos.
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum