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