Динамично преоразяване на изображения

Практически във всяко уеб приложение, използващо изображения, съществува нужда да се генерират намалени копия на тези изображения, като често се налага да се работи с няколко формата на допълнителни изображения.
Също така добавянето на нови размери в съществуващото приложение създава известни затруднения. Оттук идва задачата:

Задача

Да обозначим списък с изисквания:

  • Да се генерират допълнителни изображения на всякакви формати в реално време, без да се добавя допълнителна функционалност в приложението по всяко време на съществуването му;
  • Допълнителните изображения не трябва да се генерират при всяко запитване;
  • Да се затвори възможността за генериране на допълнителни изображения с неустановени формати.

Ще обясня последната точка, тъй като тя леко противоречи на първата. Ако направим генерирането на каквито и да било изображения открито, съществува вероятност за атака на сайта чрез генериране на голямо количество запитвания за преоразмеряване на изображението в безкрайно много формати, затова е необходимо да се изключи тази уязвимост.

Конфигурация на инсталацията на 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; }
}

В крайна сметка допълнителните изображения могат да се изтеглят по следните линкове:

* 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

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster