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 相关文章推荐
一个程序下载的管理程序(二)
Oct 09 PHP
PHP MemCached 高级缓存应用代码
Aug 05 PHP
探讨如何把session存入数据库
Jun 07 PHP
php三维数组去重(示例代码)
Nov 26 PHP
php简单smarty入门程序实例
Jun 11 PHP
Symfony的安装和配置方法
Mar 17 PHP
PHP实现通过URL提取根域名
Mar 31 PHP
php微信公众平台开发(一) 配置接口
Dec 06 PHP
thinkPHP模板引擎用法示例
Dec 08 PHP
php5.5使用PHPMailer-5.2发送邮件的完整步骤
Oct 14 PHP
php + WebUploader实现图片批量上传功能
May 06 PHP
laravel5环境隐藏index.php后缀(apache)的方法
Oct 12 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常用代码大全(新手入门必备)
2010/06/29 PHP
PHP 计算代码执行耗时的代码修正网上普遍错误
2011/05/14 PHP
php 抽象类的简单应用
2011/09/06 PHP
基于thinkPHP类的插入数据库操作功能示例
2017/01/06 PHP
thinkphp中U方法按路由规则生成url的方法
2018/03/12 PHP
php的单例模式及应用场景详解
2021/02/27 PHP
JAVASCRIPT IE 与 FF中兼容问题小结
2009/02/18 Javascript
extjs 列表框(multiselect)的动态添加列表项的方法
2009/07/31 Javascript
javaScript parseInt字符转化为数字函数使用小结
2009/11/05 Javascript
javascript中关于执行环境的杂谈
2011/08/14 Javascript
jquery实现文字由下到上循环滚动的实例代码
2013/08/09 Javascript
JavaScript基础函数整理汇总
2015/01/30 Javascript
easyui validatebox验证
2016/04/29 Javascript
JavaScript开发Chrome浏览器扩展程序UI的教程
2016/05/16 Javascript
vue.js 1.x与2.0中js实时监听input值的变化
2017/03/15 Javascript
ES6中Symbol类型用法实例详解
2017/04/06 Javascript
自定义PC微信扫码登录样式写法
2017/12/12 Javascript
javascript数据结构之多叉树经典操作示例【创建、添加、遍历、移除等】
2018/08/01 Javascript
Layui给数据表格动态添加一行并跳转到添加行所在页的方法
2018/08/20 Javascript
Node.js创建一个Express服务的方法详解
2020/01/06 Javascript
vue项目配置同一局域网可使用ip访问的操作
2020/10/23 Javascript
原生JS实现pc端轮播图效果
2020/12/21 Javascript
Python模块的制作方法实例分析
2019/12/21 Python
详解用Python进行时间序列预测的7种方法
2020/03/13 Python
Python实现像awk一样分割字符串
2020/09/15 Python
Python 测试框架unittest和pytest的优劣
2020/09/26 Python
师范毕业生求职自荐信
2013/09/25 职场文书
销售人员个人求职信
2013/09/26 职场文书
师范大学音乐表演专业求职信
2013/10/23 职场文书
学生干部的自我评价分享
2014/01/18 职场文书
行政管理毕业生自荐信
2014/02/24 职场文书
GMP办公室主任岗位职责
2014/03/14 职场文书
保密工作责任书
2014/04/16 职场文书
娱乐节目策划方案
2014/06/10 职场文书
Goland使用Go Modules创建/管理项目的操作
2021/05/06 Golang
从np.random.normal()到正态分布的拟合操作
2021/06/02 Python