Статьи - Фотогалерея своими руками с использованием Perl
Фотогалерея своими руками с использованием Perl
ФОТОГАЛЕРЕЯ СВОИМИ РУКАМИ С ИСПОЛЬЗОВАНИЕМ PERL
ПРЕДИСЛОВИЕ
В общем-то скриптов фотогалерей, как платных так и бесплатных в сети Интернет довольно достаточно, но всегда все хочется сделать самому, поэтому попробуем определить как нам правильно это сделать, причем что бы это было красиво и легко управлялось. Так как такое понятие как Админ-интерфейс, часто отсутствует, а чаще создано на каком-то минимальном уровне, то особое внимание уделим именно ему. Идею создания подобного скрипта навеяла статья опубликованная на webcsript.ru, как практическое применение модулей для работы с графикой.
ПОСТАНОВКА ЗАДАЧИ:
Какой должна быть собственно фотогалерея? Она должна выводить маленькие иконки фотографий в таблице и постранично, должны быть подписи к фоторгафиям, а сами иконки (а может и подписи тоже) должны быть ссылками на большие фотографии - это внешняя сторона. А что должно быть во внутренней:
во-первых мы хотим картинки закидывать через upload, а не возится с FTP, а потом возится с ссылками...;
во вторых иконки для фотографий мы не хотим делать сами: уменьшать изображение в графическом редакторе, потом сопоставлять на сайте полученную иконку с большим изображением, пусть это делает наш скрипт;
в третьих мы хотим руководить процессом вывода на экран картинок: сколько иконок будет у нас на странице, как они будут располагаться (количество столбцов и строк) и какой будет размер иконки;
в четвертых мы хотим иметь несколько фотогалерей на одном сайте, и для каждой фотогалереи использовать свой дизайн и свои параметры;
а в пятых, естественно, мы хотим править подписи к фотографиям, заголовки к фотогалереи, шаблоны и остальные мелочи;
Теперь самое интересное, что для этого нужно:
собственно сервер, на котором мы будем все это обкатывать, с установленным Perl и MySQL (для тех кто не хочет работать с файловыми БД, я лично отношусь к их числу);
к Perl должны быть установленны модули: CGI (для передачи переменных окружениея), DBI и DBD::mysql (для работы с MySQL), Image::Magick (для работы с графикой).
СТРУКТУРА АДМИН ИНТЕРФЕЙСА:
Итак какую структуру данных мы можем обрисовать:
Какие действия будет производить наш админ-интерфейс:
показ структуры фотогалерей;
создание, редакитрование, удаление фотогалереи;
загрузка, изменение, удаление изображения;
формирование иконок изображений;
ОПИСАНИЕ АДМИН-ИНТЕРФЕЙСА:
Для начала создадим таблице в базе MySQL их всего две:
таблица фотогалерей со следующими полями gallery_table:
id - идентификатор галереи (тип поля MEDIUMINT - AUTO_INCREMENT - PRIMARY KEY);
name - название, заголовок фотогалереи (тип поля VARCHAR до 250 символов);
desc - описание фотогалереи (тип поля VARCHAR до 250 символов);
template - шаблон вывода фотогалереи (тип поля TEXT);
x_icon - максимальная ширина иконки (тип поля VARCHAR до 5 символов);
y_icon - максимальная высота иконки (тип поля VARCHAR до 5 символов);
row_list - количество выводимых строк фотографий (тип поля VARCHAR до 5 символов);
column_list - количество выводимых колонок фотографий (тип поля VARCHAR до 5 символов);
таблица фотографий со следующими полями image_table:
id - идентификатор изображения (тип поля MEDIUMINT - AUTO_INCREMENT - PRIMARY KEY);
gallery - id номер фотогалереии к которой относится изображение (тип поля MEDIUMINT);
name - название изображения, оно же подпись к картинке (тип поля VARCHAR до 250 символов);
type_image - расширение (тип) изображения (тип поля VARCHAR до 4 символов);
Скрипт создания таблиц:
#!/usr/bin/perl use DBI; $name_base_mysql = "mybase"; # база данных MySQL $host_base_mysql = "localhost"; # host MySQL $port_base_mysql = "3306"; # порт MySQL $user_base_mysql = "user"; # пользователь MySQL $pass_base_mysql = "qwerty"; # пароль пользователя MySQL $dbh = "DBI:mysql:$name_base_mysql:$host_base_mysql:$port_base_mysql"; $dbh = DBI->connect($dbh, $user_base_mysql, $pass_base_mysql); $dbh -> do("CREATE TABLE IF NOT EXISTS image_table ( id MEDIUMINT NOT NULL AUTO_INCREMENT, gallery MEDIUMINT NOT NULL, name VARCHAR(250) NOT NULL, type_image VARCHAR(50) NOT NULL, PRIMARY KEY (id), INDEX (gallery))"); $dbh -> do("CREATE TABLE IF NOT EXISTS gallery_table ( id MEDIUMINT NOT NULL AUTO_INCREMENT, name VARCHAR(250) NOT NULL, titling VARCHAR(250) NOT NULL, template TEXT NOT NULL, x_icon VARCHAR(5) NOT NULL, y_icon VARCHAR(5) NOT NULL, row_list VARCHAR(5) NOT NULL, column_list VARCHAR(5) NOT NULL, PRIMARY KEY (id))"); print "Content-type: text/html; charset=windows-1251\n\n"; print qq "Create table OK!"; exit;
Здесь в принципе ничего сложного нет, только единственное иногда некоторые администраторы не дают привилегии для создания и удаления таблиц, поэтому если не работает, бегом к администратору...
Теперь перейдем непостредственно к нашему скрипту админ-интерфейса. Для этого нам понадобится четыре шаблона:
Теперь обсудим какие что же у нас жа шаблоны получились. Первые три обычные формы без особых сложностей, единственно параметр формы загрузки изображения enctype="multipart/form-data" так как мы должны передать не текст, а файл. Так же в первых двух шаблонах есть динамические внедрения (<!-- 1 --> и <!-- 1_insert -->), так как мы должны будем первоначально формировать список наших галерей для последующего их выбора. Вот с четвертым шаблоном нужно повозится. Во-первых мы должны сформировать и выдать список фотогалерей (<!-- 1 --> - одна строка списка), во-вторых сформировать и выдать список фотографий выбранной фотогалереи (<!-- 2 --> - одна строка списка). Переменные и параметры которые мы бодем обрабатывать скриптом я, для удобства, выделил темно-желтым цветом. Выделим их в список и определим, что мы с ними предполагаем делать:
mod - параметр указывающий объект с которым мы непосредственно работаем: фотогалерея (category) или изображение (image). Значение подставляется скриптом вместо выражения %mod%;
edit - параметр указывающий производимое действие над объектом: загрузка (upload), создание (new), изменение (edit), удаление (delete). Значение подставляется скриптом вместо выражения %edit%. При работе со списком указывает фотогалерею (идентификатор), которую просматриваем. Значение подставляется скриптом вместо выражения %id%;
id - индентификатор объекта. Значение подставляется скриптом вместо выражения %id%;
fdb[0-6] - параметры передаваемые из формы и указывающиеся непосредственно пользователем. Значение подставляется скриптом вместо выражений: %name%, %titling%, %row%, %column%, %y_icon%, %x_icon%, %html%, %id_category%, берущихся из нашей базы данных;
image - фотография которую мы хотим загрузить;
doing - подтверждение операции над объектом;
%script_url% - URL нашего скрипта. Можно конечно указывать его и сразу, но при переносе скрипта на другой хост прийдется переправлять все шаблоны, что несколько неудобно;
остальные параметры заключенные %, проще будет объяснить в процессе кода.
Теперь можно заняться непосредственно скриптом. Начало стандартное:
#!/usr/bin/perl use CGI; use DBI; use Image::Magick; use strict;
Так же я рекомендовал ввести еще дополнительные параметры работы скрипта:
use CGI::Carp qw (fatalsToBrowser); # что бы ошибки скрипта выпадали в браузер $CGI::POST_MAX = 262144; # что бы не было желания закачивать картинки в особо крупных размерах :-)
Устанавливаем начальные переменные:
use vars '$path_image', '$name_base_mysql', '$host_base_mysql', '$port_base_mysql', '$user_base_mysql', '$pass_base_mysql', '$mod', '$edit', '$id', '$doing', '$cat', '$image', '@fdb', '@temp', '$dbh', '$sth', '$sql', '$tmp', '$image_url'; $path_image = "/home/site/mysite/html/gallery/"; # путь где будут располагаться фотографии $script_url = "http://www.mysite.ru/cgi-bin/gallery/gallery.pl"; # url где располагается наш скрипт $image_url = "http://www.mysite.ru/gallery/"; # url где располагаются наши фотографии $name_base_mysql = "mybase"; # база данных MySQL $host_base_mysql = "localhost"; # host MySQL $port_base_mysql = "3306"; # порт MySQL $user_base_mysql = "user"; # пользователь MySQL* $pass_base_mysql = "qwerty"; # пароль пользователя MySQL
*Привилегии для пользователя MySQL можно установить только SELECT, INSERT, UPDATE, DELETE
Перенаправляем на процедуру в соответствии с переданными переменными $mod и $edit:
if ($mod eq 'category') { if ($edit eq 'new') {&mod_category_new} if ($edit eq 'edit') {&mod_category_edit} if ($edit eq 'delete') {&mod_category_delete} } if ($mod eq 'image') { if ($edit eq 'upload') {&mod_image_upload} if ($edit eq 'edit') {&mod_image_edit} if ($edit eq 'delete') {&mod_image_delete} } &mod_list_gallery; exit;
В итоге получается, что скрипт вызывает определенную процедуру в соответствии с двумя переданными параметрами $mod и $edit - объект и производимые действия над объектом. Если же нас не удовлетворяет хоть один из параметров, то выходим в процедуру просмотра фотогалерей.
Рассмотрим и разберем в одтельности каждую процедуру:
Из вышеуказанного кода теперь можно определить, почему мы в таблице фотографий не указывали имени файла, а только расширение - именем файла фотографии у нас будет являться id номер, что предохранит нас от от повторов имен файлов, т.к. поле id ключевое и повторы в нем запрещены, а так же очень просто выставляется соответсвие иконки для определенной картинки, мы просто к имени файла приставляем "i", а остальное остается неизменным.
Теперь остается собрать наш шаблон воедино и выдать на экран:
Сначала проверяем подтверждение операции над объектом, в данном случае загружаемой картинкой:
if ($doing eq "afform") {
Проверяем имя файла на соответствие разрешенного типа (расширения):
my (@tv, $file) $tv[0] = $image; $tv[0] =~s /.*((png)|(gif)|(jpg))$/$1/gi; if ($tv[0] eq '') {exit;} # Хотя конечно лучше поставить более толковую проверку, но я не буду здесь "раздувать" код
Вставляем данные полученные из формы и полученное расширение файла в MySQL:
$dbh = "DBI:mysql:$name_base_mysql:$host_base_mysql:$port_base_mysql"; $dbh = DBI -> connect($dbh, $user_base_mysql, $pass_base_mysql); $dbh -> do("INSERT INTO image_table SET name = '$fdb[0]', gallery = '$fdb[1]', type_image = '$tv[0]' "); $tv[1] = $dbh->{'mysql_insertid'}; # Выберем последний id номер, он будет именем нашего файла $dbh -> disconnect();
Теперь сохраняем фотографию на сервере:
$file = $path_image.$tv[1].".".$tv[0]; open (IMG, ">$file"); binmode IMG; flock ($file, 2); print IMG while (<$image>); close (IMG); chmod 0644, $file;
Берем данные о наших фотогалереях из базы данных MySQL*:
$sql = "SELECT id, name FROM gallery_table ORDER BY name ASC"; $dbh = "DBI:mysql:$name_base_mysql:$host_base_mysql:$port_base_mysql"; $dbh = DBI -> connect($dbh, $user_base_mysql, $pass_base_mysql); $sth = $dbh -> prepare($sql); $sth -> execute(); my ($kolvo_category, $i, $tmp, @category, $line_temp); $i = 0; $kolvo_category = $sth -> rows; while ($tmp = $sth -> fetchrow_arrayref()) {$category[0][$i]=$tmp->[0];$category[1][$i]=$tmp->[1];$i++;} $sth -> finish(); $dbh -> disconnect();
*Кстати подобная операция, как, впрочем и следующая, будет повторятся практически везде, поэтому её можно вынести в отдельную процедуру, либо выполнять сразу в начале скрипта...
Формируем список фотогалерей:
for ($i = 0; $i < $kolvo_category; $i++) { $line_temp = $temp_line_1; if ($cat eq $category[0][$i]) {$line_temp =~s /%selected%/selected/gi;} # вот, кстати, зачем нам нужен был параметр cat - только для этого, что бы было удобно else {$line_temp =~s /%selected%//gi;} $line_temp =~s /%id_category%/$category[0][$i]/gi; $line_temp =~s /%name_category%/$category[1][$i]/gi; $temp_list_1 .= $line_temp; }
если мы производим операцию над объектом, то есть производим upload изображения
получаем имя файла (переменная $image - по сути имеет два значения, имя файла и непосредственно файл; и в зависимости от того, как мы используем эту переменную, то получаем соответстующее её значение);
выбираем расширение файла, в нашем случае ((png)|(gif)|(jpg)) - разрешенные расширения файлов которые мы можем загружать;
вставляем данные об изображении в таблицу базы данных MySQL;
производми upload файла;
сразу же считываем только что загруженный файл в новый проект Image::Magick;
определяем размеры изображения, до которого мы должны его ужать;
сжимаем изображение и записываем в новый файл;
редиректим скрипт;
если же мы только хотим загрузить файл, то просто выводим обработанную форму и все.
С этой процедурой все, кратко пробежимся по ней:
процедура изменения и процедура удаления фотографии:sub mod_image_edit { sub mod_image_delete {
Данные процедуры отличаются лишь тем, что при переданном параметре doing - первая производит UPDATE таблицы MySQL, а вторая DELETE FROM. А изменение изображения сводится только к изменению названия, описания и галереи изображения, правда есть некоторые нюансы:
Сначала проверяем подтверждение операции над объектом, в данном случае - картинкой:
if ($doing eq "afform") {
Обновляем таблицу если мы редактируем изображение
$dbh = "DBI:mysql:$name_base_mysql:$host_base_mysql:$port_base_mysql"; $dbh = DBI -> connect($dbh, $user_base_mysql, $pass_base_mysql); $dbh -> do("UPDATE image_table SET name = '$fdb[0]', gallery = '$fdb[1]' WHERE id = '$id'"); $dbh -> disconnect();
Изменяем иконку, изображения, так как в разных фотогалереях могут быть разные размеры иконок (данную операцию я бы рекомендовал производить после проверки изменеия галереи фотографии, что бы лишний раз не переписывать иконку)
Эта операция полностью идентична опрерации изменения иконки зображения при upload, единственное прежде нужно взять данные об изображении (id номер и расширение (type-image)). После изменения иконки производим редирект в список фотогалерей
Удаляем запись из таблицы если мы удаляем изображение:
Сначала считываем данные о этом изображении, для того, что бы мы могли удалить соответственные файлы:
$dbh -> do("DELETE FROM image_table WHERE id = '$id'"); $dbh -> disconnect(); $file = $path_image."i".$photo[0][0].".".$photo[1][0]; unlink ($file); $file = $path_image.$photo[0][0].".".$photo[1][0]; unlink ($file);
Опять же редирект...
}
Теперь вернемся к тому, что мы пока только хотим произвести действие, здесь, я думаю, тоже особых сложностей не должно возникать, алгоритм такой же, что и при upload, единственное мы сначало должны получить данные об изображении из MySQL и вставить их в форму:
Вот в общем-то все процедуры работы с изображениями рассмотрели, теперь процедуры работы с фотогалереями:
Сразу хочу сказать, что различие между процедурами создания, изменения и удаления минимальны:
в процессе создания мы ничего не проверяем толко данные переданные из формы;
в процессе редактирования мы проверяем изменились ли параметры x_icon и y_icon, и если да, то переписываем все иконки изображений в соответсвии с новыми параметрами;
в процессе удаления, мы проверяем есть ли в данной фотогалереи фотографии и если есть отказываем в удалении, чтобы не оставалось "безхозных" фотографий ;
Структура же процедур точно такая же как и у процедур работы с изображениями;
С админ-интерфейсом все, теперь перейдем к внешней части, собственно что теперь должны увидеть пользователи...
ОПИСАНИЕ СКРИПТА ПОКАЗА ФОТОГАЛЕРЕИ:
Сам шаблон фотогалереи у нас находится в таблице базы данных MySQL, а так как, у нас может быть несколько фотогалерей, то и шаблонов будет столько же, и при запуске нашего скрипта нужно будет указывать какую фотогалерею мы используем. То есть скрипт сам по себе по ссылке http://www.mysite.ru/cgi-bin/gallery.cgi - работать не будет, точнее будет, но покажет при этом пустую страницу, для этого ссылку нужно будет делать http://www.mysite.ru/cgi-bin/gallery.cgi?gal=1, где gal - id номер фотогалереи. Если же мы будем использовать только одну галерею, то данный параметр мы можем вписать прямо в скрипт, и тогда не будет никаких "заморочек".
В блоках «заголовок» и «окончание» используются следующие переменные:
%name_category% - Название категории;
%title_category% - Описание категории;
В блоке «фотография» используются следующие переменные:
%link_image% - Ссылка на фотографию;
%link_icon% - Ссылка на уменьшенное изображение;
%name_image% - Название фотографии;
В блоке «список страниц» используются следующие переменные:
- Ссылка на предыдущую/следующую страницу;
Теперь перейдем скрипту, естественно он должен быть компактен и работать в один проход, то есть процедуры мы не используем:
Начало стандартное:
#!/usr/bin/perl use CGI; use DBI; use DBD::mysql; use strict; my ($query, $gallery, $page, $dbh, $sth, $sql, $tmp, @cat, $mi, $i, $max_img, @img, @temp, $tl1, $tl2, $tl3, $tl4, $tl5, $np, $ii, $tl, $link, $list2, $n_row, $n_col, $list4, $list5, $iii, $url_img, $l_img, $l_ico);
Устанавливаем начальные переменные:
$url_img = "http://www.mysite.ru/gallery/";
Получаем переменные окружения:
$query = new CGI; $gallery = $query -> param('gal'); $page = $query -> param('p'); $gallery = 0 if $gallery eq ''; # MySQL уходит в "штопор" если указывается пустое значение в условии запроса $page = 1 if $page eq '';
$mi = $cat[3]*$cat[4]; # количество фотографий на странице $i = ($page-1)*$mi; # "стартовая точка" для LIMIT @temp = split(/\n/,$cat[2]); # переводим шаблон в массив, так как его обработка ведется построчно
Выбираем количество фотографий фотогалереи:
$sql = "SELECT id FROM image_table WHERE category='$gallery'"; $sth = $dbh -> prepare($sql); $sth -> execute(); $max_img = $sth->rows;$sth->finish();