PHP加Nginx实现动态裁剪图片方案


Posted in PHP onMarch 10, 2014

许久以前写过一篇也是关于高性能PHP图片动态裁剪方案的文章,那文章使用的是nginx Cache和rewrite实现的,当然再加上CDN,那个方案存在一个问题就是图片并没有实际生成,而是以二进制的形式存在缓存中。如果缓存失效了那么还需要请求php再次生成。如果说到区别这是我暂且认为的吧。
利用空余时间,新增了静态生成图片支持,支持对图片3种模式切换,在门户网站自动对图片尺寸进行裁剪,减少服务器带宽,理论上应该也满足了业务的需求吧,图片裁剪使用了Imagick组件。

一、思路再现:
1、先写好请求服务器生成图片动态脚本,主要就是对图片进行等比缩放计算+裁剪。
2、确定你想要生成的url规则,比如http://www.domain.com/www/300×200-1/test.jpg。
3、对浏览器做缓存处理。
4、结束。
二、动态裁剪PHP脚本

/**
 * Author pony_chiang
 * 高性能图像裁剪方案
 * 需要php-imagick扩展
 */
ini_set ( "memory_limit", "80M" );// 请求地址比如  http://yourdomain.com/resize.php?site=www&width=300&height=200&mode=2&path=uploadfile/helloworld.png
// nginx重写规则  rewrite ^([^\.]*)/s/(.*)/(\d+)x(\d+)-(\d)/(.*) $1/s/resize.php?site=$2&width=$3&height=$4&mode=$5&path=$6 last;
$path = trim ( $_GET ['path'] );
$mode = intval ( $_GET ['mode'] );
$site = trim ( $_GET ['site'] );
$width = intval ( $_GET ['width'] );
$height = intval ( $_GET ['height'] );
$site_list = array ('www' => '/mnt/webroot/test/' );
$orig_dir = dirname ( __FILE__ );
if (! array_key_exists ( $site, $site_list )) {
    header ( 'HTTP/1.1 400 Bad Request' );
    exit ();
}
if ($mode > 3 || $mode < 0) {
    header ( 'HTTP/1.1 400 Bad Request' );
    exit ();
}
$orig_file = $site_list [$site] . $path;
if (! file_exists ( $orig_file )) {
    header ( 'HTTP/1.1 404 Not Found' );
    exit ();
}
$file_ext = '.' . pathinfo ( $path, PATHINFO_EXTENSION );
$file_name = basename ( $path, $file_ext );
$save_path = "{$orig_dir}/{$site}/{$width}x{$height}-{$mode}/{$path}";
$save_dir = dirname ( $save_path );
if (! file_exists ( $save_dir ))
    wpx_mkdir ( $save_dir );
$target_width = $width;
$target_height = $height;
$new_width = $target_width;
$new_height = $target_height;
$image = new Imagick ( $orig_file );
list ( $orig_width, $orig_height, $type, $attr ) = getimagesize ( $orig_file );
if ($mode == "0") {
    //等比缩放图像
    $new_height = $orig_height * $new_width / $orig_width;
    if ($new_height > $target_height) {
        $new_width = $orig_width * $target_height / $orig_height;
        $new_height = $target_height;
    }
} else if ($mode == "2") {
    // 放大并裁剪图像
    $desired_aspect = $target_width / $target_height;
    $orig_aspect = $orig_width / $orig_height;
    if ($desired_aspect > $orig_aspect) {
        $trim = $orig_height - ($orig_width / $desired_aspect);
        $image->cropImage ( $orig_width, $orig_height - $trim, 0, $trim / 2 );
        error_log ( "HEIGHT TRIM $trim" );
    } else {
        $trim = $orig_width - ($orig_height * $desired_aspect);
        $image->cropImage ( $orig_width - $trim, $orig_height, $trim / 2, 0 );
    }
}
$image->resizeImage ( $new_width, $new_height, imagick::FILTER_LANCZOS, 1 );
$image->writeImage ( $save_path );
header ( 'Content-Type: image/jpeg' );
header ( 'Last-Modified: ' . gmdate ( 'D, d M Y H:i:s' ) . ' GMT' );
echo file_get_contents ( $save_path );
return true;
// 循环生成目录
function wpx_mkdir($dir, $mode = 0777) {
    if (is_dir ( $dir ) || @mkdir ( $dir, $mode ))
        return true;
    if (! wpx_mkdir ( dirname ( $dir ), $mode ))
        return false;
    return @mkdir ( $dir, $mode );
}

三、nginx.conf配置

