Часто на сайтах нужно ресайзить рисунки и в большинстве случаев это выглядит так:
  1. во время генерации страницы запускается скрипт с адресом рисунка и параметрами ресайза;
  2. скрипт проверяет нет ли уже отрезайзеного файла на сервере;
  3. если его нет, то запускается процес ресайза и сохранения файла.

Такой метод имеет ряд очевидных недостатков:
  • замедляется генерация страницы (особенно если нужно ресайзить много рисунков);
  • отресайзенные рисунки не всегда будут запрошены клиентом.

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

Идея, понятно, не новая. В интернете нашел несколько упоминаний о таком подходе, но реализация мне не понравилась. Поэтому я решил создать свой костыль набор скриптов для этого дела.
Итак, первым делом в папку, где будут хранится отресайзенные рисунки положим .htaccess файл примерно такого содержания:

RewriteEngine On

RewriteBase /lazyresizer/imgcache

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /lazyresizer/lazyresizer/resize_handler.php?path=$1 [L,QSA]


В зависимости от структуры ваших директорий замените RewriteBase и путь к resize_handler.php.

Сам resize_handler.php у меня получился таким:

include_once 'PHPThumbResizer.php';

try {
if ($_GET['path']) {
PHPThumbResizer::replaceResized($_GET['path']);
}
} catch (Exception $e) {
header('HTTP/1.1 500 Internal Server Error');
echo '<!DOCTYPE HTML>
<meta charset="utf-8">
<title>500 Internal Server Error</title>
<h1>Error</h1>
<p>'.$e->getMessage().'</p>';
}

PHPThumbResizer — это класс, который наследует мой LazyResizer и реализует метод resizeAndSave.

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

В месте, куда нужно вставить URL отресайзенного изображения, код может выглядеть так:

<?
$original = 'images/abstract-images/01.jpg';
include_once 'lazyresizer/PHPThumbResizer.php';
?>

<table>
<tr>
<td><img src="<?= $original ?>" /></td>
<td><img src="<?= PHPThumbResizer::resizedPath($original, 200, 200) ?>" /></td>
<td><img src="<?= PHPThumbResizer::resizedPath($original, 50, 100, array('mode' => 'adaptive')) ?>" /></td>
</tr>
<tr>
<th>Original</th>
<th>200x200</th>
<th>50x100 (adaptive mode)</th>
</tr>
</table>


В итоге получаем

<table>
<tr>
<td><img src="images/abstract-images/01.jpg" /></td>
<td><img src="imgcache/images/abstract-images/01(9bcfbe-200x200).jpg" /></td>
<td><img src="imgcache/images/abstract-images/01(a7fd45-50x100).jpg?mode=adaptive" ></td>
</tr>
<tr>
<th>Original</th>
<th>200x200</th>
<th>50x100 (adaptive mode)</th>
</tr>
</table>


Особенности реализации

Во-первых, рисунки будут иметь такой же путь как и оригинал, только с префиксом imgcache (или как вы назовете папку с кэшем) и с модифицированным названием файла.

Во-вторых, в названии отресазенного риунка можно увидеть 6 символов контрольной суммы, за которой через дефис следует размер. Контрольная сумма нужна для того, чтобы
  • при изменении оригинала не выдавался старый отресазенный рисунок;
  • веб-пользователи не смогли забить сервер ресайзингом рисунков простым изменением названия кеш-файла;
  • можно было создавать несколько типов отресазенных рисунков в зависимости от GET параметров.

Реализацию, которую я назвал Lazy Resizer, можно найти на github.
В качестве библиотеки ресайза, я взял PHPThumb, но как говорилось выше, можно подключить и другую библиотеку.