Zadziwiająco wielu ludzi ma problemy z tworzeniem galerii zdjęć w PHP. Postanowiłem wyjść im naprzeciw i dostarczyć ten oto artykuł. Odpowie on na pytania:
Jak tworzyć miniaturki?
Jak wyświetlać obrazki?
Jak stworzyć system nawigacji "Poprzedni/Następny"
Zapraszam do lektury.
Nasza galeria oparta będzie o bazę danych MySQL. Przechowywać będziemy w niej dane o aktualnie trzymanych w galerii obrazkach. Cały skrypt zmieścimy w trzech plikach. Pierwszy z nich,
gallery.php, posłuży nam do prezentowania galerii internautom.
convert.php będzie produkować miniaturki, a
layout.php przechowa kod HTML. Po tym krótkim wstępie... bierzemy się do pracy :).
Tradycyjnie zaczniemy od bazy danych. Oto źródła tabeli:
CREATE TABLE `galeria` (
`id` int(8) NOT NULL auto_increment,
`zdjecie` varchar(32) NOT NULL default '',
`opis` varchar(255) NOT NULL default '',
PRIMARY KEY (`id`)
) TYPE=MyISAM; |
Pierwsze pole to ID elementu, drugie - nazwa pliku ze zdjęciem, a trzecie jest jego opisem. Więcej pól na razie nam nie potrzeba. Dodadzą je sobie już sami czytelnicy w zależności od potrzeb.
Obrazki nie są przechowywane w bazie, gdyż jest to metoda wysoce nieefektywna. Musielibyśmy się bawić polami binarnymi i samodzielnie wyciągać dane z bazy, a to odbiłoby się na szybkości działania skryptu. Stąd też wybrałem najprostszy sposób - pliki przechowywane zwyczajnie na dysku twardym.
Plik
layout.php zawiera sam kod galerii, więc nie będziemy poświęcać mu zbyt dużo uwagi:
<?php
function lay_header($title){
echo <<<XXX
<html>
<head>
<title>{$title}</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2"/>
</head>
<body>
XXX;
} // end lay_header();
function lay_footer(){
echo <<<XXX
<p align="center">(c) Zyx, Webcity.pl</p>
</body>
</html>
XXX;
} // end lay_footer();
function lay_list_begin(){
echo <<<XXX
<table border="0">
<tr>
<td>Miniaturka</td>
<td>Opis</td>
</tr>
XXX;
} // end lay_list_begin();
function lay_list_element($id, $name, $desc, $dir){
echo <<<XXX
<tr>
<td><a href="gallery.php?cmd=show&id={$id}"><img src="{$dir}{$name}"/></a></td>
<td>{$desc}</td>
</tr>
XXX;
} // end lay_list_begin();
function lay_list_end(){
echo <<<XXX
</table>
XXX;
} // end lay_list_end();
function lay_photo($prev, $next, $name, $desc, $dir){
echo <<<XXX
<table border="0">
<tr>
<td align="left">{$prev}</td>
<td align="right">{$next}</td>
</tr>
<tr>
<td colspan="2"><img src="{$dir}{$name}"/></td>
</tr>
<tr>
<td colspan="2">{$desc}</td>
</tr>
</table>
XXX;
} // end lay_photo();
?> |
Skupmy się teraz na kodzie samego
gallery.php. Na początek definiujemy dwie stałe zawierające ścieżki do pełnowymiarowych obrazów oraz ich miniaturek. Ponadto załadujemy tutaj poprzednio stworzony plik oraz połączymy się z bazą danych.
<?php
define('BIG_DIR', './img/big/');
define('SMALL_DIR', './img/small/');
require('layout.php');
mysql_connect('localhost', 'root', '');
mysql_select_db('moja_kurde_baza'); |
Teraz zabierzmy się za obsługę akcji. Będą ich dwie - "show", pokazująca pojedynczy obrazek, oraz domyślna wyświetlająca listę miniaturek.
switch($_GET['cmd']){
case 'show':
$r = mysql_query('SELECT zdjecie, opis FROM galeria WHERE id=\''.mysql_real_escape_string($_GET['id']).'\'');
if(!($row = mysql_fetch_row($r))){
die('Brak podanego zdjęcia!');
}
$r = mysql_query('SELECT MAX(id) FROM galeria WHERE id < \''.mysql_real_escape_string($_GET['id']).'\'');
$prev = mysql_fetch_row($r);
if($prev[0] != ''){
$prev = '<a href="gallery.php?cmd=show&id='.$prev[0].'">Poprzedni</a>';
}else{
$prev = '';
}
$r = mysql_query('SELECT MIN(id) FROM galeria WHERE id > \''.mysql_real_escape_string($_GET['id']).'\'');
$next = mysql_fetch_row($r);
if($next[0] != ''){
$next = '<a href="gallery.php?cmd=show&id='.$next[0].'">Następny</a>';
}else{
$next = '';
}
lay_header('Podgląd zdjęcia');
lay_photo($prev, $next, $row[0], $row[1], BIG_DIR);
break; |
Najpierw pobieramy informacje o samym zdjęciu. Następnie skrypt zabiera się za generowanie linków "Poprzedni" oraz "Następny". Wbrew pozorom, uzyskanie ID poprzedniego i następnego rekordu jest bardzo proste. Pokażę to na przykładzie pierwszego linka ("Poprzedni"). Klauzulą
WHERE zawężam obszar poszukiwań do rekordów mających ID mniejsze od ID aktualnego zdjęcia. Na tak ograniczonym zbiorze wywołuję funkcję
MAX(id), która zwróci mi największy znajdujący się w nim ID. Jako, że identyfikatory są zawsze posortowane, oznacza to, że dostanę ID poprzedniego elementu. Podobnie jest z linkiem "Następny", tyle że robimy na odwrót: dajemy elementy większe i funkcję
MIN(id).
Wyświetlanie listy miniaturek nie wymaga chyba szczegółowego omawiania.
default:
lay_header('Galeria');
$r = mysql_query('SELECT id, zdjecie, opis FROM galeria ORDER BY id');
lay_list_begin();
while($row = mysql_fetch_row($r)){
lay_list_element($row[0], $row[1], $row[2], SMALL_DIR);
}
lay_list_end();
}
lay_footer();
mysql_close();
?> |
Produkcja miniaturek
Do produkcji miniaturek użyjemy biblioteki GD w wersji 2. Pozwala ona na manipulację obrazami. Niestety nasz konwerter nie będzie obsługiwać formatu GIF w powodu braku obsługi takowego w ww. bibliotece (problemy patentowe).
Zaczniemy od detekcji formatu, w jakim zapisany jest oryginalny plik. Potrzebujemy tego do załadowania pliku do pamięci komputera:
<?php
if(strpos($_GET['nazwa'], '.jpg') !== FALSE){
$img = imagecreatefromjpeg('./img/big/'.$_GET['nazwa']);
$format = 0;
}elseif(strpos($_GET['nazwa'],'.png') !== FALSE){
$img = imagecreatefrompng('./img/big/'.$_GET['nazwa']);
$format = 1;
}else{
die('Format nieobsługiwany');
} |
Kolejnym krokiem będzie zestaw obliczeń matematycznych, dzięki którym w miniaturce zostanie zachowany odpowiedni stosunek długości do szerokości obrazka.
// Wymiarowanie rysunku
$x = imagesx($img);
$y = imagesy($img);
if($x > $y){
$nx = 200;
$ny = 200 * ($y / $x);
}elseif($x < $y){
$nx = 200 * ($x / $y);
$ny = 200;
}else{
$nx = 200;
$ny = 200;
} |
Za podstawowy rozmiar pliku przyjąłem 200 pikseli. Jest on przypisywany zawsze dłuższemu bokowi. Do krótszego natomiast przypisujemy rozmiar podstawowy pomnożony przez ww. stosunek obliczany z wzoru:
krótszy bok / dłuższy bok. Uzyskane dane podstawiamy do funkcji
imagecopyresampled(), która wprowadzi nam zmiany do zdjęcia.
$new_img = imagecreatetruecolor($nx, $ny);
imagecopyresampled($new_img, $img, 0, 0, 0, 0, $nx, $ny, $x, $y); |
Funkcja ta nie operuje na tym samym obrazie - przeskalowane zdjęcie musi zostać zapisane w nowym miejscu, które stworzyliśmy wcześniej funkcją
imagecreatetruecolor(). Utworzoną miniaturkę zapisujemy na twardy dysk:
if($format == 0){
imagejpeg($new_img, './img/small/'.$_GET['nazwa'], 9);
}else{
imagepng($new_img, './img/small/'.$_GET['nazwa']);
}
?> |
Skrypt wywołujemy następująco:
convert.php?nazwa=nazwa_pliku.
Zakończenie
Nasza galeria jest już gotowa. Pozostaje już tylko dodanie rekordów do bazy, utworzenie miniaturek i podziwianie efektów. Niemniej jednak, nie jest to koniec pracy. Brakuje jeszcze choćby panelu administracyjnego oraz stronicowania miniaturek, co przydaje się szczególnie przy dużych galeriach. Ale to pozostawiam już Twojej inwencji - wszak ćwiczenie czyni mistrza.