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 相关文章推荐
完美解决dedecms中的[html][/html]和[code][/code]问题
Mar 20 PHP
手把手教你使用DedeCms V3的在线采集图文教程
Apr 03 PHP
php 字符过滤类,用于过滤各类用户输入的数据
May 27 PHP
c#中的实现php中的preg_replace
Dec 21 PHP
PHP操作MySQL事务实例
Nov 05 PHP
php+mysqli批量查询多张表数据的方法
Jan 29 PHP
php上传图片生成缩略图(GD库)
Jan 06 PHP
PHP框架laravel的.env文件配置教程
Jun 07 PHP
关于ThinkPhp 框架表单验证及ajax验证问题
Jul 19 PHP
php实现微信公众平台发红包功能
Jun 14 PHP
PHP设计模式之PHP迭代器模式讲解
Mar 22 PHP
PHP进阶学习之类的自动加载机制原理分析
Jun 18 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生成静态页
2006/11/25 PHP
解析PHP中的内存管理,PHP动态分配和释放内存
2013/06/28 PHP
php常用文件操作函数汇总
2014/11/22 PHP
jQuery 跨域访问问题解决方法
2009/12/02 Javascript
jquery选择器原理介绍($()使用方法)
2014/03/25 Javascript
jQery使网页在显示器上居中显示适用于任何分辨率
2014/06/09 Javascript
Jquery弹出层插件ThickBox的使用方法
2014/12/09 Javascript
JQuery中serialize() 序列化
2015/03/13 Javascript
AngularJs验证重复密码的方法(两种)
2016/11/25 Javascript
Bootstrap实现渐变顶部固定自适应导航栏
2020/08/27 Javascript
微信小程序slider组件使用详解
2018/01/31 Javascript
Vue.js 中的 v-cloak 指令及使用详解
2018/11/19 Javascript
微信小程序新手教程之页面打开数量限制
2019/03/03 Javascript
3分钟了解vue数据劫持的原理实现
2019/05/01 Javascript
JavaScript中如何对多维数组(矩阵)去重的实现
2019/12/04 Javascript
[03:42]2014DOTA2西雅图国际邀请赛7月9日TOPPLAY
2014/07/09 DOTA
Python入门篇之编程习惯与特点
2014/10/17 Python
python中split方法用法分析
2015/04/17 Python
Python爬虫实现网页信息抓取功能示例【URL与正则模块】
2017/05/18 Python
Python基于正则表达式实现文件内容替换的方法
2017/08/30 Python
Python实现XML文件解析的示例代码
2018/02/05 Python
200行python代码实现2048游戏
2019/07/17 Python
Django中自定义admin Xadmin的实现代码
2019/08/09 Python
Python如何优雅获取本机IP方法
2019/11/10 Python
Spring http服务远程调用实现过程解析
2020/06/11 Python
Python3.8安装Pygame教程步骤详解
2020/08/14 Python
俄罗斯家居用品购物网站:Евродом
2020/11/21 全球购物
传统软件工程与面向对象的软件工程有什么区别
2012/05/31 面试题
给国外客户的邀请函
2014/01/30 职场文书
写自荐信的注意事项
2014/03/09 职场文书
贷款委托书范本
2014/04/08 职场文书
2014年档案管理员工作总结
2014/12/01 职场文书
2015年八一建军节慰问信
2015/03/23 职场文书
课题研究阶段性总结
2015/08/13 职场文书
2016新年问候语大全
2015/11/11 职场文书
SQL Server数据定义——模式与基本表操作
2021/04/05 SQL Server