TL;DR:
Slet addslashes($data)
. Det er overflødigt her.
Dobbelt-escape .. to gange
$data=fread($p,filesize($fi));
$data=addslashes($data);
$dat= pg_escape_bytea($data);
Du læser dataene ind, undslipper dem, som om det var en streng-literal, og konverterer dem derefter til bytea octal eller hex-escapes. Det kunne aldrig fungere på den måde, selvom pg_escape_bytea
var fornuftig, hvilket den ikke er.
PHP's pg_escape_bytea
ser ud til at dobbelt-escape outputtet, så det kan indsættes i en streng literal. Dette er utroligt grimt, men der ser ikke ud til at være et alternativ, der ikke gør dette dobbelt-escape, så du kan tilsyneladende ikke bruge parametriserede sætninger til bytea i PHP. Du bør stadig gøre det for alt andet.
I dette tilfælde skal du blot fjerne addslashes
linje for data læst ind fra filen er tilstrækkelig.
Testcase, der viser, at pg_escape_bytea
double-escapes (og bruger også altid de gamle, ineffektive oktale escapes):
<?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 fordoblede skråstreger? Det er fordi det antager, at du vil interpolere det i SQL som en streng, hvilket er ekstremt hukommelsesineffektivt, grimt og en meget dårlig vane. Du ser dog ikke ud til at få noget alternativ.
Det betyder blandt andet, at:
pg_unescape_bytea(pg_escape_bytea("\x01\x02\x03"));
... giver det forkerte resultat , da pg_unescape_bytea
er faktisk ikke det modsatte af pg_escape_bytea
. Det gør det også umuligt at feed output fra pg_escape_bytea
ind i pg_query_params
som en parameter skal du interpolere den i.
Afkodning
Hvis du bruger en moderne PostgreSQL, sætter den sandsynligvis bytea_output
til hex
som standard. Det betyder, at hvis jeg skriver mine data til en bytea
feltet og hent det tilbage, vil det se nogenlunde sådan her ud:
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)
"Øh, hvad", siger du måske? Det er fint, det er bare PostgreSQL's lidt mere kompakte hex-repræsentation af bytea
. pg_unescape_bytea
vil håndtere det fint og producere de samme rå bytes som output ... hvis du har en moderne PHP og libpq
. På ældre versioner vil du få skrald og skal indstille bytea_output
for at escape
for pg_unescape_bytea
at håndtere det.
Hvad du bør gøre i stedet
Brug PDO.
Det har sane(ish) understøttelse af 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:Store objekter, som har et eksempel på præcis, hvad du vil have;
- PDOStatement::bindParam
- hvordan man gemmer serialiseret objekt med navneområde i databasen ved hjælp af pdo php
- Bind BYTEA til PGSQL PDO-forberedt erklæring i PHP5
Du vil måske også kigge ind på PostgreSQL's lob-understøttelse (stort objekt), som giver en streaming, søgbar grænseflade, der stadig er fuldt transaktionel.
Nu, videre til min sæbeboks
Hvis PHP havde en reel forskel mellem "byte string" og "text string" typer, ville du ikke engang have brug for pg_escape_bytea
da databasedriveren kunne gøre det for dig. Intet af denne grimhed ville være påkrævet. Desværre er der ingen separate streng- og bytetyper i PHP.
Brug venligst PDO med parametriserede udsagn så meget som muligt.
Hvor du ikke kan, brug i det mindste pg_query_params
og parametriserede udsagn. PHP's addslashes
er ikke et alternativ, det er ineffektivt, grimt og forstår ikke databasespecifikke escape-regler. Du skal stadig escape bytea
manuelt hvis du ikke bruger PDO af irrelevante historiske årsager, men alt andet skal gå gennem parametriserede udsagn.
For vejledning om pg_query_params
:
- Bobby-tabeller, PHP-sektion.
- PHP-manualen på
pg_query_params