sql >> Databasteknik >  >> RDS >> PostgreSQL

Lagra bilder i bytea-fält i en PostgreSQL-databas

TL;DR:

Ta bort addslashes($data) . Det är överflödigt här.

Dubbel-escape .. två gånger

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

Du läser in data, escaper den som om den vore en strängliteral och konverterar den sedan till bytea octal eller hex escapes. Det skulle aldrig fungera på det sättet även om pg_escape_bytea var förnuftig, vilket den inte är.

PHPs pg_escape_bytea verkar dubbel-escape utgången så att den kan infogas i en bokstavlig sträng. Det här är otroligt fult, men det verkar inte finnas ett alternativ som inte gör det här dubbelflykten, så du kan inte använda parametriserade satser för bytea i PHP. Du bör fortfarande göra det för allt annat.

I det här fallet tar du helt enkelt bort addslashes rad för data som läses in från filen räcker.

Testfall som visar att pg_escape_bytea double-escapes (och använder alltid de gamla, ineffektiva oktala escapesna också):

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

Kör:

php oh-the-horror.php

Resultat:

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

Ser du de dubbla snedstrecket? Det beror på att det antar att du kommer att interpolera det i SQL som en sträng, vilket är extremt minnesineffektivt, fult och en mycket dålig vana. Du verkar dock inte få något alternativ.

Detta innebär bland annat att:

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

... ger fel resultat , eftersom pg_unescape_bytea är faktiskt inte motsatsen till pg_escape_bytea . Det gör det också omöjligt att mata utdata från pg_escape_bytea till pg_query_params som en parameter måste du interpolera den i.

Avkodning

Om du använder en modern PostgreSQL ställer den förmodligen in bytea_output till hex som standard. Det betyder att om jag skriver mina data till en bytea fältet och hämta det sedan, kommer det att se ut ungefär så här:

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)

"Ehm, vad", kan du säga? Det är bra, det är bara PostgreSQL:s lite mer kompakta hex-representation av bytea . pg_unescape_bytea kommer att hantera det bra och producera samma råbyte som utdata ... om du har en modern PHP och libpq . På äldre versioner får du skräp och måste ställa in bytea_output för att escape för pg_unescape_bytea att hantera det.

Vad du bör göra istället

Använd PDO.

Den har sane(ish) stöd för 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();

Se:

  • PHP:Stora objekt, som har ett exempel på exakt vad du vill ha;
  • PDOStatement::bindParam
  • hur man lagrar serialiserade objekt med namnutrymme i databasen med pdo php
  • Bind BYTEA till PGSQL PDO Prepared Statement i PHP5

Du kanske också vill titta in på PostgreSQL:s lob-stöd (stora objekt), som ger ett strömmande, sökbart gränssnitt som fortfarande är helt transaktionsbaserat.

Nu, vidare till min tvållåda

Om PHP hade en verklig skillnad mellan "byte string" och "text string" typer, skulle du inte ens behöva pg_escape_bytea eftersom databasdrivrutinen kan göra det åt dig. Inget av denna fulhet skulle krävas. Tyvärr finns det inga separata sträng- och bytetyper i PHP.

Vänligen använd PDO med parametriserade satser så mycket som möjligt.

Där du inte kan, använd åtminstone pg_query_params och parametriserade uttalanden. PHPs addslashes är inte ett alternativ, det är ineffektivt, fult och förstår inte databasspecifika escape-regler. Du måste fortfarande escape bytea manuellt om du inte använder PDO av svåra historiska skäl, men allt annat bör gå igenom parametriserade uttalanden.

För vägledning om pg_query_params :

  • Bobby-tabeller, PHP-sektion.
  • PHP-manualen på pg_query_params


  1. MySQL 5.6 EOL-meddelande

  2. Returnera alla möjliga kombinationer av värden på kolumner i SQL

  3. Lägg till en länkad serverinloggning i SQL Server (T-SQL-exempel)

  4. Databasbelastningsbalansering:distribuerade vs centraliserade inställningar