Pull to refresh

Отложенный ресайз рисунков с использованием Apache mod_rewrite и PHP

Часто на сайтах нужно ресайзить рисунки и в большинстве случаев это выглядит так:
  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, но как говорилось выше, можно подключить и другую библиотеку.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.