TL;DR:
Smažte addslashes($data)
. Tady je to nadbytečné.
Dvojité escapování .. dvakrát
$data=fread($p,filesize($fi));
$data=addslashes($data);
$dat= pg_escape_bytea($data);
Načtete data, uzavřete je, jako by to byl řetězcový literál, a poté je převedete na bajtové osmičkové nebo hex. Takto by to nikdy nemohlo fungovat, i kdyby pg_escape_bytea
byl příčetný, což není.
pg_escape_bytea
PHP vypadá jako dvojitý únik výstup, takže jej lze vložit do řetězcového literálu. To je neuvěřitelně ošklivé, ale nezdá se, že by existovala alternativa, která by toto dvojité escapování neprováděla, takže se zdá, že v PHP nemůžete používat parametrizované příkazy pro bytea. Stejně byste to měli udělat pro všechno ostatní.
V tomto případě jednoduše odstraňte addslashes
řádek pro data načtená ze souboru je dostačující.
Testovací případ ukazuje, že pg_escape_bytea
double-escapes (a vždy také používá staré, neefektivní oktalové escape):
<?php
# oh-the-horror.php
print pg_escape_bytea("Blah binary\x00\x01\x02\x03\x04 blah");
?>
Spustit:
php oh-the-horror.php
Výsledek:
Blah binary\\000\\001\\002\\003\\004 blah
Vidíte zdvojená zpětná lomítka? Je to proto, že se předpokládá, že jej budete interpolovat do SQL jako řetězec, což je extrémně paměťově neefektivní, ošklivé a velmi špatný zvyk. Zdá se však, že nemáte žádnou alternativu.
Mimo jiné to znamená, že:
pg_unescape_bytea(pg_escape_bytea("\x01\x02\x03"));
... vytváří nesprávný výsledek , protože pg_unescape_bytea
není ve skutečnosti opakem pg_escape_bytea
. Také to znemožňuje napájet výstup pg_escape_bytea
do pg_query_params
jako parametr jej musíte interpolovat.
Dekódování
Pokud používáte moderní PostgreSQL, pravděpodobně nastavuje bytea_output
na hex
ve výchozím stavu. To znamená, že když zapíšu svá data do bytea
pole a poté jej načtěte zpět, bude to vypadat nějak takto:
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, co," dalo by se říct? To je v pořádku, je to jen trochu kompaktnější hexová reprezentace bytea
PostgreSQL . pg_unescape_bytea
zvládne to dobře a vytvoří stejné nezpracované bajty jako výstup ... pokud máte moderní PHP a libpq
. Na starších verzích budete mít odpadky a budete muset nastavit bytea_output
k escape
pro pg_unescape_bytea
zvládnout to.
Co byste měli udělat místo toho
Použijte CHOP.
Má rozumnou podporu pro 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();
Viz:
- PHP:Velké objekty, které obsahují příklad toho, co přesně chcete;
- PDOStatement::bindParam
- jak uložit serializovaný objekt s jmenným prostorem v databázi pomocí pdo php
- Navázat BYTEA na PGSQL připravený příkaz PDO v PHP5
Můžete se také podívat na podporu lob (velký objekt) PostgreSQL, která poskytuje streamované rozhraní, které je stále plně transakční.
A teď k mé mýdlové krabičce
Pokud by PHP skutečně rozlišovalo mezi typy "byte string" a "text string", nepotřebovali byste ani pg_escape_bytea
jak by to za vás mohl udělat ovladač databáze. Nic z této ošklivosti by nebylo potřeba. Bohužel v PHP neexistují žádné samostatné typy řetězců a bajtů.
Prosím, používejte PDO s parametrizovanými příkazy co nejvíce.
Kde nemůžete, použijte alespoň pg_query_params
a parametrizované příkazy. addslashes
PHP není alternativou, je neefektivní, ošklivý a nerozumí pravidlům útěku specifickým pro databázi. Stále musíte ručně escapovat bytea
pokud nepoužíváte PDO z historických důvodů, ale vše ostatní by mělo projít parametrizovanými příkazy.
Pokyny k pg_query_params
:
- Tabulky Bobby, sekce PHP.
- Příručka PHP o
pg_query_params