server {
        listen       80;
        server_name test.yourdomain.com;
        root   /mnt/webroot/test;
        index  index.php;
        expires 30d;        location /s {
           #只有当没有生成这张图片时才调用动态裁剪
           if (!-e $request_filename) {
             rewrite ^([^\.]*)/s/(.*)/(\d+)x(\d+)-(\d)/(.*) $1/s/resize.php?site=$2&width=$3&height=$4&mode=$5&path=$6 last;
             break;
           }
        }
        error_page   404 403 402 500 502 503 504  /404.html;
        location = /404.html {
        }
        location ~ \.php$ {
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
}

PS:在文章的末尾我要特别强调一点是关于浏览器缓存的文章,不管你是否是通过php生成的图片也好,还是使用nginx缓存生成的图片也罢,在php代码中添加一行
header('Last-Modified: ' .gmdate('D, d M Y H:i:s') . ' GMT' );

对你使用CDN有十分莫大的帮助。具体产生的效果就是客户端第一次访问此文件的http状态码是200,刷新后状态码一直都是304了。
PHP 相关文章推荐
PHP学习散记_编码(json_encode 中文不显示)
Nov 10 PHP
php 如何获取数组第一个值
Aug 06 PHP
ThinkPHP基本的增删查改操作实例教程
Aug 22 PHP
PHP循环遍历数组的3种方法list()、each()和while总结
Nov 19 PHP
PDO的安全处理与事物处理方法
Oct 31 PHP
PHP实现小偷程序实例
Oct 31 PHP
PHP实现的大文件切割与合并功能示例
Apr 10 PHP
PHP 布尔值的自增与自减的实现方法
May 03 PHP
让Laravel API永远返回JSON格式响应的方法示例
Sep 05 PHP
Laravel Validator自定义错误返回提示消息并在前端展示
May 09 PHP
PHP rmdir()函数的用法总结
Jul 02 PHP
PHP 对象继承原理与简单用法示例
Apr 21 PHP
php实现文件下载简单示例(代码实现文件下载)
Mar 10 #PHP
php实现文件编码批量转换
Mar 10 #PHP
php导出word文档与excel电子表格的简单示例代码
Mar 08 #PHP
php 创建以UNIX时间戳命名的文件夹(示例代码)
Mar 08 #PHP
PHP_Cooikes不同页面无法传递的解决方法
Mar 07 #PHP
php function用法如何递归及return和echo区别
Mar 07 #PHP
详解PHP中strlen和mb_strlen函数的区别
Mar 07 #PHP
You might like
php实现与erlang的二进制通讯实例解析
2014/07/23 PHP
laravel 5 实现模板主题功能(续)
2015/03/02 PHP
php实现在多维数组中查找特定value的方法
2015/07/29 PHP
PHP使用Pthread实现的多线程操作实例
2015/11/14 PHP
php实现购物车功能(下)
2016/01/05 PHP
laravel框架select2多选插件初始化默认选中项操作示例
2020/02/18 PHP
jquery form表单提交插件asp.net后台中文解码
2010/06/12 Javascript
jQuery移动和复制dom节点实用DOM操作案例
2012/12/17 Javascript
JavaScript动态添加style节点的方法
2015/06/09 Javascript
JavaScript中子对象访问父对象的方式详解
2016/09/01 Javascript
Angular实现的table表格排序功能完整示例
2017/12/22 Javascript
vue.js中proxyTable 转发请求的实现方法
2018/09/20 Javascript
详解关于Angular4 ng-zorro使用过程中遇到的问题
2018/12/05 Javascript
微信小程序之高德地图多点路线规划过程示例详解
2021/01/18 Javascript
[02:47]3.19DOTA2发布会 国服成长历程回顾
2014/03/25 DOTA
python多重继承实例
2014/10/11 Python
在Python中使用matplotlib模块绘制数据图的示例
2015/05/04 Python
简单谈谈Python中的闭包
2016/11/30 Python
Python中的浮点数原理与运算分析
2017/10/12 Python
python进行TCP端口扫描的实现
2018/12/21 Python
Python实现FM算法解析
2019/06/18 Python
python 基于TCP协议的套接字编程详解
2019/06/29 Python
Django多数据库配置及逆向生成model教程
2020/03/28 Python
使用tensorflow进行音乐类型的分类
2020/08/14 Python
台湾团购、宅配和优惠券:17Life
2017/08/14 全球购物
怎样自定义一个异常类
2016/09/27 面试题
中专三年学习的个人自我评价
2013/12/12 职场文书
内衣营销方案
2014/03/15 职场文书
给校长的建议书200字
2014/05/16 职场文书
干部职工纪律作风整改措施思想汇报
2014/10/11 职场文书
机修车间主任岗位职责
2015/04/08 职场文书
大学生党课感想
2015/08/11 职场文书
2016年社区党支部公开承诺书
2016/03/25 职场文书
Python一行代码实现自动发邮件功能
2021/05/30 Python
详细介绍python操作RabbitMq
2022/04/12 Python
Mybatis-Plus 使用 @TableField 自动填充日期
2022/04/26 Java/Android