Подготовка мини-копий картинок (thumbs) на лету

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

Подумал я однажды, чем каждый раз перегинерировать мини-копии картинок, можно перехватить запрос для несуществующей картинки и сгенерировать мини-копию с нужным размером на лету. И попробовал это реализовать. Расскажу и вам, как я это делал, уважаемые любители Symfony.

Файл .haccess в папке web имеет инструкцию -- если запрашиваемого файла не существует, то вызывается механизм Symfony, обрабатывающий этот запрос. Воспользуемся этим для создания мини-копий.

Создаю

Мне понадобится добавить в проект модуль, к примеру uploads:

symfony generate:module frontend uploads

В routing.yml добавляю путь, имеющий такой-же url, что и папка где я буду хранить мини-копии, в этом состоит трюк. В данном случае url /uploads/thumbs.

uploads_thumbs:
 url:  /uploads/thumbs/:size/:path
 param: { module: uploads, action: thumbs }

Чтобы не писать паровоз для работы с графикой я использую прекрасный плагин для Symfony, sfThumbnailPlugin. Устанавливаю:

symfony plugin:install sfThumbnailPlugin

Приступаю к модулю, который был сгенерирован, добавляю процедуру создания уменьшенной копии в actions.class.php.

/**
 * This action will generate thumbs,  if it is not yet generated
 * and cache them to uploads/thumbs folder
 * @param sfWebRequest $request
 */
public function executeThumbs(sfWebRequest $request)
{

  $path = $request->getParameter('path');
  $size = $request->getParameter('size');
  $dir  = sfConfig::get('sf_upload_dir');

  if ( !$path || !$size || !file_exists( "$dir/thumbs/$size" ) || !file_exists( "$dir/$path")   ) $this->forward404();

  if ( !file_exists( "$dir/thumbs/$path" ) )
  {
    $thumbnail = new sfThumbnail($size, $size);
    $thumbnail->loadFile( "$dir/$path" );
    $thumbnail->save( "$dir/thumbs/$size/$path", 'image/png');
  }

  return $this->redirect( $request->getUri() );

}

По тексту понятно, что если нет одного из необходимых параметров - пути или размера, или папка с нужным размером мини-копий не создана, то выводить ошибку. Если же всё нормально, то создать мини-копию, сохранить туда где лежат мини-копии и перенаправить запрос снова по тому-же самому пути. Но на сей раз он не будет обрабатываться Symfony потому как нужный файл есть. Вот и весь трюк!

Проверяю

Создам в папке web/uploads/thumbs несколько папок с размерами мини-копий, которые мне необходимо получать, например 150, 300, 500, ставлю этим папкам права 0777, кладу в web/uploads какую-нибудь тестовую картинку 1.jpg. Пробую запросы:

  • http://localhost/my_web/uploads/thumbs/150/1.jpg
  • http://localhost/my_web/uploads/thumbs/300/1.jpg
  • http://localhost/my_web/uploads/thumbs/500/1.jpg

Но вот ничего не получается и я разбираюсь, в чём же дело.

Работа над ошибками

Первая проблема, это параметр :path, который определяется не полностью. Точка и jpg распознаётся как следующая за :path часть пути. Чтобы не было проблем с расширением файла, придётся немного допилить настройку routing. Делается это в factories.yml:

all:
  routing:
    class: sfPatternRouting
    param:
      generate_shortest_url:            true
      extra_parameters_as_query_string: true
      segment_separators:  ['/']

Здесь я измелил параметр segment_separators, который стандартно считает разделителями путей символы / и . Поскольку точка нам нужна для получения полного имени картинки, мы эту точку убираем из segment_separators. Если есть иной способ не считать точку разделителем, пожалуйста добавьте в комментарии к статье, я считаю что он есть (подсказка: with_wildcard_чтототам прямо в routing.yml, но я не помню точно).

Вторая проблема обычно вылазит на production хостинге, где папку web, как полагается, мы выносим из проекта отдельно. Указать пути к sf_web_dir и sf_upload_dir можно и другими способами, но я делаю это в settings.yml:

all:
  web_dir:    %SF_ROOT_DIR%/../my_web         #было %SF_ROOT_DIR%/web
  upload_dir: %SF_ROOT_DIR%/../my_web/uploads #было %SF_ROOT_DIR%/web/uploads

Отчищаю кэш symfony cc и пробую те же запросы сделать снова. Ура! Работает!

BlackCrystalБиблиотека → Подготовка мини-копий картинок (thumbs) на лету

Скрипт ВКонтакте MP3

Скрипт стирания выборочных сообщений со стены ВКонтакте

Скрипт удаления из всех групп ВКонтакте

Регенерация Session Id в Symfony - фича или баг?

Скрипт стирания сообщений со стены ВКонтакте

AJAX-запросы между доменами

Найти друзей слова causes. Часть первая.

Удобное размещение папки с проектом Symfony

Подготовка мини-копий картинок (thumbs) на лету

Расширяем возможности sfWebResponse

Отображение ошибок валидации

Проверка персонального кода sfValidatorIsikukood

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

1999-2009 BlackCrystal ¬|г Clan.    2007-2012 BlackCrystal Ltd.    2011-2012 BlackCrystal Club.