Przechowywanie zdjęć w bazie danych
Uwagi wstępne:
To jest mój pierwszy artykuł, więc proszę o wyrozumiałość.
Celem artykułu jest zademonstrowanie, jak przechowywać zdjęcia w bazie MySQL, dlatego też cały tekst koncentruje się tylko i wyłącznie na tym zadaniu. Dla większej przejrzystości tekstu, zamieszczone fragmenty kodu koncentrują się wyłącznie na tym zagadnieniu. Należy mieć na uwadze, że zamieszczony kod co prawda będzie działał, ale nie jest on kompletny, ani optymalny. Może zawierać uchybienia dotyczące bezpieczeństwa, zaś generowane przez niego dokumenty nie zawsze będą zgodne z normami.
Pisząc ten tekst, przyjąłem, że Czytelnik zna podstawy PHP i wie, jak komunikować się z bazą danych
Wstęp
Podstawową cechą stron generowanych dynamicznie jest ich interaktywność – użytkownicy mają wpływ na treści dostępne na stronie, a często wręcz są ich twórcami. „Twórczość” użytkowników trzeba w jakiś sposób przechowywać po stronie serwera – teoretycznie można to robić, operując na plikach, znacznie wygodniejsze do tego celu są jednak bazy danych.
Tradycyjnie, w BD przechowywane są dane tekstowe, lub pokrewne. Niemal zawsze dotyczy to bardzo niewielkich porcji danych, często liczonych w pojedynczych bajtach. Można jednak w nich przechowywać także duże ilości binarnych danych.
1. Konstrukcja tablicy bazodanowej:
Potrzebna nam będzie najprostsza tabela, w której możemy przechowywać dane binarne. Do tego celu stosujemy typy danych BLOB. Dostępne są typy:
BLOB, MEDIUMBLOB, TINYBLOB i LONGBLOB. Różnią się między sobą maksymalną długością - dokładne wielkości każdego z nich znajdziesz w dokumentacji bazy. My użyjemy typu MEDIUMBLOB. Aby zdjęcia rozróżniać między sobą, dodamy jeszcze pole id typu INTEGER - będzie to klucz główny naszej tablicy. Dla uproszczenia kodu PHP, pole to będzie miało atrybut AUTO_INCREMENT.Definicja naszej tablicy wygląda następująco:
CREATE TABLE zdjecia (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
zdjecie MEDIUMBLOB NOT NULL
)
id INTEGER AUTO_INCREMENT PRIMARY KEY,
zdjecie MEDIUMBLOB NOT NULL
)
2. Formularz HTML - dodawanie zdjęcia do bazy - plik dodawajka.php:
Tutaj wszelkie komentarze są chyba zbędne. Pierwszy plik, jaki utworzymy, będzie po prostu statycznym formularzem. (Patrz uwagi u góry strony!)
plik: dodawajka.php
<FORM ACTION="upload.php" METHOD="POST" ENCTYPE="multipart/form-data">
Zdjęcie: </td><td><INPUT type="file" name="zdjecie">
<input type="submit" name="ok" value="Wyślij zdjęcie do bazy"/>
</FORM>
Zdjęcie: </td><td><INPUT type="file" name="zdjecie">
<input type="submit" name="ok" value="Wyślij zdjęcie do bazy"/>
</FORM>
3. Dodawanie pliku do bazy - plik upload.php:
Zaczynamy od połączenia z bazą:
<?
$uzytkownik = "user"; //
$haslo = "pass"; // Rzecz jasna wszystkie te dane zależą od naszej konkretnej bazy!
$db_name = "base"; //
$adres = "localhost"; //
$link = mysql_connect( $adres, $uzytkownik, $haslo);
mysql_select_db($db_name);
$uzytkownik = "user"; //
$haslo = "pass"; // Rzecz jasna wszystkie te dane zależą od naszej konkretnej bazy!
$db_name = "base"; //
$adres = "localhost"; //
$link = mysql_connect( $adres, $uzytkownik, $haslo);
mysql_select_db($db_name);
Następnie musimy otworzyć do odczytu plik, który nadesłał nam Użytkownik. Jego zawartość zawartość zapisujemy w zmiennej $content:
$fhandle = fopen($_FILES['zdjecie']['tmp_name'], "r");
$content = base64_encode(fread($fhandle, $_FILES['zdjecie']['size']));
fclose($fhandle);
$content = base64_encode(fread($fhandle, $_FILES['zdjecie']['size']));
fclose($fhandle);
I wreszcie - właściwe dodanie danych do bazy:
Na koniec - informujemy użytkownika, jaki adres ma jego zdjęcie. Oczywiście w miejsce ADRES_STRONY wstawiamy jej adres. Plik showimage.php stworzymy później.
$adres = "ADRES_STRONY/showimage.php?id=".mysql_insert_id()
echo "Twoje zdjęcie otrzymało adres: <br/>".$adres;
echo "Twoje zdjęcie otrzymało adres: <br/>".$adres;
Oraz - aby upewnić się, że wszystko przebiegło poprawnie (a przy okazji zademonstrować, jak to zrobić) - wyświetlamy właśnie dodane zdjęcie:
4. Wyświetlanie zdjęcia - plik showimage.php
Przede wszystkim - chcemy, aby ten plik był traktowany przez przeglądarkę, jak zdjęcie. Musi mieć więc właściwy nagłówek:
Zaczynamy od połączenia z bazą i zadania zapytania:
$uzytkownik = "user"; //
$haslo = "pass"; // Rzecz jasna wszystkie te dane zależą od naszej konkretnej bazy!
$db_name = "base"; //
$adres = "localhost"; //
$link = mysql_connect( $adres, $uzytkownik, $haslo);
mysql_select_db($db);
$result = mysql_query("SELECT zdjecie FROM zdjecia WHERE id=".$_GET['id']);
$haslo = "pass"; // Rzecz jasna wszystkie te dane zależą od naszej konkretnej bazy!
$db_name = "base"; //
$adres = "localhost"; //
$link = mysql_connect( $adres, $uzytkownik, $haslo);
mysql_select_db($db);
$result = mysql_query("SELECT zdjecie FROM zdjecia WHERE id=".$_GET['id']);
Następnie - po upewnieniu się, że cokolwiek w bazie zostało znalezione - wyciągamy z wyniku zapytania jedyny wiersz, i wyświetlamy go... A właściwie - wysyłamy użytkownikowi.
if (mysql_num_rows($result) != 0)
{
$row = mysql_fetch_assoc($result);
echo base64_decode($row['zdjecie']);
}
{
$row = mysql_fetch_assoc($result);
echo base64_decode($row['zdjecie']);
}
5. Uzupełnienie serwisu:
Rzecz właściwie nie mająca już związku z tematem, ale będąca ładnym uzupełnieniem całości - w głównym katalogu na serwerze w pliku .htaccess dopisujemy regułę:
RewriteEngine On
RewriteRule ^photo([0-9][0-9][0-9]).jpg showimage.php?id=$1
RewriteRule ^photo([0-9][0-9][0-9]).jpg showimage.php?id=$1
W ten sposób w pełni będziemy udawać, że nasze zdjęcia są prawdziwymi .jpgami, a nie są generowane dynamicznie. Taka reguła sprawi, że adres NASZASTRONA/photo123.jpg będzie przez serwer interpretowany tak samo, jak adres NASZASTRONA/showimage.php?id=123.



