Redimensionnement d'images à la volée

Dans presque toutes les applications web utilisant des images, il existe un besoin de générer des copies réduites de ces images, et souvent, il y a plusieurs formats d'images supplémentaires.
L'ajout de nouvelles tailles à une application existante peut aussi causer quelques soucis. Voici donc le problème :

La tâche

Définissons la liste des exigences :

  • Générer des images supplémentaires de tous formats à la volée sans ajouter de fonctionnalités supplémentaires à l'application à tout moment de son existence ;
  • Des images supplémentaires ne doivent pas être générées à chaque demande ;
  • Fermer la possibilité de générer des images supplémentaires dans des formats non définis.

J'expliquerai ce dernier point, car il contredit légèrement le premier point. Si nous ouvrons la génération de toutes les images, il existe un risque d'attaque sur le site par la génération d'un grand nombre de requêtes pour redimensionner une image dans un nombre infini de formats, donc cette vulnérabilité doit être sécurisée.

Configuration de l'installation de nginx

Pour répondre aux exigences susmentionnées, nous aurons besoin du jeu de modules nginx suivant :

Modules ngx_http_image_filter_module et ngx_http_secure_link_module par défaut, ils ne sont pas installés, donc ils doivent être spécifiés lors de la configuration de l'installation nginx:

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

Configuration de nginx

Dans la configuration de notre hôte, nous ajoutons un nouveau location et les paramètres globaux de mise en cache :

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

Nous ajoutons également un nouvel hôte dans la configuration :

server {
    nom_du_serveur                     myproject.ru;
    écoute                          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; }
}

En conséquence, les images supplémentaires peuvent être récupérées via les liens :

* try_files — sensible aux espaces et aux caractères russes, il a donc fallu créer un contournement avec alias.

L'utilisation dans une application web

Au niveau de l'application web, nous pouvons effectuer la procédure suivante (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'
                );

Bien que je recommande également de calculer les dimensions preview.

Rake

Lors de la suppression de l'image d'origine, les aperçus, bien sûr, ne seront pas supprimés du cache tant que le cache n'est pas invalidé, et dans notre cas, les aperçus peuvent exister jusqu'à un jour après la suppression, mais c’est le maximum.

original

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster