2009-11-17 6 views
8

Je dois insérer une ligne en utilisant la bibliothèque mysql améliorée de php dans une table de mysql qui a sa clé primaire de type VARBINARY. Le contenu de ce champ est un hachage sha1 calculé.PHP- insérer des données binaires dans mysql en utilisant des instructions préparées

Si je lance la requête à l'ancienne, il fonctionne parfaitement:

$mysqli->$query("INSERT INTO table (id, field1) VALUES (0x" . $id . ",'" . $field1 . "')"); 

Mais lorsque je tente de l'exécuter comme une déclaration préparée, je ne peux pas comprendre comment le faire. Si je effectuer l'action équivalente:

if($stmt = $mysqli->prepare("INSERT INTO table (id, field1) VALUES (?, ?)")) { 
    $stmt->bind_param('ss', "0x".$id, $field1); 
    //execute statement 
} 

Il jette une exception en disant que le contenu était trop grand pour ce domaine. Et si j'essaie de l'insérer comme un champ BLOB: la ligne est insérée, mais le champ d'identification est maintenant vide (non nul, vide)

if($stmt = $mysqli->prepare("INSERT INTO table (id, field1) VALUES (?, ?)")) { 
    $stmt->bind_param('bs', $id, $field1); 
    //execute statement 
} 

Il ne donne aucune erreur,.

Je sais que je peux mélanger la requête et entrer l'identifiant concaténé dans la chaîne et les autres champs comme paramètres de liaison de l'instruction préparée, mais je demande juste de savoir quelle est la bonne façon d'insérer cela et peut-être aidera quelqu'un dans le futur.

+0

Quelles sont les valeurs que vous avez pour $ id et field1 $ quand vous faites cela? Est-ce que $ id est un entier? Si oui, avez-vous essayé de le relier comme tel? 'stmt-> bind_param ('est', $ id, $ field1);' – nash

+0

la valeur de $ id est un hash sha1. Ce n'est pas un nombre entier. Les autres champs ne causent pas le problème mais sont principalement des chaînes. –

+0

Plus un pour essayer de conserver la sécurité des instructions préparées tout en résolvant ce problème. – HoldOffHunger

Répondre

6

fonction PHP sha1 renvoie une représentation de chaîne d'un nombre hexadécimal. Cela signifie que si vous l'imprimez à l'écran, il affichera un nombre hexadécimal. Mais en mémoire, c'est un tas de caractères ASCII.

Donc, prenez le nombre hexadécimal 1A2F. Comme ASCII dans la mémoire qui serait 0x31413246, au lieu de 0x1A2F

L'interface normale de MySQL envoie tous les arguments sous forme de chaînes. Lors de l'utilisation de l'interface normale, MySQL convertira la chaîne ASCII en une valeur binaire.

La nouvelle méthode d'instruction préparée envoie tout en tant que binaire. Donc, votre valeur de "1A2F" va maintenant être envoyée comme 0x31413246 et insérée dans la colonne. - source: dev.mysql.com - Prepared statements

Au lieu de cela, convertir votre chaîne Hex en emballant dans une chaîne binaire en utilisant:

$binId = pack("H*", $id); // this string is not ASCII, don't print it to the screen! That will be uggly. 

puis passer $binId à la déclaration préparée MySQLi au lieu de $ id.

+0

Vous avez raison. C'est la façon de le faire. Merci beaucoup. –

+0

Me demandais moi-même! Je voulais juste noter que vous pouvez également utiliser 'hex2bin' comme une alternative pratique à' pack', et pouvez également utiliser 'bin2hex' lorsque vous retirez les données (plutôt que d'utiliser' HEX() 'dans votre instruction). – Haravikk

3

essayer ceci:

if($stmt = $mysqli->prepare("INSERT INTO table (id, field1) VALUES (unhex(?), ?)") { 
    $stmt->bind_param('ss', $id, $field1); 
    //execute statement 
} 
0

tl; dr: consultez send_long_data().

Je sais que c'est une très vieille question, mais c'était exactement ce que j'essayais de faire et échouer à. Après avoir essayé les réponses ci-dessus et passé beaucoup de temps à expérimenter, j'ai finalement trouvé quelque chose qui fonctionne de la façon dont la question et moi essayions.

Il est source de confusion parce que la seule référence pour savoir comment procéder à « b » types dans le PHP bind_param documentation est indirectement en référence à des données dépassant la taille des paquets autorisés (que je initialement sautée):

Si la taille des données d'une variable dépasse max. La taille maximale autorisée des paquets (max_allowed_packet), vous devez spécifier b dans types et utiliser mysqli_stmt_send_long_data() pour envoyer les données en paquets.

Il s'avère que les types binaires doivent être envoyés par eux-mêmes avant d'exécuter votre insertion. Je l'ai trouvé à partir d'un article from Oracle's website.

Comme ils l'expliquent succinctement, je vais paraphraser la partie la plus pertinente:

Stockage du blob

Voici le code pour stocker un blob en utilisant MySQLi:

$stmt = $mysqli->prepare("INSERT INTO images (image) VALUES(?)") 
$null = NULL; //bolded 
$stmt->bind_param("b", $null); 

$stmt->send_long_data(0, file_get_contents("osaka.jpg")); //bolded 

$stmt->execute(); 

J'ai mis en gras deux morceaux de code, que j'ai l'encre sont dignes d'intérêt à:

La variable null de $ est nécessaire, parce que bind_param() veut toujours une référence variable pour un paramètre donné. Dans ce cas, le paramètre "b" (comme dans blob). Donc, $ null est juste un mannequin, pour faire fonctionner la syntaxe.

Dans l'étape suivante, j'ai besoin de "remplir" mon paramètre blob avec les données réelles. Ceci est fait par send_long_data(). Le premier paramètre de indique le paramètre auquel associer les données. Les paramètres sont numérotés à partir de 0. Le deuxième paramètre de send_long_data() contient les données réelles à stocker.

Lors de l'utilisation send_long_data(), s'il vous plaît assurez-vous que le blob n'est pas plus grand que MySQL max_allowed_packet

Questions connexes