вернуться назад

Создание собственной галлереи

Всё, изложенное далее, не следует принимать как некий рецепт или поучение. Это скорее "путевые заметки" в процессе создания галереи, которыми я счёл возможным с вами поделиться.

В Интернете, не прилагая значительных усилий, можно найти много готовых галерей, и, казалось бы, что-то из этого обилия для своих целей можно и приспособить. Так что сочинять собственную галерею, вроде, и не обязательно. Но в Интернете же есть и статьи о том, как создать свою собственную галерею, причём эти галереи создавались отнюдь не потому, что их авторам делать было нечего. Просто готовые решения устраивают не всех, и не во всех отношениях. Прежде всего, готовые плагины, а именно так оформляются галереи, обладают, как правило, избыточным функционалом, что называется "на все случаи жизни". Мне попадались галереи, где было реализовано около десятка вариантов смены одного изображения другим. Ну, и объём кода у них соответствующий. Для современных компьютеров с большим объёмом памяти и ёмкими дисками это, может быть, и не очень критично, но на время загрузки всё равно влияет, и, кроме того, на меня, например, крайне неприятно действует тот факт, что в память моего компьютера загружен код, который никогда, ни при каких обстоятельствах использован не будет. Далее, о самом функционале. Кажется, всё бы ничего, да размер основного изображения представляется мелковатым, или места для комментария к изображению не предусмотрено и тому подобное, т.е. "я бы сделал не так". Это значит, нужно лезть в чужой код, нужный функционал там находить, и что-то в нём менять, и это может оказаться задачей совсем не тривиальной. Или ещё. Есть у меня на примете одна миленькая галерея, но она реализована на MooTools. Ну кто сейчас в MooTools играет? Этот фреймворк, в общем-то, не хуже и не лучше других, но осваивать его только ради внесения нескольких поправок, а затем напрочь забыть, слишком уж расточительно по временным затратам.

Такие вот предваряющие замечания. Полагаю, я достаточно внятно изложил, зачем мне понадобилось создание собственной "самописной" галереи.

Планирование галереи

Для начала определимся с требованиями, которым должна соответствовать галерея.

  1. Галерея должна быть работоспособной, даже если в браузере отключён JavaScript. Сейчас редко кто отключает JavaScript, да и не всякий сможет в современном браузере JavaScript отключить, но уникумы есть. Не будем лишать их возможности пользоваться галереей.

  2. Окно галереи с основным изображением будет фиксированной ширины: 950px. Дисплеи сейчас большие, но будем всё же ориентироваться на экраны шириной 1024рх, таких ещё много. Высота – какая получится.

  3. Должны быть навигационные указатели "вперёд" для того, чтобы подгрузить следующий комплект снимков в рубрике, и "назад" для возврата к предыдущему.

  4. Если мы "дошли" до последней картинки в рубрике, то указатель — "вперёд" должен исчезать, если это самое первое изображение в рубрике, не должен отображаться указатель "назад".

  5. Пользователю необходимо предоставить возможность перелистывать изображения не выходя из окна просмотра. Т.е. пользователь может перемещаться между изображения в пределах отображённых миниатюр кликами мыши на соответствующих указателях.

  6. Должна быть предусмотрена возможность просмотра изображения в формате "на весь экран".

Если вы не можете представить себе визуально, как будет выглядеть страница, просто прочитав ее исходный код, то лучший способ создать страницу, управляемую базой данных, это начать со статической страницы и заполнить её текстом-заполнителем и изображениями. Затем мы создадим правила стиля CSS, чтобы страница выглядела так, как необходимо, и, наконец, заменим каждый элемент-заполнитель PHP-кодом. Каждый раз при замене, рекомендую проверять страницу в браузере, чтобы убедиться, что всё ещё держится вместе должным образом, и вы ничего не поломали.

макет

Рис. 1-1. Статический макет галереи.

На рис. 1-1 показан статический макет галереи и указаны элементы, которые необходимо преобразовать в динамический код. Я сделал миниатюры стандартного размера, высотой 48 пикселов. Кроме того, чтобы облегчить жизнь, я дал каждой миниатюре то же имя, что и у более крупной версии, и сохранил их в отдельной подпапке папки изображений под названием thumbs. Основные изображения я так же нормализовал и сделал их все шириной 950 пикселов. Высота – какая получится.

На рис. 1-2 показано расположение блоков в макете галереи. Как видите, имеется общая обёртка, блок div id="wrapper", куда помещена вся html-разметка.

блоки

Рис. 1-2. Структура расположения блоков в макете галереи.

Я обозначил только основные элементы, чтобы не затемнять это рисунок без особой на то необходимости. Весь функционал галереи помещён в div id="gallery". Вот такой план предстоит реализовать.

Подготовка к кодированию галереи

Для начала необходимо создать базу данных, в которой будет храниться всё необходимое для создания галереи. Моя база данных имеет вид, отображённый на рис. 1-3.

