动态调整图像大小

几乎在所有使用图像的 Web 应用程序中,都需要创建这些图像的小型副本,并且附加图像通常有多种格式。
向现有应用程序添加新维度也会引起一些麻烦。 因此任务是:

任务

让我们表示一下要求列表:

  • 在应用程序存在期间随时生成任何格式的附加图像,而无需在应用程序中引入附加功能;
  • 不需要根据每个请求生成额外的图像;
  • 禁用生成未指定格式的其他图像的功能。

我将解释最后一点,因为它与第一点略有矛盾。 如果我们开放任何图像的生成,那么就有可能通过生成大量请求将图像大小调整为无限多种格式来攻击网站,因此需要关闭此漏洞。

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配置

我们在主机配置中添加一个新的 和一般缓存参数:

...
    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 {
    server_name                     myproject.ru;
    listen                          81;

    访问日志 /www/myproject.ru/logs/nginx.preview.access_log;
    错误日志 /www/myproject.ru/logs/nginx.preview.error_log 信息;

    # 指定md5的秘密词
    secure_link_secret 秘密;

    # 错误被发送到一个单独的位置
    错误页面 403 404 415 500 502 503 504 = @404;

    # 尺寸过滤器的位置
    位置 ~ ^/i/[^/]+/(.+) {
        
        # Igor Sysoev 的肮脏黑客行为 *
        别名/www/myproject.ru/images/$1;
        尝试文件“”@404;
    
        #检查链接和md5的正确性
        如果 ($secure_link = "") { 返回 404; }
        
        # 使用适当的过滤器
        图像过滤器尺寸;
    }

    # 以此类推,其他过滤器的其余位置
    位置 ~ ^/c/[^/]+/(d+|-)x(d+|-)/(.+) {
        设置$宽度$1;
        设置$高度$2;
        
        别名/www/myproject.ru/images/$3;
        尝试文件“”@404;
    
        如果 ($secure_link = "") { 返回 404; }
    
        图像过滤器裁剪$宽度$高度;
    }
    
    位置 ~ ^/r/[^/]+/(d+|-)x(d+|-)/(.+) {
        设置$宽度$1;
        设置$高度$2;

        别名/www/myproject.ru/images/$3;
        尝试文件“”@404;

        如果 ($secure_link = "") { 返回 404; }

        图像过滤器调整$宽度$高度;
    }

    位置@404 { 返回404; }
}

因此,可以使用以下链接获取其他图像:

* 尝试文件 - 对空格和俄语字符敏感,所以我不得不用 别号.

在网络应用程序中使用

在 Web 应用程序级别,您可以执行以下过程 (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;
}

我的 $preview_path = &proxy_image(
                    源 => 'image1.jpg',
                    高度 => 100,
                    宽度 => 100,
                    过滤器 => '调整大小'
                );

虽然我也建议计算尺寸 预览.

当删除原始图像时,预览自然不会从缓存中删除,直到缓存失效,而在我们的例子中,预览在删除后可以存在一天,但这是最长的时间。

原来的

来源: habr.com

添加评论