sql >> Base de Datos >  >> RDS >> PostgreSQL

Almacenamiento de imágenes en campos bytea en una base de datos PostgreSQL

TL;DR:

Eliminar addslashes($data) . Es redundante aquí.

Doble escape... dos veces

$data=fread($p,filesize($fi));
$data=addslashes($data);
$dat= pg_escape_bytea($data); 

Usted lee los datos, escapa como si fuera un literal de cadena, luego los convierte en bytea octal o escapes hexadecimales. Nunca podría funcionar de esa manera incluso si pg_escape_bytea estaba cuerdo, que no lo es.

pg_escape_bytea de PHP parece doble escape la salida para que pueda insertarse en un literal de cadena. Esto es increíblemente feo, pero no parece haber una alternativa que no haga este doble escape, por lo que parece que no puede usar declaraciones parametrizadas para bytea en PHP. Deberías seguir haciéndolo para todo lo demás.

En este caso, simplemente eliminando las addslashes línea para los datos leídos del archivo es suficiente.

Caso de prueba que muestra que pg_escape_bytea escapes dobles (y siempre usa también los viejos e ineficientes escapes octales):

<?php
# oh-the-horror.php
print pg_escape_bytea("Blah binary\x00\x01\x02\x03\x04 blah");
?>

Ejecutar:

php oh-the-horror.php

Resultado:

Blah binary\\000\\001\\002\\003\\004 blah

¿Ves las barras invertidas duplicadas? Esto se debe a que supone que lo va a interpolar en SQL como una cadena, lo cual es extremadamente ineficiente para la memoria, feo y un muy mal hábito. Sin embargo, parece que no tienes otra alternativa.

Entre otras cosas, esto significa que:

pg_unescape_bytea(pg_escape_bytea("\x01\x02\x03"));

... produce el resultado incorrecto , ya que pg_unescape_bytea en realidad no es lo contrario de pg_escape_bytea . También hace que sea imposible alimentar la salida de pg_escape_bytea en pg_query_params como parámetro, debe interpolarlo.

Decodificación

Si está utilizando un PostgreSQL moderno, probablemente establezca bytea_output a hex por defecto. Eso significa que si escribo mis datos en un bytea luego recupérelo, se verá así:

craig=> CREATE TABLE byteademo(x bytea);
CREATE TABLE
craig=> INSERT INTO byteademo(x) VALUES ('Blah binary\\000\\001\\002\\003\\004 blah');
INSERT 0 1
craig=> SELECT * FROM byteademo ;
                                     x                                      
----------------------------------------------------------------------------
 \x426c61682062696e6172795c3030305c3030315c3030325c3030335c30303420626c6168
(1 row)

"Um, ¿qué", podrías decir? Está bien, es solo la representación hexadecimal ligeramente más compacta de PostgreSQL de bytea . pg_unescape_bytea lo manejará bien y producirá los mismos bytes sin formato que la salida... si tiene un PHP moderno y libpq . En versiones anteriores, obtendrá basura y deberá configurar bytea_output escape para pg_unescape_bytea para manejarlo.

Qué deberías hacer en su lugar

Usar DOP.

Tiene soporte sensato (ish) para bytea .

$sth = $pdo->prepare('INSERT INTO mytable(somecol, byteacol) VALUES (:somecol, :byteacol)');
$sth->bindParam(':somecol', 'bork bork bork');
$sth->bindParam(':byteacol', $thebytes, PDO::PARAM_LOB);
$sth->execute();

Ver:

  • PHP:Objetos grandes, que tiene un ejemplo de exactamente lo que desea;
  • DeclaraciónPDOS::bindParam
  • cómo almacenar un objeto serializado con espacio de nombres en la base de datos usando pdo php
  • Enlace BYTEA a la declaración preparada de PGSQL PDO en PHP5

También es posible que desee consultar la compatibilidad con lob (objetos grandes) de PostgreSQL, que proporciona una interfaz de búsqueda de transmisión que aún es completamente transaccional.

Ahora, a mi caja de jabón

Si PHP tuviera una distinción real entre los tipos de "cadena de bytes" y "cadena de texto", ni siquiera necesitaría pg_escape_bytea ya que el controlador de la base de datos podría hacerlo por usted. Nada de esta fealdad sería necesaria. Desafortunadamente, no hay cadenas separadas y tipos de bytes en PHP.

Por favor, use PDO con sentencias parametrizadas tanto como sea posible.

Donde no puedas, al menos usa pg_query_params y sentencias parametrizadas. addslashes de PHP no es una alternativa, es ineficiente, desagradable y no comprende las reglas de escape específicas de la base de datos. Todavía tienes que escapar manualmente bytea si no está utilizando PDO por razones históricas repulsivas, pero todo lo demás debe pasar por declaraciones parametrizadas.

Para obtener orientación sobre pg_query_params :

  • Tablas Bobby, sección PHP.
  • El manual de PHP en pg_query_params