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