2009-11-17 17 views
8

Tengo que insertar una fila usando la biblioteca mejorada de mysql de php en una tabla en mysql que tiene su clave primaria de tipo VARBINARY. El contenido de este campo es un hash sha1 calculado.PHP- insertando datos binarios en mysql usando declaraciones preparadas

Si funciono con la pregunta de la manera antigua que funciona perfectamente:

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

Pero cuando intento ejecutarlo como una declaración preparada, no puedo encontrar la manera de hacerlo. Si realizo la acción equivalente:

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

Se produce una excepción diciendo que el contenido era demasiado grande para este campo. Y si intento insertarlo como un campo BLOB:

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

Se da ningún error, se inserta la fila, pero el campo identificador ahora está vacía (no nulo, vacío).

Sé que puedo mezclar la consulta e ingresar el id concatenado en la cadena y los otros campos como parámetros de enlace de la declaración preparada, pero solo pregunto cuál es la forma correcta de insertar esto y tal vez ayudará a alguien en el futuro.

+0

¿Qué valores tiene para ello y $ $ campo1 cuando se hace esto? ¿$ Id es un número entero? Si es así, ¿has intentado atarlo como tal? 'stmt-> bind_param ('es', $ id, $ campo1);' – nash

+0

el valor de $ id es un hash sha1. No es un número entero. Los otros campos no están causando el problema, pero son principalmente cadenas. –

+0

Más uno para tratar de conservar la seguridad de las declaraciones preparadas mientras se resuelve este problema. – HoldOffHunger

Respuesta

6

de PHP sha1 devuelve una representación de cadena de un número hexadecimal.

Lo que eso significa es que si lo imprime en la pantalla, se mostrará un número hexadecimal. Pero en memoria, es un grupo de caracteres ASCII.

Por lo tanto, tome el número hexadecimal 1A2F. Como ASCII en la memoria que sería 0x31413246, en lugar de 0x1A2F

La interfaz normal de MySQL envía todos los argumentos como cadenas. Al usar la interfaz normal, MySQL convertirá la cadena ASCII a un valor binario.

El nuevo método de declaración preparado envía todo como binario. Entonces, su buen valor de "1A2F" ahora se enviará como 0x31413246 y se insertará en la columna. - source: dev.mysql.com - Prepared statements

En cambio, convertir la cadena de Hex por el embalaje en una cadena binaria usando:

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

y luego pasar a la $binId MySQLi comunicado en lugar de $ Identificación del preparado.

+0

Tienes razón. Esta es la manera de hacerlo. Muchas gracias. –

+0

¡Estaba preguntándome esto! Solo quería señalar que también puede usar 'hex2bin' como una alternativa conveniente a' pack', y también puede usar 'bin2hex' cuando saca los datos nuevamente (en lugar de tener que usar' HEX() 'en su declaración). – Haravikk

3

probar esto en su lugar: la función

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

tl; dr: echa un vistazo a send_long_data().

Sé que esta es una pregunta muy antigua, pero fue exactamente lo que estaba tratando de hacer y no a. Después de probar las respuestas anteriores y pasar mucho tiempo experimentando, finalmente encontré algo que funciona de la forma en que la pregunta y yo lo intentábamos.

Es confuso porque la única referencia para la forma de proceder con "b" tipos en el PHP bind_param documentation es indirectamente cuando se hace referencia a los datos exceda el tamaño permitido de paquetes (que inicialmente me he saltado sobre):

Si el tamaño de datos de una variable excede el máx. permitido que el tamaño del paquete (max_allowed_packet), se tiene que especificar b en tipos y utilizar mysqli_stmt_send_long_data() para enviar los datos en paquetes.

Resulta que los tipos binarios deben enviarse solos antes de ejecutar su inserción. Encontré esto en un article from Oracle's website.

Desde lo explican de manera sucinta, voy a parafrasear la parte más relevante:

Almacenamiento de la burbuja

Aquí está el código para almacenar una mancha usando 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(); 

En negrita dos piezas de código, que I th de tinta son vale la pena mirar:

El $ nula variable es necesaria, debido a bind_param() siempre quiere una referencia variable para un determinado parámetros. En este caso, el parámetro "b" (como en blob). Entonces, $ null es solo un maniquí, para que la sintaxis funcione.

En el siguiente paso necesito "llenar" mi parámetro blob con los datos reales. Esto se hace por send_long_data(). El primer parámetro de este método indica con qué parámetro asociar los datos. Los parámetros están numerados comenzando con 0. El segundo parámetro de send_long_data() contiene los datos reales que se almacenarán.

Durante el uso de send_long_data(), por favor asegúrese de que la mancha no es más grande que max_allowed_packet de MySQL

Cuestiones relacionadas