база

Рис. 1-3. Структура базы данных галереи

В таблице четыре столбца: id_photo, photo_name, photo_desc и path_name. Это количество столбцов и их наименование определялись потребностями моей галереи. В качестве имени пути я использовал то, что мне дал фотоаппарат. Умничать не стал. Настоятельно рекомендую не использовать в этом (именно в этом) столбце кириллицу. Избавите себя от лишних проблем. В качестве базы данных использовалась MySQL, но это совершенно не принципиально. Можно использовать и любую другую базу данных.

Таблица изображений не содержит самих изображений, только пути к ним, по той простой причине, что это обычно вызывает больше проблем, чем следовало бы ожидать. Основные проблемы заключаются в следующем:

* Изображения не могут быть проиндексированы или найдены поисковой системой без сохранения отдельно текстовой информации.

* Изображения, как правило, большие, что приводит к существенному увеличению размеров таблиц. Если есть ограничение на объем хранилища в базе данных, вы рискуете тем, что вам не хватит места.

* Фрагментация таблицы влияет на производительность при частом удалении изображений.

* Извлечение изображений из базы данных включает в себя передачу изображения в отдельный скрипт, замедляя отображение на веб-странице.

Хранение изображений в базе данных - это не лучшее решение. Более эффективно хранить изображения в обычной папке на вашем сайте и использовать базу данных для получения информации об изображениях. Вам нужно всего три части информации в базе данных - имя файла, заголовок и описание, которые мы будем использовать в дальнейшем. Название снимка также может быть использовано в качестве текста alt. Некоторые разработчики хранят полный путь к изображению в базе данных, но я думаю, что хранение только имени файла дает вам большую гибкость. Путь к папке изображений будет встроен в HTML. Вы также можете сохранить в таблице высоту и ширину изображения, но это не обязательно.

Далее необходимо подготовить изображения. Нам потребуются миниатюры, изображения среднего размера, которые будут отображаться в пространстве главного изображения галереи, и большие изображения для полноэкранного режима. Я уже упоминал, что миниатюры я поместил в папку thumb, саму папку с миниатюрами поместил в корневой каталог галереи. Для остальных изображений я создал каталог images, в котором создал два подкаталога, large и medium, в которых и разместил большие и средние изображения. Такая структура каталогов вызвана особенностями организации моего сайта. О размерах миниатюр и изображений среднего размера я упоминал ранее, а так же о мотивации, которая побудила меня принять такие решения. Ширину больших изображений я принял равной 1200рх. Должен заметить, что чем осмысленнее вы подойдёте к выбору размеров изображений, тем меньше у вас будет проблем. Старайтесь, чтобы ваши изображения были, по возможности, одного размера, или, по крайней мере, не разнились значительно. Мои же решения были во многом вынужденными, ибо я создавал галерею взамен существовавшей на сайте, и корректировать размеры большого количества изображений мне не хотелось.

И ещё один подготовительный момент: к базе данных необходимо подключаться. Для этого я создал файл connection.php и поместил его в каталог includes. Ниже приводится код этого файла



	<?php
	function dbConnect($user, $connectionType = 'mysqli') {
		$host = 'localhost';
		$db = 'php_gallary';//так именуется моя база, вы назовёте свою иначе
	        $user = 'root';
		$pwd = '';

		if ($connectionType == 'mysqli') {
			$conn = @ new mysqli($host, $user, $pwd, $db);
			if ($conn->connect_error) {
				exit($conn->connect_error);
			}
			return $conn;
		} else {
			try {
				return new PDO("mysql:host=$host;dbname=$db", $user, $pwd);
			} catch (PDOException $e) {
				echo $e->getMessage();
			}
		}
	}

Здесь, я полагаю, всё ясно. Допускается подключение к базе данных как в процедурном стиле, так и в объектно-ориентированном посредством объекта PDO. Конечно, когда вы перенесёте своё творение на сервер провайдера, значения логина и пароля для доступа к базе данных, (переменные $user и $pwd) будут другими, те же, которые указаны сейчас, предназначены для локального сервера, работающего на вашем компьютере.

Преобразование элементов галереи в код РНР

Мы сделаем наши миниатюры ссылками и будем формировать запрос на вывод основного изображения в адресной строке браузера, используя метод GET. Наша ссылка будет выглядеть следующим образом


		<a href="<?php echo $_SERVER['PHP_SELF'];?>?image=<?php echo $row['filename'];?>">

$_SERVER['PHP_SELF'] - это удобная предопределенная переменная, которая ссылается на имя текущей страницы. Вы могли бы просто уйти из gallary.php, жестко закодированой в URL, но я предполагааю, что многие из вас будут использовать файлы загрузки, которые имеют другое, не такое, как у меня, имя. Использование $_SERVER['PHP_SELF'] гарантирует, что URL-адрес указывает на правильную страницу. Остальная часть кода создает строку запроса с текущим именем файла.

