[Postgres][PHP] Jak zapisać i potem odczytać grafikę lub dowolny plik w bazie danych?
Chcesz stworzyć tabelę, w której będą przechowywane pliki binarne, a więc grafiki, dźwięki, filmy, etc.
Zdecydowanie nie polecam upychania w bazie danych dużych plików, ponieważ można je umieścić w osobnym katalogu, a w bazie dodać tylko ścieżki do nich. Natomiast są sytuacje, gdy pliki musisz dodać. Nie jest to zadanie intuicyjne dla niedoświadczonego administratora bazy. Nie znaczy jednak, że dodawanie plików jest kłopotliwe.
Stwórzmy sobie prostą bazę, do której dodamy grafikę. Niech baza nazywa się baza1, a tabela ma nazwę tabela1. Tabela na nasze potrzeby składa się z dwóch pól:
CREATE TABLE tabela1 (numer int, plik oid);
Pole numer może mieć unikalny numer rysunku, a pole plik typu oid będzie zawierało plik. Typ oid reprezentuje identyfikator obiektu, ponieważ pliki zapisywane są w obiektach, a pole przechowuje numer tego obiektu w bazie.
Ok, jeżeli mamy już tabelę, czas wrzucić do niej jakąś grafikę:
<?
$plik = "grafika.gif";
$f = fopen($plik,"r");
$zawartosc = fread($f,filesize($plik));
fclose($f);
$baza = pg_connect("dbname=baza1 port=5432 user=nazwa");
$wynik = pg_Exec($baza, "BEGIN");
$oid = pg_lo_create($baza);
$wynik = pg_Exec($baza, "INSERT INTO tabela1 VALUES (10, $oid);");
$h = pg_lo_open($baza, $oid, "w");
pg_lo_write($h, $zawartosc);
pg_lo_close($h);
$wynik = pg_Exec($baza, "COMMIT");
pg_close($baza);
?>
Przede wszystkim musisz pobrać zawartość pliku i umieścić go w całości w zmiennej $zawartosc - operacja prosta i standardowa, polegająca na odczytaniu zawartości pliku o określonym rozmiarze, który pobieramy za pomocą funkcji filesize().
Następnie łączymy się z bazą i w obrębie jednej transakcji zaczynającej się od słowa kluczowego BEGIN, a kończącej na COMMIT wykonujemy operację dodania obiektu.
Następnie tworzymy identyfikator obiektu $oid za pomocą funkcji pg_lo_create(), wstawiamy go do tabeli, a następnie otwieramy obiekt do zapisu funkcją pg_lo_open(). Funkcja pg_lo_write() zapisuje do obiektu naszą zawartość (czyli obrazek) i możemy już zamknąć połączenie z obiektem i bazą. Plik został pomyślnie włączony do tabeli.
Gdy teraz sprawdzisz zawartość tabeli otrzymasz:
baza1=# select * from tabela1;
numer | plik
-------+-------
10 | 25334
(1 row)
Jak widzisz, w polu plik znajduje się nasz identyfikator obiektu. Umiesz już zapisać plik do bazy, czas aby go odczytać...
<?
$baza = pg_connect("dbname=baza1 port=5432 user=nazwa");
$wynik = pg_Exec($baza, "SELECT plik FROM tabela1 WHERE numer=10;");
$pole = pg_fetch_row($wynik, 0);
$wynik = pg_Exec($baza, "BEGIN");
$h = pg_lo_open($baza, $pole[0], "r");
header("Content-type: image/gif");
pg_lo_read_all($h);
pg_lo_close($h);
$wynik = pg_Exec($baza, "COMMIT");
pg_close($baza);
exit;
?>
Zasada jest bardzo podobna do zwykłego pobierania rekordów, z tą różnicą, że tutaj też należy odczytywać dane w transakcji (BEGIN/COMMIT) i po odczytaniu wartości pola typu oid nawiązywane jest połączenie z obiektem (tym razem do odczytu "r").
Po otworzeniu obiektu pobierany jest w całości funkcją pg_lo_read_all() i od razu wysyłany na standardowe wyjście. Stąd potrzebne jest określenie jakiego typu plik będzie pokazany na ekranie. Typ MIME Content-type: image/gif określa pliki GIF.
Ponieważ nic poza grafiką nie może pojawić się na ekranie (jest to plik binarny), najlepiej odczyt wykonać w osobnym pliku, który zwróci tylko obrazek. Można go wywołać np. tak: <img src="plik.php?nrgrafiki=10"> i potem parametr nrgrafiki wykorzystać przy wyciąganiu określonej grafiki z bazy danych.