PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Armazenando imagens em campos bytea em um banco de dados PostgreSQL

TL;DR:


Excluir addslashes($data) . É redundante aqui.

Escape duplo .. duas vezes

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

Você lê os dados, escapa como se fosse uma string literal e depois os converte em bytea octal ou escapes hexadecimais. Nunca poderia funcionar assim mesmo que pg_escape_bytea era são, o que não é.

pg_escape_bytea do PHP parece escape duplo a saída para que ela possa ser inserida em um literal de string. Isso é incrivelmente feio, mas não parece haver uma alternativa que não faça esse escape duplo, então você não pode usar instruções parametrizadas para bytea em PHP. Você ainda deve fazer isso para todo o resto.

Neste caso, basta remover as addslashes linha para os dados lidos do arquivo é suficiente.

Caso de teste mostrando que pg_escape_bytea escapes duplos (e sempre usa os antigos e ineficientes escapes octais também):
<?php
# oh-the-horror.php
print pg_escape_bytea("Blah binary\x00\x01\x02\x03\x04 blah");
?>

Correr:
php oh-the-horror.php

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

Veja as barras invertidas duplas? Isso porque supõe que você vai interpolar isso no SQL como uma string, o que é extremamente ineficiente em memória, feio e um hábito muito ruim. Você não parece ter nenhuma alternativa, no entanto.

Entre outras coisas, isso significa que:
pg_unescape_bytea(pg_escape_bytea("\x01\x02\x03"));

... produz o resultado errado , uma vez que pg_unescape_bytea na verdade não é o inverso de pg_escape_bytea . Também torna impossível alimentar a saída de pg_escape_bytea em pg_query_params como parâmetro, você deve interpolar.

Decodificação


Se você estiver usando um PostgreSQL moderno, ele provavelmente configura bytea_output para hex por padrão. Isso significa que se eu gravar meus dados em um bytea field e, em seguida, buscá-lo de volta, será algo assim:
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)

"Hum, o que", você pode dizer? Tudo bem, é apenas a representação hexadecimal um pouco mais compacta do PostgreSQL de bytea . pg_unescape_bytea irá lidar com isso bem e produzir os mesmos bytes brutos como saída ... se você tiver um PHP moderno e libpq . Em versões mais antigas, você receberá lixo e precisará definir bytea_output para escape para pg_unescape_bytea para lidar com isso.

O que você deve fazer em vez disso


Usar DOP.

Tem suporte 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:Large Objects, que tem um exemplo de exatamente o que você quer;
  • PDOStatement::bindParam
  • como armazenar objeto serializado com namespace no banco de dados usando pdo php
  • Vincule BYTEA à instrução preparada PGSQL PDO em PHP5

Você também pode querer dar uma olhada no suporte a lob (objeto grande) do PostgreSQL, que fornece uma interface de streaming e pesquisável que ainda é totalmente transacional.

Agora, vamos para minha caixa de sabão


Se o PHP tivesse uma distinção real entre os tipos "string de bytes" e "string de texto", você nem precisaria de pg_escape_bytea pois o driver do banco de dados pode fazer isso por você. Nada dessa feiúra seria necessário. Infelizmente, não existem tipos separados de string e bytes no PHP.

Por favor, use PDO com instruções parametrizadas tanto quanto possível.

Onde você não puder, pelo menos use pg_query_params e instruções parametrizadas. addslashes do PHP não é uma alternativa, é ineficiente, feio e não entende as regras de escape específicas do banco de dados. Você ainda precisa escapar manualmente de bytea se você não estiver usando o PDO por motivos históricos nojentos, mas todo o resto deve passar por instruções parametrizadas.

Para orientação sobre pg_query_params :
  • Tabelas Bobby, seção PHP.
  • O manual do PHP em pg_query_params