PHP + BLOB + Oracle – Wgrywanie danych do bazy, czyli upload obrazu lub innego pliku binarnego

Oracle udostępnia o wiele bardziej zaawansowane mechanizmy do współpracy ze swoją bazą niż MySQL. Jest to widoczne prawie na każdym kroku – również, gdy łączymy się z bazą Oracla za pomocą PHP. Ewidentnym na to przykładem jest upload plików binarnych do bazy z poziomu PHP. W MySQL niejako wklejamy plik do zapytania SQL. W Oracle nie jest to już takie oczywiste.

Poniższy kod jest zrealizowany w oparciu o bardzo prostą tabelę.

1
2
3
4
CREATE TABLE bloby (
	id NUMBER PRIMARY KEY,
	blob_col BLOB
)

Do przesłania pliku użyjemy również bardzo prostego formularza.

1
2
3
4
<form method="post" enctype="multipart/form-data">
	<input name="userfile" type="file">
	<input name="upload" type="submit" value="Upload">
</form>

Pierwsze co robimy to logujemy się do bazy.

1
2
3
4
5
6
$con = OCILogon("user","password");
	if (!$con) { 
		echo "ERROR: OCILogon"; 
		exit; 
	}
	echo "OK: OCILogon <br>";

W zależności od rezultatu logowania albo wyświetlany jest komunikat o błędzie i skrypt się kończy, albo wyświetlany jest komunikat o powodzeniu i skrypt leci dalej. Kolejna rzecz, którą musimy zrobić to utworzyć deskryptor dla naszego BLOBa. Deskryptor to obiekt klasy OCI-Lob, który służy do komunikacji między naszym skryptem, a polem typu BLOB.

7
$lob = oci_new_descriptor($con, OCI_D_LOB);

Deskryptorem zajmiemy się jeszcze zaraz, ale teraz wygenerujemy zapytanie SQL do bazy.

8
9
10
$sql = "INSERT INTO bloby (id, blob_col) VALUES(1, EMPTY_BLOB()) RETURNING blob_col INTO :BLOBDATA";
$stid = OCIParse($con, $sql);
oci_bind_by_name($stid, ":BLOBDATA", $lob, -1, OCI_B_BLOB);

Powyżej mamy trzy linijki. Pierwsza to treść zapytania. Nie wygląda to jednak jak typowe zapytanie typu INSERT. Użyta jest tu funkcja EMPTY_BLOB(), która inicjuje pole typu BLOB w naszej tabeli. Pola typu BLOB nie trzymają bezpośrednio danych, lecz tylko specjalny deskryptor opisujący, gdzie te dane są. Kiedy inicjujemy tą funkcją nasze pole, to tworzymy taki właśnie deskryptor. Jest też użyta klauzula RETURNING. Powoduje ona, że po wykonaniu INSERTa zostanie nam zwrócone to co w skutek wykonania tego INSERTa zostało wpisane do kolumny blob_col. Zwrócone nam to zostanie poprzez zmienną :BLOBDATA. Co to za zmienna, dowiemy się zaraz.

Druga linijka parsuje nam nasze zapytanie do postaci binarnej.

Trzecia linijka robi dużo tajemnej magii. Sprawia ona, że zmienna z naszego zapytania o nazwie :BLOBDATA zostanie nam przekazana przez zmienną $lob w naszym skrypcie PHP. Innymi słowy, utworzony przez bazę deskryptor pola BLOB posłuży do wypełnienia deskryptora ukrytego pod zmienną $lob.

11
12
13
14
15
16
$res = OCIExecute($stid, OCI_NO_AUTO_COMMIT);
	if (!$res) { 
		echo "ERROR: OCIExecute"; 
		exit; 
	}
	echo "OK: OCIExecute <br>";

Powyżej wykonujemy zapytanie. Ważny jest tutaj drugi parametr, który przekazujemy do tej funkcji, gdyż bez niego nie uda nam się przesłać większych plików do bazy.

17
18
19
20
21
22
$save = $lob->savefile($_FILES['userfile']['tmp_name']);
	if (!$save) { 
		echo "ERROR: savefile"; 
		exit; 
	}
	echo "OK: OCIExecute <br>";

Powyżej użyliśmy naszego deskryptora, aby przesłać dane do BLOBa. Podajemy tutaj tylko ściężkę do pliku. W tym przypadku, ścieżka pochodzi ze zwykłego formularza.

23
oci_commit($con);

Na koniec potwierdzamy zapytanie. I już.