PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Memorizzazione di immagini in campi byte in un database PostgreSQL

TL;DR:

Elimina addslashes($data) . Qui è ridondante.

Doppio escape .. due volte

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

Leggi i dati, esegui l'escape come se fosse una stringa letterale, quindi lo converti in bytea ottale o esadecimale. Non potrebbe mai funzionare in questo modo anche se pg_escape_bytea era sano di mente, ma non lo è.

pg_escape_bytea di PHP sembra doppio escape l'output in modo che possa essere inserito in una stringa letterale. Questo è incredibilmente brutto, ma non sembra esserci un'alternativa che non esegua questo doppio escape, quindi non sembra che tu possa usare istruzioni parametrizzate per bytea in PHP. Dovresti comunque farlo per tutto il resto.

In questo caso, è sufficiente rimuovere le addslashes è sufficiente la riga per i dati letti dal file.

Caso di test che mostra che pg_escape_bytea double-escapes (e usa sempre anche i vecchi e inefficienti escape ottali):

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

Corri:

php oh-the-horror.php

Risultato:

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

Vedi le barre rovesciate raddoppiate? Questo perché presuppone che lo interpolerai in SQL come una stringa, il che è estremamente inefficiente in termini di memoria, brutto e una pessima abitudine. Tuttavia, non sembra che tu abbia alternative.

Tra l'altro questo significa che:

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

... produce il risultato errato , poiché pg_unescape_bytea in realtà non è il contrario di pg_escape_bytea . Inoltre, rende impossibile alimentare l'output di pg_escape_bytea in pg_query_params come parametro, devi interpolarlo.

Decodifica

Se stai usando un PostgreSQL moderno, probabilmente imposta bytea_output in hex per impostazione predefinita. Ciò significa che se scrivo i miei dati su un bytea campo quindi recuperalo, sarà simile a questo:

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)

"Uhm, cosa", potresti dire? Va bene, è solo la rappresentazione esadecimale leggermente più compatta di bytea di PostgreSQL . pg_unescape_bytea lo gestirà bene e produrrà gli stessi byte grezzi dell'output ... se hai un PHP moderno e libpq . Nelle versioni precedenti otterrai spazzatura e dovrai impostare bytea_output per escape per pg_unescape_bytea per gestirlo.

Cosa dovresti fare invece

Usa DOP.

Ha un supporto sano (ish) per 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();

Vedi:

  • PHP:Large Objects, che contiene un esempio di esattamente ciò che desideri;
  • PDOStement::bindParam
  • come memorizzare un oggetto serializzato con spazio dei nomi nel database usando pdo php
  • Collega BYTEA a PGSQL PDO Prepared Statement in PHP5

Potresti anche voler esaminare il supporto lob (oggetto di grandi dimensioni) di PostgreSQL, che fornisce un'interfaccia in streaming ricercabile che è ancora completamente transazionale.

Ora, alla mia scatola di sapone

Se PHP avesse una vera distinzione tra i tipi "stringa di byte" e "stringa di testo", non avresti nemmeno bisogno di pg_escape_bytea poiché il driver del database potrebbe farlo per te. Nessuna di queste bruttezze sarebbe necessaria. Sfortunatamente, in PHP non ci sono tipi di stringhe e byte separati.

Si prega di utilizzare il più possibile PDO con istruzioni parametrizzate.

Dove non puoi, usa almeno pg_query_params e dichiarazioni parametrizzate. addslashes di PHP non è un'alternativa, è inefficiente, brutto e non comprende le regole di escape specifiche del database. Devi ancora uscire manualmente da bytea se non stai usando PDO per sfiziosi motivi storici, ma tutto il resto dovrebbe passare attraverso istruzioni parametrizzate.

Per indicazioni su pg_query_params :

  • Tabelle Bobby, sezione PHP.
  • Il manuale PHP su pg_query_params