Jak daje sekcje header z jpg to mam wysyp znaków
jak dam gifa to wyskakuje okienko z pytaniem czy zapisać czy nie.- wyświetla się owszem ale małe okienko z czerwonym x coś nie tak z tym skryptem może ktoś pomoże
Jednakże konstrukcja:
$result = mysql_query("SELECT zdjecie FROM zdjecia WHERE id=".$_GET['id']);
daje duże możliwości nieautoryzowanego dostępu nawet do innych tabel w bazie. Proponuje zmienną id przechowywać w postaci zmienne liczbowej (konwertować ją z $_GET['id'] na liczbę).
mysql_select_db($db, $link);
dać:
mysql_select_db($db);
I nie bardzo rozumiem, po co tutaj ten sprintf:
oraz po co w ogóle zmienna $query (przecież nic z nią nie robimy):
$zapytanie = mysql_query("INSERT INTO zdjecia (zdjecie) VALUES (\"".$content."\")";
Tablice $HTTP_cośtam faktycznie są przestarzałe - zaraz to zmienię.
Co do obsługi plików - po prostu przyzwyczajony jestem z języka C, że się to robi tak, a nie inaczej. Pewnie inaczej się da - ale chyba fopen() i fread() nie są nieprawidłowe?
Ponadto mysql_query musi przyjąć jako drugi parametr: $link oraz zamiast $HTTP_POST_FILES należy używać $_FILES i zamiast $HTTP_GET_VARS - $_GET. Nie rozumiem też, po co tutaj zmienna $query? I zamiast fopen, fread, fclose, myślę, że wystarczy file_get_contents: