PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Przechowywanie obrazów w polach bajtowych w bazie danych PostgreSQL

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Znajdź rodzica rekurencyjnie za pomocą Query

  2. Plik ~/.psqlrc dla DBA

  3. Postgresql DROP TABLE nie działa

  4. Połącz wiele wierszy w tablicy za pomocą SQL na PostgreSQL

  5. Jak skonfigurować bazę danych PostgreSQL w Django