Практически във всяко уеб приложение, което използва изображения, съществува нужда от генериране на намалени копия на тези изображения, като често, форматите на допълнителните изображения са няколко.
Също така, добавянето на нови размери в съществуващо приложение е донякъде проблематично. Следователно задачата е:
Задача
Нека определим списъка с изисквания:
- Да генерираме допълнителни изображения в произволни формати в реално време без да добавяме допълнителен функционал в приложението по всяко време на съществуването на приложението;
- Допълнителните изображения не трябва да се генерират при всяко запитване;
- Да се затвори възможността за генериране на допълнителни изображения в нестандартни формати.
Ще обясня последната точка, тъй като тя малко противоречи на първата точка. Ако направим генерирането на всякакви изображения отворено, съществува възможност за атака на сайта чрез генериране на голямо количество запитвания за преоразмеряване на изображението в безкраен брой формати, затова тази уязвимост трябва да бъде затворена.
Конфигурация на инсталацията на nginx
За да отговорим на гореспоменатите изисквания, ще ни е необходим следният набор от модули на nginx:
- — за преоразмеряване на изображения;
- — за кеширане;
- — за защита от спам;
Модули ngx_http_image_filter_module и ngx_http_secure_link_module по подразбиране не са инсталирани, затова трябва да ги посочите по време на конфигурацията на инсталацията nginx:
phoinix@phoinix-work:~\/src\/nginx-0.8.29
$ .\/configure --with-http_secure_link_module --with-http_image_filter_module
Конфигурация на nginx
В конфигурацията на нашия хост добавяме нов location и общите параметри за кеш:
...
proxy_cache_path /www/myprojects/cache levels=1:2 keys_zone=image-preview:10m;
...
server {
...
location ~ ^/preview/([cir])/(.+) {
# Тип операции
set $oper $1;
# Параметры изображения и путь к файлу
set $remn $2;
# Проксируем на отдельный хост
proxy_pass http://myproject.ru:81/$oper/$remn;
proxy_intercept_errors on;
error_page 404 = /preview/404;
# Кеширование
proxy_cache image-preview;
proxy_cache_key "$host$document_uri";
# 200 ответы кешируем на 1 день
proxy_cache_valid 200 1d;
# остальные ответы кешируем на 1 минуту
proxy_cache_valid any 1m;
}
# Возвращаем ошибку
location = /preview/404 {
internal;
default_type image/gif;
alias /www/myprojects/image/noimage.gif;
}
...
}
...
Също така добавяме нов хост в конфигурацията:
server {
име на сървъра myproject.ru;
слушай 81;
access_log /www/myproject.ru/logs/nginx.preview.access_log;
error_log /www/myproject.ru/logs/nginx.preview.error_log info;
# Указываем секретное слово для md5
secure_link_secret secret;
# Ошибки отправляем она отдельный location
error_page 403 404 415 500 502 503 504 = @404;
# location Для фильтра size
location ~ ^/i/[^/]+/(.+) {
# грязный хак от Игоря Сысоева *
alias /www/myproject.ru/images/$1;
try_files "" @404;
# Проверяем правильность ссылки и md5
if ($secure_link = "") { return 404; }
# Используем соответсвующий фильтр
image_filter size;
}
# По аналогии остальные location для других фильтров
location ~ ^/c/[^/]+/(d+|-)x(d+|-)/(.) {
set $width $1;
set $height $2;
alias /www/myproject.ru/images/$3;
try_files "" @404;
if ($secure_link = "") { return 404; }
image_filter crop $width $height;
}
location ~ ^/r/[^/]+/(d+|-)x(d+|-)/(.) {
set $width $1;
set $height $2;
alias /www/myproject.ru/images/$3;
try_files "" @404;
if ($secure_link = "") { return 404; }
image_filter resize $width $height;
}
location @404 { return 404; }
}
В крайна сметка, допълнителните изображения могат да се изтеглят чрез линкове:
- [md5]/[path_to_image]
- [md5]/[size]/[path_to_image]
- [md5]/[size]/[path_to_image]
* try_files — чувствителен към интервалите и руски символи, затова трябваше да направим вспомагателен код с alias.
Използване в уеб приложение
На ниво уеб приложение може да се направи следната процедура (Perl):
sub proxy_image {
use Digest::MD5 qw /md5_hex/;
my %params = @_;
my $filter = {
size => 'i',
resize => 'r',
crop => 'c'
}->{$params{filter}} || 'r';
my $path = ($filter ne 'i' ?
( $params{height} || '_' ) . 'x' . ( $params{width} || '_' ) . '/'' :
()
) . $params{source};
my $md5 = md5_hex( $path . 'secret' );
$path = '/preview/' . $filter . '/' . $md5 . '/' . $path;
return $path;
}
my $preview_path = &proxy_image(
source => 'image1.jpg',
height => 100,
width => 100,
filter => 'resize'
);
Въпреки това, бих препоръчал и да се изчислят размерите preview.
Грабли
При изтриване на оригиналното изображение, предварителните визуализации, естествено, няма да бъдат премахнати от кеша, докато кешът не бъде инвалидизиран, а в нашия случай предварителните визуализации могат да съществуват до 24 часа след изтриването, но това е максимумът.
Източник: habr.com
