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

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

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

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

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

Примечание: Если вы решите изменять размеры картинок, при помощи CSS, то вас ждет один неприятный сюрприз. Дело в занимаемом дисковом пространстве картинок. К примеру, если вы выведите на сайте 100Кб картинку, и установите в CSS свойство width в "50px", то, несмотря на то, что картинка будет выглядеть маленькой, она по прежнему будет занимать 100Кб. Наверное, вы уже понимаете сколько лишнего трафика будет проходить каждый раз, когда будет открываться страница хотя бы с десятком таких миниатюр.

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

Пишем инструмент для автоматического создания миниатюр

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

Перед тем, как начинать писать инструмент, необходимо определиться с минимальным набором требований. После некоторого времени у вас появиться подобного рода список:

  • Уникальность имен миниатюр. Когда у вас много статей или товаров, то, велика вероятность, что найдутся, как минимум, два изображения с одинаковыми названиями. Так же вы просто можете сортировать картинки по каталогам, не заботясь об уникальности имен.
  • Поддержка разных типов картинок. В основном, это gif, png и jpg.
  • Динамические размеры. В любой момент времени вам могут потребоваться другие размеры миниатюр. Например, вы изменили немного верстку для отображения элементов списка и вам необходимо изменить размеры миниатюр. Это действие должно решаться простым изменением параметра в url.
  • Кэширование картинок. Картинки должны не только физически создаваться на диске (т.к. изменение размера изображения занимает время), но и кэшироваться браузером (каждое обращение за картинкой - это лишний запрос). А так же сами картинки должны периодически заново создаваться. Ведь, возможно, что какие-то картинки были изменены, со времени создания миниатюр.
  • Возможность быстро удалить все миниатюры. Все миниатюры должны храниться в одном месте. В противном случае, банальная очистка сайта от лишних файлов или необходимость массового пересоздания миниатюр вызовут у вас определенные трудности. 
  • Простота внедрения. Скрипт должен легко встраиваться на любой сайт и использовать минимальный набор базовых функций языка php. 

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

Создайте файл с названием "thumb.php" и внесите первый блок - блок с параметрами:

<?
/* ВАЖНО */
/* Вначале необходимо создать директорию для хранения миниатюр */
 
/* Параметры */
// Каталог для хранения миниатюр
$path_thumbs = 'images/thumbs/';
// Минимальный размер миниатюры (ширина)
$size_min = 1;
// Размер миниатюры по умолчанию (ширина)
$size_def = 40;
// Максимальный размер миниатюры (ширина)
$size_max = 1600;
// Время актуальности кэша миниатюры 
$cache_lifetime = 84000 * 30; 
// Значение id по умолчанию
$id_def = 0;

В этом блоке определены следующие параметры: каталог для хранения миниатюр, ограничения размера (ширины) и его значение по умолчанию, время кэширования результата, значение идентификатора по умолчанию. Если большая часть параметров понятна, то параметр идентификатора необходимо пояснить. Идентификатор используется для того, чтобы отделить картинки с одинаковыми названиями друг от друга. Целочисленный ID есть практически везде, он есть у любой статьи и у любого товара. В крайнем случае, его достаточно просто определить.

Примечание: Изменение размера картинки происходит пропорционально, поэтому достаточно использовать только ширину миниатюры.

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

  • site.ru/thumb.php?[id={Идентификатор}]&[s={Ширина}]&[f={Полный путь к изображению}]

Примечание: Короткие имена выбраны для простоты. Вы можете изменить названия параметров, но тогда придется немного подкорректировать код. 

Определяем блок:

// Проверяем наличие параметра с полным путем к картинке
if ( isset($_GET['f']) ) $f = (string) $_GET['f']; 
// Если параметра нет, то выходим
else exit;
 
// Получаем информацию о пути
$path_parts = pathinfo($f);
 
// Получаем родительский каталог,
// где хранится картинка
$path_images = $path_parts['dirname'];
// Получаем полное название картинки
$f = $path_parts['basename'];
// Разбираем название файла
$image_filename = basename($f,'.'.$path_parts['extension']);
$image_extension = $path_parts['extension'];
 
// Проверяем, что название картинки состоит из символов, тире и цифр
// Вы можете удалить эту проверку, 
// например, в случае если вы используете кириллицу
if ( !preg_match('/^([a-zA-Z0-9-_\.]{1,100})$/', $f) ) exit;
 
// Получаем ширину файла
if ( isset($_GET['s']) ) $s = (int) $_GET['s'];
else $s = $size_def;
// Проверяем ограничение минимального размера миниатюры
if ( $s < $size_min ) $s = $size_min;
// Проверяем ограничение максимального размера миниатюры
if ( $s > $size_max ) $s = $size_max;
 
// Используем id статьи как унификатор
if ( isset($_GET['id']) ) $id = (int) $_GET['id'];
else $id = $id_def;
// Идентификатор не может быть отрицательным
if ($id < 0) $id = $id_def;

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

// Проверка наличия функции для получения типа
if ( !function_exists('mime_content_type') ) {
    function mime_content_type($f) {
        $extension = pathinfo($f, PATHINFO_EXTENSION);
        $extension = strtolower($extension);
        switch ( $extension ) {
            case 'jpg':
            case 'jpeg': return 'image/jpeg'; break;
            case 'png':
            case 'gif': return 'image/'. $extension; break;
        }
    }
}

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

// Формируем физический путь к миниатюре
$file_thumb = $_SERVER['DOCUMENT_ROOT'] . '/' . $path_thumbs . $image_filename .'-thumb-' . $id . '-' . $s .'.'. $image_extension;
 
// Если файл с миниатюрой существует
if ( file_exists($file_thumb) ) {
    $cache_modified = time() - @filemtime($file_thumb);
    // Если время кэширования картинки не истекло,
    // то возвращаем картинку
    if ( $cache_modified < $cache_lifetime ) {
        // Время последнего изменения
        header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($file_thumb)) .' GMT', true, 200);
        // Длина
        header('Content-Length: '. filesize($file_thumb));
        // Тип
        header('Content-Type: '. mime_content_type($file_thumb));
        // Кэширование
        header("Cache-Control: public");
        header("Expires: " . date("r", @filemtime($file_thumb) + $cache_lifetime));
        echo file_get_contents($file_thumb);
        exit;
    }
}

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

// Формируем физический путь к картинке
$file_image = $_SERVER['DOCUMENT_ROOT'] . '/' . $path_images .'/'. $f;
 
// Если картинка существует,
// то создаем миниатюру
if ( file_exists($file_image) ) {
    // Получаем размеры и тип файла
    $is = getimagesize($file_image);
    // Если файл не является изображением,
    // то ничего не возвращаем
    if ( $is === false ) exit;
 
    // В соответствии с типом получаем картинку
    switch ( $is[2] ) {
        case 1: $image = imagecreatefromgif($file_image); break;
        case 2: $image = imagecreatefromjpeg($file_image); break;
        case 3: $image = imagecreatefrompng($file_image); break;
        default: exit; break;
    }
 
    // Считаем коэффициент для изменения размера высоты
    $coefficient = $s / $is[0] ;
 
    // Если ширина картинки больше требуемой
    if ( $is[0] > $s ) {
        $th_width = $s;
        $th_height = floor($is[1] * $coefficient); 
        $thumb = imagecreatetruecolor($th_width, $th_height);
        imagecopyresampled($thumb, $image, 0, 0, 0, 0, $th_width, $th_height, $is[0], $is[1]);
    } 
    // Иначе отдаем картинку "как есть"
    // Примечание: Увеличение картинки в большинстве случаев сделает ее некрасивой.
    // Поэтому лучше заменить слишком мелкую картинку и затем заменить ее большой.
    // Например, из картинки 16х16 врядли получится нормальная картинка 200х200
    else { $thumb = $image;}
 
    // Сохраняем файл, в соответствии с типом
    switch ( $is[2] ) {
        case 1: imagegif($thumb, $file_thumb); break;
        case 2: imagejpeg($thumb, $file_thumb); break;
        case 3: imagepng($thumb, $file_thumb); break;
        default: exit; break;
    }
 
    // Отдаем изображение браузеру
    header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($file_thumb)) .' GMT', true, 200);
    header('Content-Length: '. filesize($file_thumb));
    header('Content-Type: '. mime_content_type($file_thumb));
    header("Cache-Control: public");
    header("Expires: " . date("r", time() + $cache_lifetime));
    echo file_get_contents($file_thumb);
}

