Bildgröße zur Laufzeit ändern

In nahezu jeder Webanwendung, die Bilder verwendet, besteht die Notwendigkeit, reduzierte Kopien dieser Bilder zu erstellen. Oftmals gibt es mehrere Formate zusätzlicher Bilder.
Es verursacht auch einige Kopfschmerzen, neue Größen in einer bestehenden Anwendung hinzuzufügen. Daher die Aufgabe:

Aufgabe

Lassen Sie uns die Liste der Anforderungen festlegen:

  • Zusätzliche Bilder beliebiger Formate dynamisch zu erstellen, ohne zusätzliche Funktionen in die Anwendung einzufügen, zu jedem Zeitpunkt während der Lebensdauer der Anwendung;
  • Zusätzliche Bilder dürfen nicht bei jeder Anfrage generiert werden;
  • Die Möglichkeit, zusätzliche Bilder in nicht festgelegten Formaten zu generieren, muss gesperrt werden.

Ich erkläre den letzten Punkt, da er dem ersten Punkt etwas widerspricht. Wenn wir die Erstellung beliebiger Bilder offen lassen, besteht die Möglichkeit, dass die Website durch das Generieren einer großen Anzahl von Anfragen zur Größenänderung von Bildern in unendlich vielen Formaten angegriffen wird, weshalb diese Sicherheitsanfälligkeit geschlossen werden muss.

nginx Installation Konfiguration

Um die oben genannten Anforderungen zu erfüllen, benötigen wir folgendes Modulset für nginx:

Module ngx_http_image_filter_module und ngx_http_secure_link_module sind standardmäßig nicht installiert, daher müssen sie während der Installationskonfiguration angegeben werden. nginx:

phoinix@phoinix-arbeit:~/src/nginx-0.8.29
$ ./configure --with-http_secure_link_module --with-http_image_filter_module

nginx Konfiguration

In die Konfiguration unseres Hosts fügen wir neu hinzu Standort und allgemeine Cache-Parameter:

...
    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;
        }
...
    }
...

Außerdem fügen wir einen neuen Host zur Konfiguration hinzu:

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; }
}

Insgesamt können zusätzliche Bilder über die Links abgerufen werden:

* try_files — empfindlich gegenüber Leerzeichen und russischen Zeichen, daher musste ich einen Workaround mit Alias.

Verwendung in einer Webanwendung

Auf der Ebene der Webanwendung kann das folgende Verfahren (Perl) durchgeführt werden:

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'
                );

Obwohl ich auch empfehlen würde, die Größen zu berechnen Vorschau.

Grapple

Beim Löschen des Originalbildes werden die Vorschauen natürlich nicht aus dem Cache entfernt, solange der Cache nicht invalidiert wird. In unserem Fall können die Vorschauen jedoch bis zu 24 Stunden nach der Löschung bestehen bleiben, aber das ist das Maximum.

Original

Quelle: habr.com

60GB SSD 8Gb DDR4