Чтобы показать все миниатюры, необходимо обернуть ячейку таблицы в цикл. Мы будем использовать цикл do...while, так что начало нашего цикла будет выглядеть так


	<table id="thumbs">
      <tr>
          <!-—Зта строка должна быть повторена -->
			   <?php do { ?>

Далее следует обращение к базе данных. Для MySQLi


	<?php } while ($row = $result->fetch_assoc()); ?>

Для PDO


	<?php } while ($row = $result->fetch()); ?>


Такое обращение выбирает следующую строку в результирующем наборе и возвращает программу к началу цикла. Поскольку $row['filename'] и $row['caption'] имеют разные значения, следующая миниатюра и связанный с ней текст alt вставляются в новую ячейку таблицы. Строка запроса также обновляется с новым именем.

Нам нужно создать логическую часть, которая изменяет основное изображение и связанные с ним надписи. Поместим этот раздел кода в блоке над объявлением DOCTYPE:


	//получение имени главного изображения
	if (isset($_GET['image'])) {
		$mainImage = $_GET['image'];
		}else {
		$mainImage = $row['filename'];
	}


Массив $_GET содержит значения, переданные через строку запроса, поэтому, если $_GET['image'] был установлен (определен), он берет имя файла из строки запроса и сохраняет его как $mainImage. Если $_GET['image'] не существовал, значение берется из первой записи в результирующем наборе, как и раньше.

Наконец, нам нужно получить заголовок основного изображения. Поскольку заголовки у всех фото различные, нам нужно извлекать их из базы данных в цикле, который отображает миниатюры в таблице. Мы хотим, чтобы заголовок соответствовал основному изображению, поэтому, если текущая запись имени файла совпадает с $mainImage, это то, что нам нужно. Помните, в начале статьи я упоминал, что реализациям всех размеров одного того же изображения дано одно и то же имя, поэтому поступим следующим образом:


	<?php 
		do {
		//получение заголовка, если имя миниатюры то же, что и у основного изображения
			if ($row['filename'] == $mainImage) {
			$caption = $row['caption']; 
		}
	?>


Постраничная навигация при большом

количестве изображений


Если у вас пять или шесть миниатюр, то они вполне удобно поместятся в галерее, но что, если у вас их 25 или 40? Ответ заключается в том, чтобы ограничить количество записей, извлекаемых одномоментно и отображаемых на каждой странице, и создать навигационную систему, которая позволит вам просматривать результаты. Вы видели эту технику бесчисленное количество раз при использовании поисковой системы; теперь вам предстоит сделать это самостоятельно. Задача может быть разбита на следующие два этапа:

1. Выборка из таблицы подмножества записей для отображения.

2. Создание навигационных ссылок на страницу через подмножества.

Оба этапа относительно просты в реализации, хотя и предполагают применение небольшой условной логики. Сохраняйте спокойствие, и мы преодолеем это затруднение.


Ограничить количество извлекаемых записей на странице просто. Добавим ключевое слово LIMIT в SQL-запрос следующим образом:


	SELECT photo_name, photo_desc, path_name FROM images LIMIT startPosition, maximum;


За ключевым словом LIMIT может следовать одно или два числа. Если используется только одно число, устанавливается максимальное число извлекаемых записей. Это полезно, но не подходит для системы постраничной навигации. Для этого нужно использовать два числа: первое указывает, с которой записи начать, а второе оговаривает максимальное количество извлекаемых записей. Будьте аккуратны с именем таблицы. Я написал здесь "images", но у вас она наверняка будет называться иначе. MySQL считает записи от 0, поэтому для отображения первых семи изображений вам нужен следующий SQL-запрос:


	SELECT photo_name, photo_desc, path_name FROM images LIMIT 0, 7;


Это для своей галереи я решил, что должно отображаться семь миниатюр из дизайнерских соображений. Если вы примете другое решение, ничего страшного не произойдёт. Чтобы показать следующий набор, SQL-запрос должен измениться на этот:


	SELECT photo_name, photo_desc, path_name FROM images LIMIT 7, 7;


Для построения навигационной системы необходим способ генерации этих чисел. Второе число никогда не меняется, поэтому давайте определим константу под названием SHOWMAX. Генерация первого числа (назовем его $startRecord) тоже довольно проста. Начните нумерацию страниц с 0 и умножьте второе число на текущий номер страницы. Итак, если вы вызываете текущую страницу $curPage, формула выглядит так:


	$startRecord = $curPage * SHOWMAX;


И SQL-запрос становится следующим:


	SELECT photo_name, photo_desc, path_name FROM images LIMIT $startRecord, SHOWMAX;


Если $curPage равен 0, $startRecord также равен 0 (0*7), но когда $curPage увеличивается до 1, $startRecord изменяется на 7 (1 * 7) и так далее.

Поскольку в таблице изображений ограниченное количество записей, необходимо определить общее число записей, чтобы предотвратить получение навигационной системой пустых результирующих наборов. Ответ заключается в использовании функции SQL COUNT() следующим образом:


	SELECT COUNT(*) FROM images;


При использовании в сочетании со звездочкой COUNT () возвращает общее количество записей в таблице.

Итак, для построения навигационной системы необходимо выполнить оба SQL запроса: один для поиска общего количества записей, а другой для извлечения необходимого подмножества. MySQL работает быстро, поэтому результат практически мгновенный.

С навигационными ссылками мы разберёмся позже. Начнем с ограничения количества миниатюр на первой странице.

Определим SHOWMAX и SQL-запрос для нахождения общего количество записей в таблице.


	// инициализация переменных для навигации
		$pos = 0;
		$firstRow = true;
	// установка максимального количества отображаемых миниатюр
		define('SHOWMAX', 7);
		$conn = dbConnect('read');
	// подготовка SQL-запроса для получения общего количества изображений
		$getTotal = 'SELECT COUNT(*) FROM images';


Теперь необходимо выполнить новый SQL-запрос. Код идет сразу после кода в предыдущем шаге, но отличается в зависимости от типа соединения MySQL.

Для MySQLi используйте этот код:


	// подтверждение запроса и сохранение результата как $totalPix
			$total = $conn–>query($getTotal);
			$row = $total–>fetch_row();
			$totalPix = $row[0];


Это подтверждает запрос и затем использует метод fetch_row() который получает одну строку из объекта MySQLi_Result как индексированный массив. В результате получается только один столбец, поэтому $row[0] содержит общее количество записей в таблице изображений.

Для PDO код будет таким:


	// подтверждение запроса и сохранение результата как $totalPix
			$total = $conn–>query($getTotal);
			$row = $total–>fetchColumn();
			$total–>closeCursor();


Запрос подтверждается, а затем используется метод fetchColumn() чтобы получить результат об общем количестве изображений, который хранится в $totalPix. Затем необходимо использовать closeCursor() чтобы освободить подключение к базе данных для следующего запроса.

Вслед за этим необходимо установить значение для текущей страницы $curPage. Ссылки навигации, которые мы создадим позже, передают значение требуемой страницы через строку запроса, поэтому нужно проверить, находится ли curPage в массиве $_GET. Если это так, используется это значение. В противном случае следует установить для текущей страницы значение 0. Вставьте следующий код сразу после кода на предыдущем шаге:


	// установление текущей страницы
			if (isset($_GET['curPage'])) {
				$curPage = $_GET['curPage'];
				} else {
				$curPage = 0;
			}


При использовании тернарного оператора тот же результат может быть достигнут посредством всего лишь одной строки кода

<


	$curPage = isset($_GET['curPage']) ? $_GET['curPage'] : 0;


Теперь у вас есть вся информация, необходимая для вычисления startrow и построения SQL-запроса для получения подмножества записей. Добавьте следующий код сразу после кода на предыдущем шаге:

<


	// вычисление стартовой строки подмножества
		$startRow = $curPage * SHOWMAX;


Исходный SQL-запрос теперь должен быть в следующей строке. Выглядит он следующим образом:

<


	// подготовка SQL для получения информации об изображении
		$sql = "SELECT photo_name, photo_desc, path_name FROM images LIMIT $startRow," . SHOWMAX;


Обратите внимание, что использованы двойные кавычки, потому что я хочу, чтобы PHP обрабатывал $startRow.

В отличие от переменных константы не обрабатываются внутри строк в двойных кавычках. Таким образом, SHOWMAX добавляется в конец SQL-запроса с оператором конкатенации (точка). Запятая внутри заключительных кавычек является частью SQL, разделяя два аргумента пункта LIMIT. Хотя $curPage поступает из пользовательского ввода, использовать его для вычисления значения $startRow безопасно, потому что оно умножается на SHOWMAX, которое является целым числом. Если значение, переданное через строку запроса, не является числом, PHP автоматически преобразует его в 0.

Текст над миниатюрами генерируется таким кодом.

<


	<p id="picCount">Отображение  с<?php echo $startRow+1;
		if ($startRow+1 < $totalPix) {
			echo ' до ';
			if ($startRow+SHOWMAX < $totalPix) {
			echo $startRow+SHOWMAX;
			} else {
			  echo $totalPix;
			}
		}
		  echo " из $totalPix";
		  ?>
		</p>


Рассмотрим это строка за строкой. Отсчёт $startRow начинается с нуля, поэтому вам нужно добавить 1, чтобы получить более удобное число. Таким образом, $startRow+1 отображает 1 на первой странице и 8 на второй странице. Во второй строке $startRow+1 сравнивается с общим количеством записей. Если оно меньше количества записей, это означает, что текущая страница отображает диапазон записей, поэтому в третьей строке отображается текст " до" с пространством по обе стороны. Затем вам нужно поработать с верхним числом диапазона, поэтому вложенный if ... и условная инструкция else добавляет значение начальной строки к максимальному числу записей, отображаемых на странице. Если результат меньше, чем общее количество записей, $startRow+SHOWMAX дает вам номер последней записи на странице. Однако, если он равен или больше суммы, вместо этого отображается $totalPix. Наконец, вы выходите из обоих условных операторов и отображаете "из", за которым следует общее количество записей.

Как упоминалось ранее, значение требуемой страницы передается в PHP скрипт через строку запроса. При первой загрузке страницы строка запроса отсутствует, поэтому значение $curPage имеет значение 0. Строка запроса создается при щелчке на миниатюре для выбора другого изображения (напоминаю, что это ссылки), она включает только имя файла основного изображения, поэтому исходное подмножество миниатюр остается неизменным. Для отображения следующего подмножества необходимо создать ссылку, увеличивающую значение $curPage на 1. Чтобы вернуться к предыдущему подмножеству, вам нужна другая ссылка, которая уменьшает значение $curPage на 1. Это достаточно просто, но вы также должны убедиться, что эти ссылки отображаются только тогда, когда есть допустимое подмножество для перехода. Например, нет смысла отображать обратную ссылку на первой странице, потому что нет предыдущего подмножества. Аналогично, вы не должны отображать прямую ссылку на странице, которая отображает последнее подмножество, потому что там нет ничего для перехода.

Обе проблемы легко решаются с помощью условных операторов. Есть одна последняя вещь, о которой вам нужно позаботиться. Необходимо также включить значение текущей страницы в строку запроса, созданную при щелчке на миниатюре. Если это не удается сделать, $curPage автоматически возвращается к 0, а первый набор миниатюры отображаются вместо текущего подмножества.

Я разместил навигационные ссылки правее и левее отображения миниатюр.

<


		<!—-Здесь должны разместиться навигационные ссылки -->
		<div id = "cameback"><p>
			<?php
			// создание обратной ссылки, если текущая страница больше, чем 0
			  if ($curPage > 0) {
				echo '<a href="' . $_SERVER['PHP_SELF'] . '?curPage=' . ($curPage-1) . 
						  '"> <Назад</a>';
			} else {
			// иначе оставить ячейку пустой
			echo ' ';
				}
			?>
			</p>
		</div>

	//здесь код отображения ячеек с миниатюрами

	<td>
	<?php
		// реализация прямой ссылки, если имеются ещё изображения
		if ($startRow+SHOWMAX < $totalPix) {
			echo '<a href="' . $_SERVER['PHP_SELF'] . '?curPage=' . ($curPage+1) . '">  
				   Вперёд ></a> 
		} else {
		// иначе оставить ячейку пустой
		  echo ' ';
		}
	?>
	</td>


Код разбивается на два раздела: первый создает обратную ссылку, если $curPage больше 0; а второй использует ту же формулу, что и раньше ($startRow+SHOWMAX < $totalPix), чтобы определить, отображать ли прямую ссылку. Я разместил обратную ссылку вне отображения таблицы миниатюр, а прямую ссылку в таблице. Возможно, кто-то меня за это поругает. Связано это с тем, что когда MySCL извлекает записи из таблицы и преобразует их в массив, счёт в этом массиве начинается с нуля, я об этом упоминал, и мне нужна была нулевая ячейка таблицы, чтобы избежать разнобоя в счёте миниатюр, а последняя ячейка таблицы на этот порядок счёта никак не влияет, и что там разместится, никакого значения не имеет.

Убедитесь, что вы получаете правильное сочетание кавычек в ссылках. Вычисления $curPage-1 и $curPage+1 заключены в круглые скобки, чтобы избежать точки после числа, неправильно интерпретируемого как десятичная точка. Она используется здесь в качестве оператора конкатенации для соединения различных частей строки запроса.

Теперь необходимо добавить значение текущей страницы в строку запроса в ссылке, окружающей миниатюру.


		<a href="<?php echo $_SERVER['PHP_SELF']; ?>?image=<?php echo $row['filename']; 
		?>&curPage=<?php echo $curPage; ?>">


Вы хотите, чтобы одно и то же подмножество отображалось при щелчке по миниатюре, поэтому вы просто передаете текущее значение $curPage через строку запроса.

Что бы ещё хотелось иметь для навигации? Рамочку вокруг той миниатюры, которую мы выбрали для просмотра. Она будет нам указывать, где мы находимся. Реализуется это посредством следующего кода


		if ($row['path_name'].'.jpg' == $mainImage) {
		?>
		<!-- вот здесь рамочку отображаем -->
		<td class = "picture imgborder"><a href="<?php echo SERVER['PHP_SELF'];?>
		?image=<?php echo $row['path_name'].'.jpg;'?>&curPage=
		<?php echo $curPage; ?>"><img src="thumb/<?php echo $row['path_name'].'.jpg'; ?>" 
		alt="<?php echo row['path_name'];?>" width="" height="48"></a></td>
			<?php
			}else{
			?>
			<!-- а здесь рамочку не отображаем -->
			<td class = "picture"><a href="<?php echo $_SERVER['PHP_SELF'];?>?image=
		<?php echo $row['path_name'].'.jpg';?>&curPage=<?php echo $curPage; ?>">
		img src="thumb/<?php echo $row['path_name'].'.jpg'; ?>"  
		alt="<?php echo $row['path_name'];?>" width="" height="48"></a>
		</td>


Что этот код делает? В блоке ifelse он анализирует, совпадает ли имя файла в выбранной ячейке таблицы с именем основного изображения. Если совпадение есть, то этой ячейке присваивается класс imgborder с соответствующим стилевым оформлением в таблице CSS. Строка здесь длинная и трудночитаемая, но идеологически простая. Это формирование ссылки на основное изображение.

Сделаем несколько замечаний по поводу размеров основного изображения. Для него мы выделили окно размером 950х450рх, но фактические размеры у нас самые различные, мы лишь нормализовали их по ширине, а необходимо сделать так, чтобы они всегда вписывались в отведённое пространство. За это отвечает следующий блок кода


		// получение размеров основного изображения и назначение
		//размеров главного изображения
			$imageSize = getimagesize('images/medium/'.$mainImage);
			$ratio = (integer)$imageSize[0]/(integer)$imageSize[1];
			if($ratio > 2.1){
			  $imageSize[3] = "width = \"910\" height = \"\" ";
			}else{
			  $imageSize[3] = "width = \"\" height = \"450\" ";
			} 


Здесь определяются фактические размеры основного изображения и сохраняются в переменной $imageSize Затем вычисляется отношение ширины изображения к его высоте и сохраняются в переменной $ratio. А далее если $ratio больше 2,1, т.е это пейзажная ориентация изображения, ему присваивается ширина 910рх, а высота такая, какая получится, а если меньше, то назначается высота 459рх, а ширина какая получится. Почему 2,1? Ранее я определил размер окна для просмотра основного изображения как 950х450рх. Если разделить 950 на 450, то получится как раз 2,1. Примите так же во внимание, что критическое значение переменной $ratio я подбирал исходя из размеров своих снимков. У вас это может быть другое значение, например единица. Если $ratio меньше единицы, значит это портретная ориентация, если больше, значит пейзаж.

Настало время привести полный код галереи.

Файл gallery.php


	
	<?php include './includes/title.php'; 
	  require_once './includes/connection.php';
  
	  // установление максимального количества извлекаемых записей
			define('SHOWMAX', 7);
			$conn = dbConnect('read', 'mysqli');
	  
	  // подготовка SQL - запроса для получения общего количества записец в таблице
			$getTotal = 'SELECT COUNT(*) FROM images ';

	// подтверждение запроса и сохранение резултата в переменной $totalPix
			$total = $conn->query($getTotal);
			$row = $total->fetch_row();
			$totalPix = $row[0];

	// установление текущей страницы
			$curPage = isset($_GET['curPage']) ? $_GET['curPage'] : 0;
		
	// вычисление стартовой строки подмножества изображений
			$startRow = $curPage * SHOWMAX;
			$sql = "SELECT photo_name, photo_desc, path_name FROM images LIMIT 
					$startRow," . SHOWMAX;
			$sql_desc = "SELECT photo_desc FROM images LIMIT $startRow," . SHOWMAX;
			$sql_caption = "SELECT photo_name FROM images LIMIT $startRow," . SHOWMAX;
		  // подтверждение запроса
			$result = $conn->query($sql) or die(mysqli_error());
			$result_desc = $conn->query($sql_desc) or die(mysqli_error());
			$result_caption = $conn->query($sql_caption) or die(mysqli_error());
	  // извлечение первой записи как массива
			$row = $result->fetch_assoc();
			$row_desc = $result_desc->fetch_assoc();
			$row_caption = $result_caption->fetch_assoc();
			$row_total = array();
			$row_count = 0;
	  // получение имени и заголовка для основного изображения
			if (isset($_GET['image'])) {
				$mainImage = $_GET['image'];
				} else {
				$mainImage = $row['path_name'].'.jpg';
				}
	  // получение размеров основного изображения и назначение
	  //размеров главного изображения
			$imageSize = getimagesize('images/medium/'.$mainImage);
			$ratio = (integer)$imageSize[0]/(integer)$imageSize[1];
			if($ratio > 2.1){
			$imageSize[3] = "width = \"910\" height = \"\" ";
			}else{
			$imageSize[3] = "width = \"\" height = \"450\" ";
			}
			do { //это нужно для передачи массива в js в дальнейшем
				$row_total[] = array($row_desc);
			}
			while($row_desc = $result_desc->fetch_assoc());
			
			do { //это нужно для передачи массива в js
				$total_caption[] = array($row_caption);
			}
			while($row_caption = $result_caption->fetch_assoc());
				
	  ?>
	<!DOCTYPE HTML>
	<html>
	<head>
		<meta charset="utf-8">
		<title>Порт<?php if(isset($title)) { echo "—{$title}"; } ?></title>
		<link href="styles/php_gallery.css" rel="stylesheet" type="text/css">
		<script src='./js/jquery-1.11.0.js'></script>
		<script src='./js/gallery.js'></script>
	</head>
	<body>
	<div id="wrapper">
		<main>
			<h2>Название рубрики</h2>
			<p id = "prifase">Здесь текст, продваряющий снимки выбранной рубрики</p>
		  <p id="picCount">Отображение с <?php echo $startRow+1;
			if ($startRow+1 < $totalPix) {
				echo ' до ';
				if ($startRow+SHOWMAX < $totalPix) {
				echo $startRow+SHOWMAX;
				} else {
				echo $totalPix;
				}
				}
				echo " из $totalPix";
				?>
		  </p>
			<div id="gallery">
			<div id = "cameback"><p>
				<?php
			// создание обратной ссылки, если текущая страница больше, чем 0
					if ($curPage > 0) {
					echo '<a href="' . $_SERVER['PHP_SELF'] . '?curPage=' . 
							($curPage-1) . '"> <Назад</a>';
					} else {
			// иначе оставить ячейку пустой
					echo ' ';
					}
				?>
			</p>
		</div>
		  <table id="thumbs">
			  <tr>
		<!--Это формирование отображеня миниатюр-->
			<?php do { 
	// назначение заголовка и описания, если имя миниатюры и основного изображения 
			//совпадают
			if ($row['path_name'].'.jpg' == $mainImage) {
			$caption = $row['photo_name']; 
			$figdescript = $row['photo_desc'];
			}
			if ($row['path_name'].'.jpg' == $mainImage) {
			 ?>
		<!-- вот здесь рамочку отображаем -->
			<td class = "picture imgborder"><a href="<?php echo 
			$_SERVER['PHP_SELF'];?>?image=<?php echo $row['path_name'].'.jpg;'?>&curPage=
                           <?php echo $curPage; ?>">
				<img src="thumb/<?php echo $row['path_name'].'.jpg'; ?>" 
				alt="<?php echo $row['path_name'];?>" width="" height="48"></a>
		</td>
			<?php
			}else{
			?>
		<!-- а здесь рамочку не отображаем -->
			<td class = "picture"><a href="<?php echo 
				$_SERVER['PHP_SELF'];?>?image=<?php echo  
				$row['path_name'].'.jpg';?>&curPage=<?php echo $curPage; ?>">
						<img src="thumb/<?php echo $row['path_name'].'.jpg'; ?>" 
						alt="<?php echo $row['path_name'];?>" width="" height="48"></a>
			</td>						
				<?php }
				} while ($row = $result->fetch_assoc()); ?>
					
			<td>
				<?php
		// реализация прямой ссылки, если имеются ещё изображения
				if ($startRow+SHOWMAX < $totalPix) {
				echo '<a href="' . $_SERVER['PHP_SELF'] . '?curPage=' . 
				($curPage+1) . '"> Вперёд ></a>';
				} else {
			// иначе оставить ячейку пустой
				echo ' ';
				}
				?>
			</td>
		</tr>
		  </table>

		  <figure id="main_image">
		  <div id = "leftarraw"><img src = "img/leftarraw.png"></div>
			<div id = "mainpicture">	<a href="images/large/<?php echo $mainImage;?>"  
					class = "lightbox">
		  <p><img id = "main_img" src="images/medium/<?php echo $mainImage;?>" 
			alt="<?php echo $caption;?>"  <?php echo $imageSize[3];?>></p>				
		</a></div>
		<div id = "rightarraw"><img src = "img/rightarraw.png"></div>
		  <figcaption><?php echo $caption;?></figcaption>
		<p id = "figdesc"><?php echo $figdescript;?></p>
					
		</figure>
	   </div>
	  </main>
	<?php include './includes/footer.php'; ?>
	</div>
	</body>
	</html>
	


Файл рhр_gallery.css


		/* Стили, определённые в теге body, удаляют все внутренние и внешние отступы (margin и padding),
		установленные на странице по умолчанию. Некоторые браузеры добавляют внешние отступы (margin), 
		другие устанавливают внутренние отступы (padding), поэтому установка и тех, и других в ноль 
		означает, что ваша страница будет выглядеть во всех браузерах одинаково. Свойство "font-family" 
		применяется ко всему тексту на странице, за исключением некоторых специфичных областей, где оно 
		переопределяется другими правилами.*/

	body {
		margin: 0;
		padding: 0;
		color: #333;
		font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
		overflow-y:scroll;
		background-color: #EAE2D7;
	}

	h1, h2 {
		margin: 0 0 10px 0;
		font-family: Verdana, Arial, Helvetica, sans-serif;
		color: #036;
	}

	h2 {
		font-size: 140%;
	}

	p {
		margin: 0 auto 1em 0;
		padding: 0 20px;
		font-size: 85%;
		line-height: 1.4;
	}

	header {
		position: absolute;
		top: -100px;
	}

	/* div wrapper оборачивает остальную часть содержания страницы. 
	Фоновое изображение для него подобрано в соответствии с цветовой гаммой моего сайта.*/

	#wrapper {
		padding:20px 0 5px;
		background: #fff url(../img/content_bg4.jpg) top left no-repeat;
		width:1070px;
		margin:0 auto;
		position:relative;
		border-left: 1px solid #A4C8D8;
		border-right: 1px solid #A4C8D8;
		min-height:490px;
	}

	/* div maincontent не имеет отступов сверху и снизу. Правый наружный 
	отступ установлен равным 10% ширины страницы и обеспечивает пространство справа. 
	* Задание максимальной и минимальной ширины обеспечивают гибкость макета. */

	main {
		margin: 0 10% 0 40px;
		min-width: 525px;
		max-width: 1050px;
	}

	main #prifase {
		width: 935px;
		font-weight: bold;
		font-size: 110%;
	}

	main #cameback {
		float: left;
		width: 90px;
		height: 60px;
		padding-left: 100px;
	}

	main #cameback >p{
		padding-top: 17px;
	}

	/* Стили для ссылок в div maincontent. */

	main a {
		font-weight: bold;
		text-decoration: none;
		padding: 2px 4px;
	}

	/* В тэге "figure" размещается основное изображение */

	figure {
		float: right;
		margin: 0 20px 0 10px;
		background-color: #efe3b3;
	}

	/* Рамка и цвет подложки для изображения */

	#main_image {
		float: left;
		text-align: center;
		width: 950px;
	}

	#main_image p {
		color:#00425E;
		font-weight: bold;
		margin: 0;
		padding: 0 auto 0 auto;
	}

	figure #mainpicture img {
		padding: 10px;
		-webkit-box-shadow: 1px 1px 15px #999999;
		box-shadow: 1px 1px 15px #999999;
	}
	#leftarraw img, #rightarraw img {
		cursor:pointer; 
		opacity: 0.3;
		}
	figure #leftarraw {
		width: 50px;
		float: left;
		margin-top: 236px;
		  margin-left: -50px;
	}
	figure #mainpicture {
		float: left;
		width: 950px;
	}
	figure #rightarraw {
		width: 50px;
		float: right;
		margin-top: 236px;
		  margin-right: -70px;
	}
	#figdesc {
		margin-left: -50px !important;
		width: 108.5%;
		background-color: #B8EBD8;
		font-size: 100%;
	}

	/* Заголовок изображения полужирный и центрированый */

	figcaption {
		margin-top: 500px;
		padding: 3px 10px;
		font-weight: bold;
		text-align: center;
	}

	/* Футер должен отобразиться ниже всего, что есть в галерее */

	footer {
		clear: both;
		background-color: #A4C8D8;
		color: #FFF;
		padding:12px;
		width:1046px;
		position:relative;
		bottom:0;
	}

	footer p {
		margin-bottom:0;
		font-size: 90%;
		font-weight:bold;
	}

	/* Класс warning депает сообщение об ошибках полужирным и красным. Используется 
	только для отладки скрипта на локальном компьютере. При переносе галереи на сервер 
	провайдера его лучше удалить. Посетителю знать о ваших проблемах не обязательно.*/

	.warning {
		font-weight: bold;
		color: #f00;
	}

	/* Стили для изображений галереи */

	#picCount {
	  color:#00425E;
	  font-weight:bold;
	  }

	#thumbs {
		float: left;
		margin-top: -5px;
		margin-left: -1%;
		margin-bottom: 5px;
	}

	#thumbs td {
		text-align: center;
	}

	#thumbs a{
		display:block;
		padding: 0;
	}

	#thumbs .picture.imgborder {
		border: 3px solid blue;
	}

	#overlay {
	  position: fixed;
	  top: 0;
	  left: 0;
	  height: 100%;
	  width: 100%;
	  background: black url(./img/spinner.gif) no-repeat scroll center center;
	}

	#lightbox {
	  position: fixed;
	}


Код, приведённый выше, обеспечивает выполнение первых четырёх пунктов требований, которые были сформулированы при планировании галереи. Мы получили галерею, функционал которой работоспособен и при отключённом JavaSсript'е. Как это всё работает, можно посмотреть на этом же сайте. Она здесь реализована.

Оставшиеся требования будем реализовывать с помощью всемогущего JavaSсript'а, но об этом в следующей статье.

Комментарии

Форма для добавления комментария отображается только авторизованным пользователям. Для того, чтобы добавить комментарий, необходимо авторизоваться.