sql >> Database >  >> RDS >> PostgreSQL

Afbeeldingen opslaan in bytea-velden in een PostgreSQL-database

TL;DR:

Verwijder addslashes($data) . Het is hier overbodig.

Dubbele ontsnapping .. twee keer

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

U leest de gegevens in, ontsnapt eraan alsof het een letterlijke tekenreeks is en converteert het vervolgens naar bytea octaal of hex-escapes. Het zou nooit zo kunnen werken, zelfs als pg_escape_bytea gezond was, wat het niet is.

PHP's pg_escape_bytea lijkt te dubbele escape de uitvoer zodat deze letterlijk in een tekenreeks kan worden ingevoegd. Dit is ongelooflijk lelijk, maar er lijkt geen alternatief te zijn dat deze dubbele escape niet doet, dus het lijkt erop dat je geen geparametriseerde instructies voor bytea in PHP kunt gebruiken. Je moet dit nog steeds doen voor al het andere.

In dit geval verwijdert u gewoon de addslashes regel voor de ingelezen gegevens uit het bestand is voldoende.

Testcase die aantoont dat pg_escape_bytea dubbele ontsnappingen (en gebruikt ook altijd de oude, inefficiënte octale ontsnappingen):

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

Uitvoeren:

php oh-the-horror.php

Resultaat:

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

Zie je de dubbele backslashes? Dat komt omdat het ervan uitgaat dat je het als een tekenreeks in SQL gaat interpoleren, wat extreem geheugeninefficiënt, lelijk en een zeer slechte gewoonte is. Je lijkt echter geen alternatief te krijgen.

Dit betekent onder meer dat:

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

... geeft het verkeerde resultaat , sinds pg_unescape_bytea is eigenlijk niet het omgekeerde van pg_escape_bytea . Het maakt het ook onmogelijk om de uitvoer van pg_escape_bytea . te voeren in pg_query_params als parameter moet je het in interpoleren.

Decodering

Als je een moderne PostgreSQL gebruikt, zet deze waarschijnlijk bytea_output naar hex standaard. Dat betekent dat als ik mijn gegevens schrijf naar een bytea veld en haal het dan terug, het ziet er ongeveer zo uit:

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)

"Eh, wat", zou je misschien zeggen? Het is prima, het is gewoon PostgreSQL's iets compactere hex-representatie van bytea . pg_unescape_bytea zal het prima afhandelen en dezelfde onbewerkte bytes produceren als uitvoer ... als je een moderne PHP en libpq hebt . Op oudere versies krijg je rotzooi en moet je bytea_output . instellen om te escape voor pg_unescape_bytea om ermee om te gaan.

Wat u in plaats daarvan moet doen

Gebruik BOB.

Het heeft gezonde (ish) ondersteuning voor 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();

Zie:

  • PHP:grote objecten, met een voorbeeld van precies wat je wilt;
  • PDOStatement::bindParam
  • hoe een geserialiseerd object met naamruimte in de database op te slaan met pdo php
  • Bind BYTEA aan PGSQL PDO opgestelde verklaring in PHP5

Misschien wilt u ook kijken naar de lob-ondersteuning (groot object) van PostgreSQL, die een streaming-, doorzoekbare interface biedt die nog steeds volledig transactioneel is.

Nu, op naar mijn zeepkist

Als PHP een echt onderscheid zou maken tussen de typen "byte string" en "text string", zou je pg_escape_bytea niet eens nodig hebben aangezien het databasestuurprogramma het voor u zou kunnen doen. Al deze lelijkheid zou niet nodig zijn. Helaas zijn er geen aparte typen strings en bytes in PHP.

Gebruik alstublieft zoveel mogelijk PDO met geparametriseerde statements.

Waar dat niet kan, gebruik in ieder geval pg_query_params en geparametriseerde statements. PHP's addslashes is geen alternatief, het is inefficiënt, lelijk en begrijpt geen database-specifieke ontsnappingsregels. Je moet nog steeds handmatig ontsnappen aan bytea als je PDO om icky historische redenen niet gebruikt, maar al het andere moet via geparametriseerde instructies gaan.

Voor hulp bij pg_query_params :

  • Bobby-tabellen, PHP-sectie.
  • De PHP-handleiding op pg_query_params


  1. 30 dagen van een datum aftrekken in T-SQL

  2. Oracle:Bereken tijdsverschil in UU:MM:SS tussen 2 datums

  3. SQL Server Prestaties TOP IO Query -1

  4. PLSQL JDBC:Hoe krijg ik de laatste rij-ID?