Praticamente in qualsiasi applicazione web che utilizza immagini c'è la necessità di generare miniature di queste immagini, e spesso ci sono diversi formati di immagini supplementari.
Aggiungere nuove dimensioni a un'applicazione esistente può essere piuttosto complicato. Da qui la necessità:
Compito
Definiamo un elenco di requisiti:
- Generare immagini supplementari in qualsiasi formato al volo senza aggiungere funzionalità extra all'applicazione in qualsiasi momento della sua esistenza;
- Le immagini supplementari non devono essere generate ad ogni richiesta;
- Limitare la generazione di immagini supplementari a formati non stabiliti.
Spiegherò quest'ultimo punto, poiché è leggermente in contraddizione con il primo. Se rendiamo possibile la generazione di qualsiasi immagine, esiste la possibilità di attacco al sito da parte di un numero eccessivo di richieste per il ridimensionamento delle immagini in una quantità infinita di formati, pertanto questa vulnerabilità deve essere chiusa.
Configurazione dell'installazione di nginx
Per soddisfare i requisiti sopra citati avremo bisogno del seguente set di moduli nginx:
- — per il ridimensionamento delle immagini;
- — per la cache;
- — per protezione dallo spam;
Moduli ngx_http_image_filter_module e ngx_http_secure_link_module per impostazione predefinita non sono inclusi, quindi devono essere specificati nella fase di configurazione dell'installazione nginx:
phoinix@phoinix-work:~/src/nginx-0.8.29
$ ./configure --with-http_secure_link_module --with-http_image_filter_module
Configurazione di nginx
Aggiungiamo nel file di configurazione del nostro host un nuovo location e parametri generali per la cache:
...
proxy_cache_path /www/myprojects/cache livelli=1:2 chiave_zona=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;
}
...
}
...
Aggiungiamo anche un nuovo host nel configurazione:
server {
server_name myproject.ru;
listen 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; }
}
Di conseguenza, le immagini supplementari possono essere recuperate tramite i seguenti link:
- [md5]/[path_to_image]
- [md5]/[size]/[path_to_image]
- [md5]/[size]/[path_to_image]
* try_files — sensibile agli spazi e ai caratteri russi, quindi è stato necessario implementare un workaround con alias.
Utilizzo nell'applicazione web
A livello dell'applicazione web, è possibile realizzare la seguente procedura (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'
);
Anche se consiglio di considerare le dimensioni anteprima.
Rastrelli
Al momento della rimozione dell'immagine originale, i preview non verranno rimossi dalla cache finché la cache non viene invalidata, e nel nostro caso i preview possono esistere per un massimo di 24 ore dopo la rimozione, ma questo è il massimo temporale.
Fonte: habr.com