На выходе получился небольшой инструмент, который динамически создает и кэширует миниатюры с уникальными названиями в одном каталоге, поддерживает разные форматы картинок и просто внедряется. Таким образом, php-скрипт полностью выполняет все требования.

Настраиваем php-скрипт для автоматического изменения размеров изображений

Примечание: Если вы пропустили раздел "Пишем инструмент" или же не создавали файл, то скачать готовый файл вы можете тут: thumb.zip

Полученный файл скопируйте в то место, где вам будет угодно. Например, в папку "utils". После чего приступите к настройке. Откройте файл и перезапишите настройки по умолчанию:

  • $path_thumbs - путь к папке для хранения миниатюрами (по умолчанию путь 'images/thumbs/'). Не забудьте создать этот каталог.
  • $size_min - минимальная ширина миниатюры в пикселях (по умолчанию 1). 
  • $size_def - ширина миниатюр в пикселях по умолчанию (по умолчанию 40)
  • $size_max - максимальный размер в пикселях миниатюры (по умолчанию 1600)
  • $cache_lifetime - время кэширования каждой миниатюры в секундах (по умолчанию 84000 * 30, т.е. тридцать дней)
  • $id_def - значение идентификатора по умолчанию (по умолчанию 0). Идентификатор применяется для создания уникальных имен миниатюр.

После внесения настроек, php-скрипт для автоматического изменения размеров уже можно использовать. Для этого еще раз вспоминаем шаблон:

  • site.ru/utils/thumb.php?[id={Идентификатор}]&[s={Ширина}]&[f={Полный путь к изображению}]

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

  • site.ru/utils/thumb.php?id=15&s=100&f=images/razdel-1/statya-15/start.png

Однако, в эпоху использования красивых ЧПУ ссылок, такой запрос будет выглядеть несколько некрасиво. Поэтому необходимо добавить в файл ".htaccess" в корне сайта следующие строки (при условии, что хостинг поддерживает mod_rewrite и что в файле .htaccess есть строка с "RewriteEngine On"):

#Добавлять строки после строки "RewriteEngine On"
#Thumbs
RewriteRule ^thumb/([0-9]{1,11})/([0-9]{1,11})/(.*) utils/thumb.php?id=$1&s=$2&f=$3 [L,QSA]

Теперь, к существующему шаблону добавился еще один:

  • site.ru/thumb/{Идентификатор}/{Ширина}/{Полный путь к изображению}

После этого, пример реального запроса будет выглядеть следующим образом:

  • site.ru/thumb/15/100/images/razdel-1/statya-15/start.png

Миниатюры, по сути, дублируют изображения на сайте. Поэтому может потребоваться настройка файла robots.txt. Конечно, поисковые системы должны адекватно реагировать на существование миниатюр, и не считать это за попытку манипуляцией поисковой выдачи. Тем не менее, если вы сомневаетесь в этом, то стоит добавить к правилам в robots.txt следующие строки (при условии, что thumb.php находится в папке utils):

Disallow: /thumb/
Disallow: /utils/thumb.php

Теперь, у вас есть отличный инструмент для автоматического изменения размеров изображений на php, который динамически создает и кэширует миниатюры с уникальными названиями в одной директории, поддерживает разные форматы изображений и легко внедряется на любой сайт.

Скачать готовый инструмент можно тут:

thumb.zip 

☕ Понравился обзор? Поделитесь с друзьями!

Добавить комментарий / отзыв

Комментарий - это вежливое и наполненное смыслом сообщение (правила).



* Нажимая на кнопку "Отправить", Вы соглашаетесь с политикой конфиденциальности.
Присоединяйтесь
 

 

Программы (Freeware, OpenSource...)