TL;DR:
Löschen Sie addslashes($data)
. Es ist hier überflüssig.
Double-Escape .. zweimal
$data=fread($p,filesize($fi));
$data=addslashes($data);
$dat= pg_escape_bytea($data);
Sie lesen die Daten ein, maskieren sie, als wären sie ein String-Literal, und konvertieren sie dann in Bytea-Oktal- oder Hex-Escapes. So herum könnte es nie funktionieren, selbst wenn pg_escape_bytea
war vernünftig, was es nicht ist.
pg_escape_bytea
von PHP scheint doppelt zu entkommen die Ausgabe, damit sie in ein Zeichenfolgenliteral eingefügt werden kann. Das ist unglaublich hässlich, aber es scheint keine Alternative zu geben, die dieses Double-Escape nicht macht, also können Sie scheinbar keine parametrisierten Anweisungen für bytea in PHP verwenden. Für alles andere sollten Sie es trotzdem tun.
Entfernen Sie in diesem Fall einfach die addslashes
Zeile für die aus der Datei eingelesenen Daten genügt.
Testfall, der diesen pg_escape_bytea
zeigt Double-Escapes (und verwendet auch immer die alten, ineffizienten Oktal-Escapes):
<?php
# oh-the-horror.php
print pg_escape_bytea("Blah binary\x00\x01\x02\x03\x04 blah");
?>
Ausführen:
php oh-the-horror.php
Ergebnis:
Blah binary\\000\\001\\002\\003\\004 blah
Sehen Sie die doppelten Backslashes? Das liegt daran, dass davon ausgegangen wird, dass Sie es als Zeichenfolge in SQL interpolieren, was extrem speicherineffizient, hässlich und eine sehr schlechte Angewohnheit ist. Du scheinst aber keine Alternative zu bekommen.
Das bedeutet unter anderem:
pg_unescape_bytea(pg_escape_bytea("\x01\x02\x03"));
... liefert das falsche Ergebnis , seit pg_unescape_bytea
ist eigentlich nicht das Gegenteil von pg_escape_bytea
. Es macht es auch unmöglich, die Ausgabe von pg_escape_bytea
zu füttern in pg_query_params
als Parameter müssen Sie ihn interpolieren.
Decodierung
Wenn Sie ein modernes PostgreSQL verwenden, setzt es wahrscheinlich bytea_output
zu hex
standardmäßig. Das heißt, wenn ich meine Daten in ein bytea
schreibe Feld dann zurückholen, sieht es etwa so aus:
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)
"Ähm, was", könntest du sagen? Es ist in Ordnung, es ist nur PostgreSQLs etwas kompaktere Hex-Darstellung von bytea
. pg_unescape_bytea
wird damit gut umgehen und die gleichen rohen Bytes als Ausgabe erzeugen ... wenn Sie ein modernes PHP und libpq
haben . Bei älteren Versionen erhalten Sie Datenmüll und müssen bytea_output
setzen um escape
für pg_unescape_bytea
um damit umzugehen.
Was Sie stattdessen tun sollten
PDO verwenden.
Es hat vernünftige Unterstützung 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();
Siehe:
- PHP:Large Objects, das ein Beispiel für genau das hat, was Sie wollen;
- PDOStatement::bindParam
- wie man serialisierte Objekte mit Namespace in der Datenbank mit pdo php speichert
- Binden Sie BYTEA an die vorbereitete PGSQL-PDO-Anweisung in PHP5
Vielleicht möchten Sie auch einen Blick auf die lob (Large Object)-Unterstützung von PostgreSQL werfen, die eine durchsuchbare Streaming-Schnittstelle bietet, die immer noch vollständig transaktional ist.
Nun zu meiner Seifenkiste
Wenn PHP wirklich zwischen den Typen "Byte-String" und "Text-String" unterscheiden würde, bräuchten Sie nicht einmal pg_escape_bytea
wie der Datenbanktreiber es für Sie tun könnte. Nichts von dieser Hässlichkeit wäre erforderlich. Leider gibt es in PHP keine separaten String- und Byte-Typen.
Bitte verwenden Sie so viel wie möglich PDO mit parametrisierten Anweisungen.
Wo Sie es nicht können, verwenden Sie zumindest pg_query_params
und parametrisierte Anweisungen. PHPs addslashes
ist keine Alternative, es ist ineffizient, hässlich und versteht keine datenbankspezifischen Escape-Regeln. Sie müssen bytea
immer noch manuell maskieren wenn Sie PDO aus ekligen historischen Gründen nicht verwenden, aber alles andere durch parametrisierte Anweisungen gehen sollte.
Für Anleitungen zu pg_query_params
:
- Bobby-Tabellen, PHP-Abschnitt.
- Das PHP-Handbuch zu
pg_query_params