TL;DR:
Usuń addslashes($data)
. Tutaj jest zbędny.
Podwójna ucieczka .. dwa razy
$data=fread($p,filesize($fi));
$data=addslashes($data);
$dat= pg_escape_bytea($data);
Wczytujesz dane, zmieniasz je tak, jakby to był literał łańcuchowy, a następnie konwertujesz je na znaki ucieczki bajtów ósemkowych lub szesnastkowych. To nigdy nie mogłoby działać w ten sposób, nawet jeśli pg_escape_bytea
był zdrowy na umyśle, a tak nie jest.
pg_escape_bytea
PHP wydaje się, że podwójna ucieczka dane wyjściowe, aby można je było wstawić do literału ciągu. Jest to niewiarygodnie brzydkie, ale nie wydaje się, aby istniała alternatywa, która nie robiłaby podwójnej ucieczki, więc nie możesz używać sparametryzowanych instrukcji dla bytea w PHP. Nadal powinieneś to robić w przypadku wszystkiego innego.
W takim przypadku wystarczy usunąć addslashes
wystarczy wiersz dla danych wczytanych z pliku.
Przypadek testowy pokazujący, że pg_escape_bytea
podwójne znaki ucieczki (i zawsze używa również starych, nieefektywnych znaków ósemkowych):
<?php
# oh-the-horror.php
print pg_escape_bytea("Blah binary\x00\x01\x02\x03\x04 blah");
?>
Uruchom:
php oh-the-horror.php
Wynik:
Blah binary\\000\\001\\002\\003\\004 blah
Widzisz podwójne ukośniki odwrotne? Dzieje się tak, ponieważ zakłada, że zamierzasz interpolować go do SQL jako łańcuch, co jest wyjątkowo niewydajne pod względem pamięci, brzydkie i bardzo złym nawykiem. Jednak wydaje się, że nie masz alternatywy.
Oznacza to między innymi, że:
pg_unescape_bytea(pg_escape_bytea("\x01\x02\x03"));
... daje zły wynik , ponieważ pg_unescape_bytea
nie jest w rzeczywistości odwrotnością pg_escape_bytea
. Uniemożliwia również podawanie danych wyjściowych pg_escape_bytea
w pg_query_params
jako parametr, musisz go interpolować.
Dekodowanie
Jeśli używasz nowoczesnego PostgreSQL, prawdopodobnie ustawia bytea_output
na hex
domyślnie. Oznacza to, że jeśli zapiszę swoje dane do bytea
pole, a następnie pobierz je z powrotem, będzie wyglądać mniej więcej tak:
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)
„Um, co”, możesz powiedzieć? W porządku, to po prostu nieco bardziej zwarta szesnastkowa reprezentacja bytea
w PostgreSQL . pg_unescape_bytea
poradzi sobie z tym dobrze i wyprodukuje te same surowe bajty, co dane wyjściowe ... jeśli masz nowoczesne PHP i libpq
. W starszych wersjach otrzymasz śmieci i będziesz musiał ustawić bytea_output
aby escape
dla pg_unescape_bytea
by sobie z tym poradzić.
Co powinieneś zrobić zamiast tego
Użyj PDO.
Ma rozsądne (ish) wsparcie dla 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();
Zobacz:
- PHP:duże obiekty, który zawiera dokładnie to, czego chcesz;
- PDOstatement::bindParam
- jak przechowywać zserializowany obiekt z przestrzenią nazw w bazie danych za pomocą pdo php
- Powiąż BYTEA z przygotowaną instrukcją PGSQL PDO w PHP5
Możesz także zajrzeć do obsługi lob (dużych obiektów) PostgreSQL, która zapewnia strumieniowy, przeszukiwalny interfejs, który wciąż jest w pełni transakcyjny.
Teraz przejdźmy do mydelniczki
Gdyby PHP miało prawdziwe rozróżnienie między typami "ciągu bajtów" i "ciągu tekstu", nie potrzebowałbyś nawet pg_escape_bytea
ponieważ sterownik bazy danych może to zrobić za Ciebie. Żadna z tych brzydoty nie byłaby wymagana. Niestety, w PHP nie ma oddzielnych typów łańcuchów i bajtów.
Proszę, używaj PDO ze sparametryzowanymi instrukcjami tak często, jak to możliwe.
Tam, gdzie nie możesz, użyj przynajmniej pg_query_params
i sparametryzowanych instrukcji. addslashes
PHP nie jest alternatywą, jest nieefektywny, brzydki i nie rozumie reguł ucieczki specyficznych dla bazy danych. Nadal musisz ręcznie zmienić bytea
jeśli nie używasz PDO z nieprzyjemnych powodów historycznych, ale wszystko inne powinno przejść przez sparametryzowane instrukcje.
Wskazówki dotyczące pg_query_params
:
- Tabele Bobby'ego, sekcja PHP.
- Podręcznik PHP dotyczący
pg_query_params