公告:

欢迎访问元元本本博客-关注建站技术、SEO优化、主机服务器、站长学习分享!

缩略图利器timthumb.php源代码详细注解

作者:元元本本博客 / 时间:2个月前 (10/22) / 分类:网站建设 / 阅读:60 / 评论:0

Timthumb.php是款很流行的用来裁剪图片生成缩略图的工具,该缩略图工具只有timthumb.php这一个文件,而该文件只有一个timthumb类,但功能非常的强大,被广泛应用于php网站作为缩略图插件。很多人知道timthumb.php也懂得运用,但是对于该文件的源代码可能也有很多人不了解,因此从oschina转载了一篇关于timthumb.php源码详解的文章分享给大家参考学习。

注释完的文件代码如下:

代码较多(2000多行),所以分成几部分:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
<?php//定义版本信息define ('VERSION', '2.8.10');//如果有配置文件,则加载timthumb-config.php,没有的话使用下面的值if( file_exists(dirname(__FILE__) . '/timthumb-config.php')){  require_once('timthumb-config.php');}//调试日志记录到web服务器日志中if(! defined('DEBUG_ON') ){  define ('DEBUG_ON', false);}//调试级别,高于这个值的level都不会记录,1最低,3最高if(! defined('DEBUG_LEVEL') ){  define ('DEBUG_LEVEL', 1);}//最大占用内存限制30Mif(! defined('MEMORY_LIMIT') ){  define ('MEMORY_LIMIT', '30M');}//关闭仿盗链if(! defined('BLOCK_EXTERNAL_LEECHERS') ){  define ('BLOCK_EXTERNAL_LEECHERS', false);} // 允许从外部获取图片if(! defined('ALLOW_EXTERNAL') ){  define ('ALLOW_EXTERNAL', TRUE);}//允许获取所有外部站点urlif(! defined('ALLOW_ALL_EXTERNAL_SITES') ){  define ('ALLOW_ALL_EXTERNAL_SITES', false);}//启用文件缓存if(! defined('FILE_CACHE_ENABLED') ){  define ('FILE_CACHE_ENABLED', TRUE);}//文件缓存更新时间,sif(! defined('FILE_CACHE_TIME_BETWEEN_CLEANS')){  define ('FILE_CACHE_TIME_BETWEEN_CLEANS', 86400);}//文件缓存生存时间,s,过了这个时间的缓存文件就会被删除if(! defined('FILE_CACHE_MAX_FILE_AGE') ){  define ('FILE_CACHE_MAX_FILE_AGE', 86400);}//缓存文件后缀if(! defined('FILE_CACHE_SUFFIX') ){  define ('FILE_CACHE_SUFFIX', '.timthumb.txt');}//缓存文件前缀if(! defined('FILE_CACHE_PREFIX') ){  define ('FILE_CACHE_PREFIX', 'timthumb');}//缓存文件目录,留空则使用系统临时目录(推荐)if(! defined('FILE_CACHE_DIRECTORY') ){  define ('FILE_CACHE_DIRECTORY', './cache');}//图片最大尺寸,此脚本最大能处理10485760字节的图片,也就是10Mif(! defined('MAX_FILE_SIZE') ){  define ('MAX_FILE_SIZE', 10485760);}  //CURL的超时时间if(! defined('CURL_TIMEOUT') ){  define ('CURL_TIMEOUT', 20);}//清理错误缓存的时间if(! defined('WAIT_BETWEEN_FETCH_ERRORS') ){  define ('WAIT_BETWEEN_FETCH_ERRORS', 3600);}//浏览器缓存时间if(! defined('BROWSER_CACHE_MAX_AGE') ){  define ('BROWSER_CACHE_MAX_AGE', 864000);}//关闭所有浏览器缓存if(! defined('BROWSER_CACHE_DISABLE') ){  define ('BROWSER_CACHE_DISABLE', false);}//最大图像宽度if(! defined('MAX_WIDTH') ){  define ('MAX_WIDTH', 1500);}//最大图像高度if(! defined('MAX_HEIGHT') ){  define ('MAX_HEIGHT', 1500);}//404错误时显示的提示图片地址,设置测值则不会显示具体的错误信息if(! defined('NOT_FOUND_IMAGE') ){  define ('NOT_FOUND_IMAGE', '');}//其他错误时显示的提示图片地址,设置测值则不会显示具体的错误信息if(! defined('ERROR_IMAGE') ){  define ('ERROR_IMAGE', '');}//PNG图片背景颜色,使用false代表透明if(! defined('PNG_IS_TRANSPARENT') ){  define ('PNG_IS_TRANSPARENT', FALSE);}//默认图片质量if(! defined('DEFAULT_Q') ){  define ('DEFAULT_Q', 90);}//默认 缩放/裁剪 模式,0:根据传入的值进行缩放(不裁剪), 1:以最合适的比例裁剪和调整大小(裁剪), 2:按比例调整大小,并添加边框(裁剪),2:按比例调整大小,不添加边框(裁剪)if(! defined('DEFAULT_ZC') ){  define ('DEFAULT_ZC', 1);}//默认需要对图片进行的处理操作,可选值和参数格式请参看processImageAndWriteToCache函数中的$filters和$imageFilters的注释if(! defined('DEFAULT_F') ){  define ('DEFAULT_F', '');}//是否对图片进行锐化if(! defined('DEFAULT_S') ){  define ('DEFAULT_S', 0);}//默认画布颜色if(! defined('DEFAULT_CC') ){  define ('DEFAULT_CC', 'ffffff');}//以下是图片压缩设置,前提是你的主机中有optipng或者pngcrush这两个工具,否则的话不会启用此功能//此功能只对png图片有效if(! defined('OPTIPNG_ENABLED') ){  define ('OPTIPNG_ENABLED', false);}  if(! defined('OPTIPNG_PATH') ){  define ('OPTIPNG_PATH', '/usr/bin/optipng');} //优先使用optipng,因为有更好的压缩比 if(! defined('PNGCRUSH_ENABLED') ){  define ('PNGCRUSH_ENABLED', false);} if(! defined('PNGCRUSH_PATH') ){  define ('PNGCRUSH_PATH', '/usr/bin/pngcrush');} //optipng不存在的话,使用pngcrush//图片压缩设置结束  /*  * * 以下是网站截图配置 * 首先,网站截图需要root权限 * Ubuntu 上使用网站截图的步骤: *  1.用这个命令安装Xvfb  sudo apt-get install subversion libqt4-webkit libqt4-dev g++ xvfb *  2.新建一个文件夹,并下载下面的源码 *  3.用这个命令下载最新的CutyCapt  svn co https://cutycapt.svn.sourceforge.net/svnroot/cutycapt *  4.进入CutyCapt文件夹 *  5.编译并安装CutyCapt *  6.尝试运行以下命令:  xvfb-run --server-args="-screen 0, 1024x768x24" CutyCapt --url="http://markmaunder.com/" --out=test.png *  7.如果生成了一个 test.php的图片,证明一切正常,现在通过浏览器试试,访问下面的地址:http://yoursite.com/path/to/timthumb.php?src=http://markmaunder.com/&webshot=1 * * 需要注意的地方: *  1.第一次webshot加载时,需要数秒钟,之后加载就很快了 * * 高级用户: *  1.如果想提速大约25%,并且你了解linux,可以运行以下命令: *  nohup Xvfb :100 -ac -nolisten tcp -screen 0, 1024x768x24 > /dev/null 2>&1 & *  并设置 WEBSHOT_XVFB_RUNNING 的值为true * * *///测试的功能,如果设置此值为true, 并在查询字符串中加上webshot=1,会让脚本返回浏览器的截图,而不是获取图像if(! defined('WEBSHOT_ENABLED') ){  define ('WEBSHOT_ENABLED', false);}//定义CutyCapt地址if(! defined('WEBSHOT_CUTYCAPT') ){  define ('WEBSHOT_CUTYCAPT', '/usr/local/bin/CutyCapt');}//Xvfb地址if(! defined('WEBSHOT_XVFB') ){  define ('WEBSHOT_XVFB', '/usr/bin/xvfb-run');}//截图屏幕宽度1024if(! defined('WEBSHOT_SCREEN_X') ){  define ('WEBSHOT_SCREEN_X', '1024');}//截图屏幕高度768if(! defined('WEBSHOT_SCREEN_Y') ){  define ('WEBSHOT_SCREEN_Y', '768');}//色深,作者说他只测试过24if(! defined('WEBSHOT_COLOR_DEPTH') ){  define ('WEBSHOT_COLOR_DEPTH', '24');}//截图格式if(! defined('WEBSHOT_IMAGE_FORMAT') ){  define ('WEBSHOT_IMAGE_FORMAT', 'png');}//截图超时时间,单位sif(! defined('WEBSHOT_TIMEOUT') ){  define ('WEBSHOT_TIMEOUT', '20');}//user_agent头if(! defined('WEBSHOT_USER_AGENT') ){  define ('WEBSHOT_USER_AGENT', "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18");}//是否启用JSif(! defined('WEBSHOT_JAVASCRIPT_ON') ){  define ('WEBSHOT_JAVASCRIPT_ON', true);}//是否启用javaif(! defined('WEBSHOT_JAVA_ON') ){  define ('WEBSHOT_JAVA_ON', false);}//开启flash和其他插件if(! defined('WEBSHOT_PLUGINS_ON') ){  define ('WEBSHOT_PLUGINS_ON', true);}//代理服务器if(! defined('WEBSHOT_PROXY') ){  define ('WEBSHOT_PROXY', '');}//如果运行了XVFB,此项设为trueif(! defined('WEBSHOT_XVFB_RUNNING') ){  define ('WEBSHOT_XVFB_RUNNING', false);}// 如果 ALLOW_EXTERNAL 的值为真 并且 ALLOW_ALL_EXTERNAL_SITES 的值为假,那么截图的图片只能从下面这些数组中的域和子域进行if(! isset($ALLOWED_SITES)){  $ALLOWED_SITES = array (    'flickr.com',    'staticflickr.com',    'picasa.com',    'img.youtube.com',    'upload.wikimedia.org',    'photobucket.com',    'imgur.com',    'imageshack.us',    'tinypic.com',  );}/*截图配置结束*/ // -------------------------------------------------------------// -------------------------- 配置结束 ------------------------// ------------------------------------------------------------- timthumb::start(); class timthumb {protected $src = "";  //需要获取的图片urlprotected $is404 = false;  //404错误码protected $docRoot = "";  //服务器文档根目录protected $lastURLError = false; //上一次请求外部url的错误信息protected $localImage = ""; //如果请求的url是本地图片,则为本地图片的地址protected $localImageMTime = 0;  //本地图片的修改时间protected $url = false;  //用parse_url解析src后的数组        protected $myHost = "";  //本机域名protected $isURL = false;  //是否为外部图片地址protected $cachefile = ''; //缓存文件地址protected $errors = array();  //错误信息列表protected $toDeletes = array(); //析构函数中需要删除的资源列表protected $cacheDirectory = ''; //缓存地址protected $startTime = 0;  //开始时间protected $lastBenchTime = 0; //上一次debug完成的时间protected $cropTop = false;  //是否启用裁剪protected $salt = "";  //文件修改时间和inode连接的字符串的盐值protected $fileCacheVersion = 1; //文件缓存版本,当这个类升级或者被更改时,这个值应该改变,从而重新生成缓存protected $filePrependSecurityBlock = "<?php die('Execution denied!'); //"; //缓存文件安全头,防止直接访问protected static $curlDataWritten = 0;  //将curl获取到的数据写入缓存文件的长度protected static $curlFH = false;  //curl请求成功后要将获取到的数据写到此文件内/*外部调用接口*/public static function start(){  //实例化模型  $tim = new timthumb();//检查实例化模型时是否有错误$tim->handleErrors();//此函数为空,用做自定义的数据验证$tim->securityChecks();//尝试读取浏览器缓存if($tim->tryBrowserCache()){  //成功的话就输出缓存exit(0);}//检测错误$tim->handleErrors();//如果启用了文件缓存,并且读取服务端缓存if(FILE_CACHE_ENABLED && $tim->tryServerCache()){  //成功的话输出缓存exit(0);}//检测读取服务端缓存时的错误$tim->handleErrors();//生成和处理图片主函数$tim->run();//检测图片生成和处理时的错误$tim->handleErrors();//程序执行完毕运行析构方法并退出exit(0);}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
/*构造方法,用来获取和设置一些基本属性*/public function __construct(){  //将允许的域设为全局变量  global $ALLOWED_SITES;//记录开始时间$this->startTime = microtime(true);//设置时区date_default_timezone_set('UTC');//写日志,记录请求IP和请求URL$this->debug(1, "Starting new request from " . $this->getIP() . " to " . $_SERVER['REQUEST_URI']);//获取服务器文档根目录$this->calcDocRoot();//获取文件的修改时间和inode,inode只在linux系统下有效$this->salt = @filemtime(__FILE__) . '-' . @fileinode(__FILE__);//记录salt信息,级别3$this->debug(3, "Salt is: " . $this->salt);//如果定义了缓存文件地址if(FILE_CACHE_DIRECTORY){  //如果这个地址不存在,或为非目录  if(! is_dir(FILE_CACHE_DIRECTORY)){    //建立这个目录  @mkdir(FILE_CACHE_DIRECTORY);//如果建立失败if(! is_dir(FILE_CACHE_DIRECTORY)){  //记录错误信息,停止执行$this->error("Could not create the file cache directory.");return false;}}//将缓存地址写入成员属性$this->cacheDirectory = FILE_CACHE_DIRECTORY;//在缓存目录下创建一个index.html文件,防止列目录if (!touch($this->cacheDirectory . '/index.html')) {  //如果出错,记录错误信息$this->error("Could not create the index.html file - to fix this create an empty file named index.html file in the cache directory.");}//如果没定义缓存文件地址,则用系统的临时文件目录做为缓存文件目录} else {$this->cacheDirectory = sys_get_temp_dir();}//进行缓存检查,清除过期缓存$this->cleanCache();//记录本机域名$this->myHost = preg_replace('/^www\./i', '', $_SERVER['HTTP_HOST']);//获取图片地址,此地址应该由$_GET中的src参数传递$this->src = $this->param('src');//此数组是解析src后的结果,包括scheme,host,port,user,pass,path,query,fragment其中一个或多个值$this->url = parse_url($this->src);//如果图片地址是本机的,则删除图片url中本机的域名部分$this->src = preg_replace('/https?:\/\/(?:www\.)?' . $this->myHost . '/i', '', $this->src);//如果图片地址的长度小于3,则是无效地址if(strlen($this->src) <= 3){  //添加错误信息$this->error("No image specified");return false;}//如果开启了防盗链,并且存在来源地址,也就是HTTP_REFERER头,并且来源地址不是本机,则进行防盗链处理if(BLOCK_EXTERNAL_LEECHERS && array_key_exists('HTTP_REFERER', $_SERVER) && (! preg_match('/^https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $_SERVER['HTTP_REFERER']))){//此base64编码的内容是一张显示 No Hotlinking的图片  $imgData = base64_decode("R0lGODlhUAAMAIAAAP8AAP///yH5BAAHAP8ALAAAAABQAAwAAAJpjI+py+0Po5y0OgAMjjv01YUZ\nOGplhWXfNa6JCLnWkXplrcBmW+spbwvaVr/cDyg7IoFC2KbYVC2NQ5MQ4ZNao9Ynzjl9ScNYpneb\nDULB3RP6JuPuaGfuuV4fumf8PuvqFyhYtjdoeFgAADs=");//显示内容为gif图片header('Content-Type: image/gif');//内容长度header('Content-Length: ' . sizeof($imgData));//无网页缓存header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');//兼容http1.0和httpsheader("Pragma: no-cache");//内容立即过期header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));//输出图片echo $imgData;return false;//退出脚本exit(0);}//如果此时的src属性包含http等字符,说明是外部链接if(preg_match('/^https?:\/\/[^\/]+/i', $this->src)){  //写日志,说明这个链接是外部的,级别2  $this->debug(2, "Is a request for an external URL: " . $this->src);//将isURL设为true,说明是外部url$this->isURL = true;//如果不包含的话,说明是内部链接} else {$this->debug(2, "Is a request for an internal file: " . $this->src);}//如果图片的src是外部网站,并且配置文件不允许从外部获取图片,则退出if($this->isURL && (! ALLOW_EXTERNAL)){$this->error("You are not allowed to fetch images from an external website.");return false;}//如果允许从外部网站获取图片if($this->isURL){  //并且配置文件允许从所有的外部网站获取图片  if(ALLOW_ALL_EXTERNAL_SITES){//写日志,允许从外部网站取回图片,级别2  $this->debug(2, "Fetching from all external sites is enabled.");//如果配置文件不允许从所有的外部网站获取图片} else {  //写日志,只能从指定的外部网站获取图片,级别2  $this->debug(2, "Fetching only from selected external sites is enabled.");//此为验证位,默认为false$allowed = false;//遍历配置文件中允许站点的列表foreach($ALLOWED_SITES as $site){  //这里对图片的url跟允许访问站点的列表进行验证,前面的条件对应的是有主机名的,后面的内容对应的是没有主机名的,写的很精巧  if ((strtolower(substr($this->url['host'],-strlen($site)-1)) === strtolower(".$site")) || (strtolower($this->url['host'])===strtolower($site))) {//通过验证则写一条日志,验证成功,级别3  $this->debug(3, "URL hostname {$this->url['host']} matches $site so allowing.");//验证位为true$allowed = true;}}//如果没通过验证, 写错误信息并退出if(! $allowed){return $this->error("You may not fetch images from that site. To enable this site in timthumb, you can either add it to \$ALLOWED_SITES and set ALLOW_EXTERNAL=true. Or you can set ALLOW_ALL_EXTERNAL_SITES=true, depending on your security needs.");}}}//缓存文件的前缀,如果是内部图片,用_int_,外部图片用_ext_$cachePrefix = ($this->isURL ? '_ext_' : '_int_');//如果是外部图片地址if($this->isURL){  //得到GET字符串的数组  $arr = explode('&', $_SERVER ['QUERY_STRING']);//按字母顺序对数组元素排序asort($arr);//生成缓存文件地址  缓存目录 + / + 缓存前缀 + $cachePrefix + 唯一散列值  + 缓存后缀$this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . implode('', $arr) . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;//如果是本地图片} else {  //获取本地图片地址  $this->localImage = $this->getLocalImagePath($this->src);//如果获取不到地址if(! $this->localImage){  //写日志,没有找到此文件,级别1  $this->debug(1, "Could not find the local image: {$this->localImage}");//记录错误信息$this->error("Could not find the internal image you specified.");//设置404错误信息$this->set404();//终止执行程序return false;}//写日志,记录本地图片信息,级别1$this->debug(1, "Local image path is {$this->localImage}");//获取文件修改时间$this->localImageMTime = @filemtime($this->localImage);//生成缓存文件地址,  缓存目录 + / + 缓存前缀 + $cachePrefix + 唯一散列值 + 缓存后缀$this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . $this->localImageMTime . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;}//记录缓存文件地址$this->debug(2, "Cache file is: " . $this->cachefile);//构造函数完成return true;}/*析构方法,删除toDeletes数组中的每一个文件*/public function __destruct(){foreach($this->toDeletes as $del){$this->debug(2, "Deleting temp file $del");@unlink($del);}}/*主函数,通过不同参数调用不同的图片处理函数*/public function run(){  //如果是外部的图片链接  if($this->isURL){//但是配置文件不允许从外部获取链接  if(! ALLOW_EXTERNAL){//写日志,说明配置文件禁止访问外部图片,级别1  $this->debug(1, "Got a request for an external image but ALLOW_EXTERNAL is disabled so returning error msg.");//写错误记录$this->error("You are not allowed to fetch images from an external website.");//退出执行return false;}//配置文件允许从外部获取链接,则写日志,接着运行,级别3$this->debug(3, "Got request for external image. Starting serveExternalImage.");//如果get了webshot参数并且为真,则进行截图操作if($this->param('webshot')){  //如果配置文件允许截图  if(WEBSHOT_ENABLED){    //写日志,说明要进行截图操作,级别3  $this->debug(3, "webshot param is set, so we're going to take a webshot.");//截图操作$this->serveWebshot();//如果配置文件不允许截图} else {  //记录错误信息并退出$this->error("You added the webshot parameter but webshots are disabled on this server. You need to set WEBSHOT_ENABLED == true to enable webshots.");}//如果不存在sebshot参数或为假} else {  //写日志,记录不进行截图操作,级别3  $this->debug(3, "webshot is NOT set so we're going to try to fetch a regular image.");//从外部URL获得图片并处理$this->serveExternalImage(); }//否则的话就是内部图片} else {  //写日志,记录是内部图片,级别3  $this->debug(3, "Got request for internal image. Starting serveInternalImage()");//获得内部图片并处理$this->serveInternalImage();}//程序执行完毕return true;}/*此函数用来处理错误*/protected function handleErrors(){  //如果错误列表中有内容  if($this->haveErrors()){//首先检测404错误,如果设置了404图片地址并且的确有404错误  if(NOT_FOUND_IMAGE && $this->is404()){//那么输出错误图片,并退出脚本if($this->serveImg(NOT_FOUND_IMAGE)){  exit(0);//输出失败的话记录错误信息} else {$this->error("Additionally, the 404 image that is configured could not be found or there was an error serving it.");}}//如果没有404错误,并且定义了错误图片,那么输出此图片if(ERROR_IMAGE){  //输出其他错误提示图片,并退出脚本if($this->serveImg(ERROR_IMAGE)){  exit(0);//输出失败的话记录错误信息} else {$this->error("Additionally, the error image that is configured could not be found or there was an error serving it.");}}//如果上面两个常量都没定义,则根据模板输出详细错误信息$this->serveErrors(); exit(0); }//没有错误的话返回假return false;}/*此函数用来读取浏览器缓存文件,前提是浏览器缓存的文件有效,具体的实现请看函数内部*/protected function tryBrowserCache(){  //如果配置文件关闭了所有浏览器缓存,则写日志,并返回假  if(BROWSER_CACHE_DISABLE){   $this->debug(3, "Browser caching is disabled"); return false; }//如果浏览器记录了页面上次修改的时间if(!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ){  //写日志,记录,级别3  $this->debug(3, "Got a conditional get");//缓存文件最后修改时间$mtime = false;//如果缓存地址无效if(! is_file($this->cachefile)){//说明没有缓存,返回假return false;}//如果存在本地图片修改时间,也就是说所请求的图片是本机的if($this->localImageMTime){  //缓存文件修改时间设置为本地图片修改时间  $mtime = $this->localImageMTime;//写日志,记录实际文件修改时间,级别3$this->debug(3, "Local real file's modification time is $mtime");//如果请求的图片不是本地的} else if(is_file($this->cachefile)){  //获取缓存文件修改时间  $mtime = @filemtime($this->cachefile);//写日志,记录缓存文件修改时间,级别3$this->debug(3, "Cached file's modification time is $mtime");}//如果没有获取到缓存文件最后修改时间,说明没有缓存,退出if(! $mtime){ return false; }//将浏览器中存储的上次修改时间转为时间戳$iftime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);//写日志,记录UNIX时间戳,级别3$this->debug(3, "The conditional get's if-modified-since unixtime is $iftime");//如果这个时间小于1秒,说明值无效,退出if($iftime < 1){  //写日志,记录此值无效$this->debug(3, "Got an invalid conditional get modified since time. Returning false.");return false;}//如果浏览器存储的时间小于实际缓存文件的最后修改时间,也就是说距上次访问后,文件被更改了,要重新请求页面if($iftime < $mtime){  //写日志,记录文件已被更改,级别3$this->debug(3, "File has been modified since last fetch.");return false;//否则就不用重新请求页面,直接读取缓存} else {  //写日志,记录缓存有效,直接读取缓存,级别3  $this->debug(3, "File has not been modified since last get, so serving a 304.");//设置HTTP头响应码为304header ($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');//记录此次操作,级别1$this->debug(1, "Returning 304 not modified");//读取成功返回真return true;}}//没有读取到缓存,返回假return false;}/*此函数用来运行缓存文件的GC和读取服务器上的缓存文件*/protected function tryServerCache(){  //写日志,记录将读取服务端缓存,级别3  $this->debug(3, "Trying server cache");  //如果缓存文件存在if(file_exists($this->cachefile)){  //写日志,记录缓存文件存在  $this->debug(3, "Cachefile {$this->cachefile} exists");//如果请求的是外部图片地址if($this->isURL){  //写日志,记录这是一次外部请求,级别3  $this->debug(3, "This is an external request, so checking if the cachefile is empty which means the request failed previously.");//如果缓存文件的大小小于1,也就是说是一个无效的缓存文件if(filesize($this->cachefile) < 1){  //写日志,记录这是一个空的缓存文件,级别3$this->debug(3, "Found an empty cachefile indicating a failed earlier request. Checking how old it is.");//如果已到了配置文件中清理无效缓存的时间if(time() - @filemtime($this->cachefile) > WAIT_BETWEEN_FETCH_ERRORS){  //写日志,记录这次删除操作,级别3  $this->debug(3, "File is older than " . WAIT_BETWEEN_FETCH_ERRORS . " seconds. Deleting and returning false so app can try and load file.");//删除此缓存文件@unlink($this->cachefile);//返回假,说明没有读取到服务端缓存return false;//否则,空的缓存文件说明上次请求失败,所以要写错误记录} else {  //写日志,记录空的缓存文件依然有效,级别3  $this->debug(3, "Empty cachefile is still fresh so returning message saying we had an error fetching this image from remote host.");//设置404错误$this->set404();//设置错误信息$this->error("An error occured fetching image.");//返回假代表没有得到缓存return false; }}//否则就是正确的缓存文件} else {  //写日志,记录将要直接读取缓存文件,级别3$this->debug(3, "Trying to serve cachefile {$this->cachefile}");}//如果输出图像缓存成功if($this->serveCacheFile()){  //写日志,记录缓存文件信息,级别3$this->debug(3, "Succesfully served cachefile {$this->cachefile}");return true;//如果不成功} else {  //写日志,记录错误信息,级别3$this->debug(3, "Failed to serve cachefile {$this->cachefile} - Deleting it from cache.");//删除此无效缓存,以便下次请求能重新创建@unlink($this->cachefile);//同样返回真,因为在serverCacheFile已经记录了错误信息return true;}}}/*此函数用来记录错误信息*/protected function error($err){  //写记录,记录错误信息,级别3  $this->debug(3, "Adding error message: $err");//记录到错误信息数组$this->errors[] = $err;return false;}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
/*测函数用来检测存储错误信息的数组中是否有内容,也就是说在上一个操作中,是否有错误*/protected function haveErrors(){if(sizeof($this->errors) > 0){return true;}return false;}/*此函数输出已存储的错误信息*/protected function serveErrors(){  //设置http头  header ($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');  //循环输出错误列表信息$html = '<ul>';foreach($this->errors as $err){$html .= '<li>' . htmlentities($err) . '</li>';}$html .= '</ul>';//输出其他错误信息echo '<h1>A TimThumb error has occured</h1>The following error(s) occured:<br />' . $html . '<br />';echo '<br />Query String : ' . htmlentities ($_SERVER['QUERY_STRING']);echo '<br />TimThumb version : ' . VERSION;}/*此函数用来读取本地图片*/protected function serveInternalImage(){  //写日志,记录本地图片地址  $this->debug(3, "Local image path is $this->localImage");  //如果地址无效if(! $this->localImage){  //记录此错误,并退出执行$this->sanityFail("localImage not set after verifying it earlier in the code.");return false;}//获取本地图片大小$fileSize = filesize($this->localImage);//如果本地图片的尺寸超过配置文件的相关设置if($fileSize > MAX_FILE_SIZE){  //记录错误原因,并退出$this->error("The file you specified is greater than the maximum allowed file size.");return false;}//如果获取到的图片尺寸无效if($fileSize <= 0){  //记录错误并退出$this->error("The file you specified is <= 0 bytes.");return false;}//如果通过了以上验证,则写日志,记录将用processImageAndWriteToCache函数处理本地图片$this->debug(3, "Calling processImageAndWriteToCache() for local image.");//处理成功则从缓存返回图片if($this->processImageAndWriteToCache($this->localImage)){$this->serveCacheFile();return true;//失败则返回假} else { return false;}}/*此函数用来清理缓存*/protected function cleanCache(){//如果定义的缓存时间小于0,则退出if (FILE_CACHE_TIME_BETWEEN_CLEANS < 0) {return;}//写日志,记录清除缓存操作,级别3$this->debug(3, "cleanCache() called");//此文件为记录上次进行清除缓存操作的时间戳文件$lastCleanFile = $this->cacheDirectory . '/timthumb_cacheLastCleanTime.touch'; //如果上面定义的文件不存在,说明这是第一次进行清除缓存操作,创建此文件并返回空即可if(! is_file($lastCleanFile)){  //写日志,记录创建文件,级别1  $this->debug(1, "File tracking last clean doesn't exist. Creating $lastCleanFile");//创建此文件if (!touch($lastCleanFile)) {  //失败的话报错并退出$this->error("Could not create cache clean timestamp file.");}return;}//如果已超过缓存时间if(@filemtime($lastCleanFile) < (time() - FILE_CACHE_TIME_BETWEEN_CLEANS) ){  //写日志,记录下面进行的清除缓存操作$this->debug(1, "Cache was last cleaned more than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago. Cleaning now.");//创建新的清除缓存时间戳文件if (!touch($lastCleanFile)) {  //失败的话记录错误信息$this->error("Could not create cache clean timestamp file.");}//此数组存的是所有缓存文件,根据前面定义的缓存文件目录和缓存文件后缀得到的$files = glob($this->cacheDirectory . '/*' . FILE_CACHE_SUFFIX);//如果有缓存文件if ($files) {  //计算当前时间和缓存最大生存时间的差值,用于下面判断缓存文件是否删除  $timeAgo = time() - FILE_CACHE_MAX_FILE_AGE;//遍历缓存文件数组foreach($files as $file){  //如果文件创建时间小于上面计算的值,也就是说此缓存文件的死期到了,就删除它  if(@filemtime($file) < $timeAgo){    //记录删除缓存文件,级别3$this->debug(3, "Deleting cache file $file older than max age: " . FILE_CACHE_MAX_FILE_AGE . " seconds");@unlink($file);}}}return true;//如果没超过缓存时间,则不用清除} else {  //写日志,记录不用清除缓存$this->debug(3, "Cache was cleaned less than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago so no cleaning needed.");}return false;}/*核心函数,处理图片并写入缓存*/protected function processImageAndWriteToCache($localImage){  //获取图片信息  $sData = getimagesize($localImage);//图像类型标记$origType = $sData[2];//mime类型$mimeType = $sData['mime'];//写日志,记录传入图像的mime类型$this->debug(3, "Mime type of image is $mimeType");//进行图像mime类型验证,只允许gif , jpg 和 pngif(! preg_match('/^image\/(?:gif|jpg|jpeg|png)$/i', $mimeType)){  //如果不是这四种类型,记录错误信息,并退出脚本return $this->error("The image being resized is not a valid gif, jpg or png.");}//图片处理需要GD库支持,这里检测是否安装了GD库if (!function_exists ('imagecreatetruecolor')) {    //没有安装的话推出脚本    return $this->error('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');}//如果安装了GD库,并且支持图像过滤器函数imagefilter,且支持IMG_FILTER_NEGATE常量if (function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {  //定义一个过滤器效果数组,后面的数字代表需要额外传入的参数  $imageFilters = array (    //负片  1 => array (IMG_FILTER_NEGATE, 0),//黑白的2 => array (IMG_FILTER_GRAYSCALE, 0),//亮度级别3 => array (IMG_FILTER_BRIGHTNESS, 1),//对比度级别4 => array (IMG_FILTER_CONTRAST, 1),//图像转换为制定颜色5 => array (IMG_FILTER_COLORIZE, 4),//突出边缘6 => array (IMG_FILTER_EDGEDETECT, 0),//浮雕7 => array (IMG_FILTER_EMBOSS, 0),//用高斯算法模糊图像8 => array (IMG_FILTER_GAUSSIAN_BLUR, 0),//模糊图像9 => array (IMG_FILTER_SELECTIVE_BLUR, 0),//平均移除法来达到轮廓效果10 => array (IMG_FILTER_MEAN_REMOVAL, 0),//平滑处理11 => array (IMG_FILTER_SMOOTH, 0),);} //生成图片宽度,由get中w参数指定,默认为0$new_width =  (int) abs ($this->param('w', 0));//生成图片高度,由get中h参数指定,默认为0$new_height = (int) abs ($this->param('h', 0));//生成图片缩放模式,由get中zc参数指定,默认为配置文件中DEFAULT_ZC的值$zoom_crop = (int) $this->param('zc', DEFAULT_ZC);//生成图片的质量,由get中q参数指定,默认为配置文件中DEFAULT_Q的值$quality = (int) abs ($this->param('q', DEFAULT_Q));//裁剪的位置$align = $this->cropTop ? 't' : $this->param('a', 'c');//需要进行的图片处理操作,多个过滤器用"|"分割,可选参数请参看$imageFilters处的注释,由于不同的过滤器需要的参数不同,如一个过滤器需要多个参数,多个参数用,分隔。例:1,2|3,1,1  代表对图像分别应用1和3过滤效果,1和3所对应的过滤效果是由$imageFilters数组确定的,其中1号过滤器还需要一个额外的参数,这里传了1,3号过滤器还需要2个额外的参数,这里传了1和1.$filters = $this->param('f', DEFAULT_F);//是否对图片进行锐化,由get中s参数指定,默认为配置文件中DEFAULT_S的值$sharpen = (bool) $this->param('s', DEFAULT_S);//生成图片的默认背景画布颜色,由get中cc参数指定,默认为配置文件中DEFAULT_CC的值$canvas_color = $this->param('cc', DEFAULT_CC);//生成png图片的背景是否透明$canvas_trans = (bool) $this->param('ct', '1'); // 如果高度和宽度都没有指定,设置他们为100*100if ($new_width == 0 && $new_height == 0) {    $new_width = 100;    $new_height = 100;} // 限制最大高度和最大宽度$new_width = min ($new_width, MAX_WIDTH);$new_height = min ($new_height, MAX_HEIGHT); // 检测并设置php运行最大占用内存$this->setMemoryLimit(); // 打开图像资源$image = $this->openImage ($mimeType, $localImage);//如果打开失败,记录信息并退出脚本if ($image === false) {return $this->error('Unable to open image.');} // 获得原始图片,也就是上面打开图片的宽和高$width = imagesx ($image);$height = imagesy ($image);$origin_x = 0;$origin_y = 0; // 如果新生成图片的宽或高没有指定,则用此等比算法算出高或宽的值if ($new_width && !$new_height) {$new_height = floor ($height * ($new_width / $width));} else if ($new_height && !$new_width) {$new_width = floor ($width * ($new_height / $height));} // 如果缩放模式选择的是3,也就是说get中zc=3或者配置文件中DEFAULT_ZC=3,则进行等比缩放,不裁剪if ($zoom_crop == 3) { $final_height = $height * ($new_width / $width);//根据等比算法设置等比计算后的宽或高if ($final_height > $new_height) {$new_width = $width * ($new_height / $height);} else {$new_height = $final_height;} } // 利用处理完毕的长和宽创建新画布,$canvas = imagecreatetruecolor ($new_width, $new_height);//关闭混色模式,也就是把PNG的alpha值保存,从而使背景透明imagealphablending ($canvas, false);//进行默认画布颜色的检测并转换,如果给出的是3个字符长度表示的颜色值if (strlen($canvas_color) == 3) { //if is 3-char notation, edit string into 6-char notation  //转换为6个字符表示的颜色值  $canvas_color =  str_repeat(substr($canvas_color, 0, 1), 2) . str_repeat(substr($canvas_color, 1, 1), 2) . str_repeat(substr($canvas_color, 2, 1), 2); //如果不是3个长度也不是6个长度的字符串,则为非法字符串,设置为默认值} else if (strlen($canvas_color) != 6) {$canvas_color = DEFAULT_CC; }//将上面得到的R 、G 、B 三种颜色值转换为10进制表示$canvas_color_R = hexdec (substr ($canvas_color, 0, 2));$canvas_color_G = hexdec (substr ($canvas_color, 2, 2));$canvas_color_B = hexdec (substr ($canvas_color, 4, 2)); // 如果传入图片的格式是png,并且配置文件设置png背景颜色为透明,并且在get传入了ct的值为真,那么就设置背景颜色为透明if(preg_match('/^image\/png$/i', $mimeType) && !PNG_IS_TRANSPARENT && $canvas_trans){   $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127);//反之设置为不透明}else{$color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 0);} // 使用分配的颜色填充背景imagefill ($canvas, 0, 0, $color);  // 如果缩放模式选择的是2,那么画布的体积是按传入的值创建的,并计算出边框的宽度if ($zoom_crop == 2) {  //等比缩放的高度$final_height = $height * ($new_width / $width);//如果计算出的等比高度,大于传入的高度if ($final_height > $new_height) {//origin_x等于传入的新高度的二分之一  $origin_x = $new_width / 2;  //设置新宽度为等比计算出的值$new_width = $width * ($new_height / $height);//计算出两次origin_x的差值$origin_x = round ($origin_x - ($new_width / 2));//否则,计算出两次origin_y的差值} else {$origin_y = $new_height / 2;$new_height = $final_height;$origin_y = round ($origin_y - ($new_height / 2)); } } // 保存图像时保存完整的alpha信息imagesavealpha ($canvas, true); //如果缩放模式选择的是1或2或3if ($zoom_crop > 0) {   $src_x = $src_y = 0;//图片原宽度$src_w = $width;//图片原高度$src_h = $height; //图片纵横比$cmp_x = $width / $new_width;$cmp_y = $height / $new_height; //裁剪算法if ($cmp_x > $cmp_y) {$src_w = round ($width / $cmp_x * $cmp_y);$src_x = round (($width - ($width / $cmp_x * $cmp_y)) / 2); } else if ($cmp_y > $cmp_x) { $src_h = round ($height / $cmp_y * $cmp_x);$src_y = round (($height - ($height / $cmp_y * $cmp_x)) / 2); } // 根据传入参数算出裁剪的位置if ($align) {if (strpos ($align, 't') !== false) {$src_y = 0;}if (strpos ($align, 'b') !== false) {$src_y = $height - $src_h;}if (strpos ($align, 'l') !== false) {$src_x = 0;}if (strpos ($align, 'r') !== false) {$src_x = $width - $src_w;}} //将图像根据算法进行裁剪,并拷贝到背景图片上imagecopyresampled ($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h); } else { //裁剪模式选择的是0,则不进行裁剪,并生成图像imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); }//如果定义了图片处理操作,并且支持图片处理函数if ($filters != '' && function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {// 分割每个过滤处理$filterList = explode ('|', $filters);foreach ($filterList as $fl) {  //分割一个过滤操作中的参数  $filterSettings = explode (',', $fl);//如果所选的过滤操作存在if (isset ($imageFilters[$filterSettings[0]])) {//将所有参数转为int类型for ($i = 0; $i < 4; $i ++) {if (!isset ($filterSettings[$i])) {$filterSettings[$i] = null;} else {$filterSettings[$i] = (int) $filterSettings[$i];}}//根据$imageFilters中定义的每个过滤效果需要的参数的不同,对图像应用过滤器效果switch ($imageFilters[$filterSettings[0]][1]) { case 1: imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);break; case 2: imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);break; case 3: imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);break; case 4: imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3], $filterSettings[4]);break; default: imagefilter ($canvas, $imageFilters[$filterSettings[0]][0]);break; }}}} // 如果设置了锐化值,并且系统支持锐化函数,则进行锐化操作if ($sharpen && function_exists ('imageconvolution')) { $sharpenMatrix = array (array (-1,-1,-1),array (-1,16,-1),array (-1,-1,-1),); $divisor = 8;$offset = 0; imageconvolution ($canvas, $sharpenMatrix, $divisor, $offset); }//如果图片是PNG或者GIF,则用imagetruecolortopalette来减小他们的体积if ( (IMAGETYPE_PNG == $origType || IMAGETYPE_GIF == $origType) && function_exists('imageistruecolor') && !imageistruecolor( $image ) && imagecolortransparent( $image ) > 0 ){imagetruecolortopalette( $canvas, false, imagecolorstotal( $image ) );}//根据生成的不同图片类型,生成图片缓存,$imgType的值用于生成安全头$imgType = "";$tempfile = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');if(preg_match('/^image\/(?:jpg|jpeg)$/i', $mimeType)){ $imgType = 'jpg';imagejpeg($canvas, $tempfile, $quality); } else if(preg_match('/^image\/png$/i', $mimeType)){ $imgType = 'png';imagepng($canvas, $tempfile, floor($quality * 0.09));} else if(preg_match('/^image\/gif$/i', $mimeType)){$imgType = 'gif';imagegif($canvas, $tempfile);} else {  //如果不是以上三种类型,记录这次错误并退出return $this->sanityFail("Could not match mime type after verifying it previously.");}//优先使用optipng工具进行png图片的压缩,前提是你装了这个工具if($imgType == 'png' && OPTIPNG_ENABLED && OPTIPNG_PATH && @is_file(OPTIPNG_PATH)){  //记录optipng的地址  $exec = OPTIPNG_PATH;//写日志,记录optipng将运行,级别3$this->debug(3, "optipng'ing $tempfile");//获取图片大小$presize = filesize($tempfile);//进行图片压缩操作$out = `$exec -o1 $tempfile`;       //清除文件状态缓存clearstatcache();//获取压缩后的文件大小$aftersize = filesize($tempfile);//算出压缩了多大$sizeDrop = $presize - $aftersize;//根据算出的不同的值,写日志,级别1if($sizeDrop > 0){$this->debug(1, "optipng reduced size by $sizeDrop");} else if($sizeDrop < 0){$this->debug(1, "optipng increased size! Difference was: $sizeDrop");} else {$this->debug(1, "optipng did not change image size.");}//optipng不存在,就尝试使用pngcrush} else if($imgType == 'png' && PNGCRUSH_ENABLED && PNGCRUSH_PATH && @is_file(PNGCRUSH_PATH)){  $exec = PNGCRUSH_PATH;//和optipng不同的是,pngcrush会将处理完的文件新生成一个文件,所以这里新建个文件$tempfile2 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');//写日志,记录文件名$this->debug(3, "pngcrush'ing $tempfile to $tempfile2");//运行pngcrush$out = `$exec $tempfile $tempfile2`;$todel = "";//如果生成文件成功if(is_file($tempfile2)){  //算出压缩后的文件大小的差值  $sizeDrop = filesize($tempfile) - filesize($tempfile2);//如果是一次有效的压缩,则将压缩后的文件作为缓存文件if($sizeDrop > 0){$this->debug(1, "pngcrush was succesful and gave a $sizeDrop byte size reduction");$todel = $tempfile;$tempfile = $tempfile2;//否则的话则这个文件没有存在的必要} else {$this->debug(1, "pngcrush did not reduce file size. Difference was $sizeDrop bytes.");$todel = $tempfile2;}//没有运行成功也需要删除这个文件} else {$this->debug(3, "pngcrush failed with output: $out");$todel = $tempfile2;}//删除无效文件或压缩前比较大的文件@unlink($todel);}//在缓存图片上写入安全头$this->debug(3, "Rewriting image with security header.");//创建一个新的缓存文件$tempfile4 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');//$context = stream_context_create ();//读取生成的图片缓存内容$fp = fopen($tempfile,'r',0,$context);//向新缓存文件写入安全头,安全头的长度应该总是$this->filePrependSecurityBlock的长度 + 6file_put_contents($tempfile4, $this->filePrependSecurityBlock . $imgType . ' ?' . '>');//将读取出来的缓存图片内容写入新缓存文件file_put_contents($tempfile4, $fp, FILE_APPEND);//关闭文件资源fclose($fp);//删除之前不安全的图片缓存文件@unlink($tempfile);//写日志,给缓存文件加锁~~$this->debug(3, "Locking and replacing cache file.");//创建锁文件文件名$lockFile = $this->cachefile . '.lock';//创建或打开锁文件$fh = fopen($lockFile, 'w');//创建失败直接退出if(! $fh){return $this->error("Could not open the lockfile for writing an image.");}//如果给锁文件加入写入锁成功if(flock($fh, LOCK_EX)){  //删除原缓存文件  @unlink($this->cachefile); //重命名覆盖,将安全的缓存文件作为缓存文件rename($tempfile4, $this->cachefile);//释放写入锁flock($fh, LOCK_UN);//释放资源fclose($fh);//删除锁文件@unlink($lockFile);//否则} else {  //关闭资源  fclose($fh);//删除锁文件@unlink($lockFile);//删除安全的缓存文件@unlink($tempfile4);//记录错误并退出return $this->error("Could not get a lock for writing.");}//写日志,记录操作完成$this->debug(3, "Done image replace with security header. Cleaning up and running cleanCache()");//释放图片资源imagedestroy($canvas);imagedestroy($image);//生成缓存成功返回真return true;}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
/*此函数用来获取服务器文档根目录*/protected function calcDocRoot(){  //直接获取文档根目录  $docRoot = @$_SERVER['DOCUMENT_ROOT'];//如果定义了LOCAL_FILE_BASE_DIRECTORY,则使用此值if (defined('LOCAL_FILE_BASE_DIRECTORY')) {$docRoot = LOCAL_FILE_BASE_DIRECTORY;   }//如果没有获取到文档根目录,也就是DOCUMENT_ROOT的值if(!isset($docRoot)){  //写一条记录,说明DOCUMENT_ROOT没找到,注意level是3  $this->debug(3, "DOCUMENT_ROOT is not set. This is probably windows. Starting search 1.");//用SCRIPT_FILENAME和PHP_SELF来得到文档根目录if(isset($_SERVER['SCRIPT_FILENAME'])){  $docRoot = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF'])));//写一条记录,说明DOCUMENT_ROOT的值是通过SCRIPT_FILENAME和PHP_SELF来得的,级别3$this->debug(3, "Generated docRoot using SCRIPT_FILENAME and PHP_SELF as: $docRoot");} }//如果还是没有获取到文档根目录if(!isset($docRoot)){  //先写一条记录,说明还是没得到DOCUMENT_ROOT,级别3  $this->debug(3, "DOCUMENT_ROOT still is not set. Starting search 2.");//通过PATH_TRANSLATED和PHP_SELF来得到文档根目录,关于PATH_TRANSLATED的说明可以看这里:http://blogs.msdn.com/b/david.wang/archive/2005/08/04/what-is-path-translated.aspxif(isset($_SERVER['PATH_TRANSLATED'])){  $docRoot = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0-strlen($_SERVER['PHP_SELF'])));//写记录,说明说明DOCUMENT_ROOT的值是通过PATH_TRANSLATED和PHP_SELF来得的,级别3$this->debug(3, "Generated docRoot using PATH_TRANSLATED and PHP_SELF as: $docRoot");} }//如果文档根目录不是服务器根目录,则去掉最后一个 '/'if($docRoot && $_SERVER['DOCUMENT_ROOT'] != '/'){ $docRoot = preg_replace('/\/$/', '', $docRoot); }//写记录,说明文档根目录的值,级别3$this->debug(3, "Doc root is: " . $docRoot);//赋值给成员属性$this->docRoot = $docRoot; } /*此函数用来获取本地图片地址,参数src是相对与文档根目录的地址*/protected function getLocalImagePath($src){  //去掉开头的 /   $src = ltrim($src, '/'); //如果前面没有获取到文档根目录,出于安全考虑,那么这里只能对timthumbs.php所在的目录下的图片进行操作 if(! $this->docRoot){   //写日志,级别3,说明下面进行图片地址的检查$this->debug(3, "We have no document root set, so as a last resort, lets check if the image is in the current dir and serve that.");//获取去掉所有路径信息的文件名$file = preg_replace('/^.*?([^\/\\\\]+)$/', '$1', $src); //如果图片文件和timthumb.php在同一目录下if(is_file($file)){  //返回此图片的路径return $this->realpath($file);}//如果图片文件和timthumb.php不在同一目录下,写错误信息,出于安全考虑,不会允许一个没有文档根目录并且在timthumbs.php所在的目录以外的文件return $this->error("Could not find your website document root and the file specified doesn't exist in timthumbs directory. We don't support serving files outside timthumb's directory without a document root for security reasons.");}  //尝试找这张图片,如果图片地址存在 if(file_exists ($this->docRoot . '/' . $src)) {   //写日志,记录文件地址,级别3   $this->debug(3, "Found file as " . $this->docRoot . '/' . $src);//返回图片路径$real = $this->realpath($this->docRoot . '/' . $src);//验证图片路径是否在本机if(stripos($real, $this->docRoot) === 0){  //是的话返回图片地址return $real;} else {  //否则写日志,没找到指定文件,级别1$this->debug(1, "Security block: The file specified occurs outside the document root.");}} //接着找。。。 $absolute = $this->realpath('/' . $src); //如果决定地址存在 if($absolute && file_exists($absolute)){  //写日志,记录图片绝对地址,级别3    $this->debug(3, "Found absolute path: $absolute");//如果文档根目录没有定义,记录这个错误信息if(! $this->docRoot){ $this->sanityFail("docRoot not set when checking absolute path."); }//验证图片路径是否在本机if(stripos($absolute, $this->docRoot) === 0){//在的话返回图片地址    return $absolute;} else {  //否则写日志,没找到指定的文件,级别1$this->debug(1, "Security block: The file specified occurs outside the document root.");}} //如果还没找到指定文件,则逐级向上查找$base = $this->docRoot; // 获取查询子目录列表if (strstr($_SERVER['SCRIPT_FILENAME'],':')) {$sub_directories = explode('\\', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));} else {$sub_directories = explode('/', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));}//遍历子目录数组foreach ($sub_directories as $sub){  //重新组合请求地址  $base .= $sub . '/';//写日志,记录搜索记录,级别3$this->debug(3, "Trying file as: " . $base . $src);//如果找到了这个文件if(file_exists($base . $src)){  //写日志,记录文件地址,级别3  $this->debug(3, "Found file as: " . $base . $src);//得到实际地址$real = $this->realpath($base . $src);//如果实际地址的确在本机中,那么返回这个地址if(stripos($real, $this->realpath($this->docRoot)) === 0){return $real;} else {  //找不到就写日志,没找到,级别1$this->debug(1, "Security block: The file specified occurs outside the document root.");}}}//还找不到的话,就返回false;return false;}/*此函数用来获得传入文件参数的真实路径*/protected function realpath($path){//去除路径中带有..的相对路径$remove_relatives = '/\w+\/\.\.\//';while(preg_match($remove_relatives,$path)){    $path = preg_replace($remove_relatives, '', $path);}//如果去除后路径中仍有..的相对路径,则用realpath函数返回路径,否则直接返回即可return preg_match('#^\.\./|/\.\./#', $path) ? realpath($path) : $path;}/*此函数用来记录在析构函数中需要删除的资源列表*/protected function toDelete($name){  //写日志,记录需要删除的文件信息  $this->debug(3, "Scheduling file $name to delete on destruct.");//添加到待删除数组$this->toDeletes[] = $name;}/*此函数是截图操作的具体实现*/protected function serveWebshot(){  //写日志,记录开始截图操作,级别3  $this->debug(3, "Starting serveWebshot");//一段提示文字,可以到http://code.google.com/p/timthumb/上按照教程进行网站截图设置$instr = "Please follow the instructions at http://code.google.com/p/timthumb/ to set your server up for taking website screenshots.";//如果CutyCapt不存在if(! is_file(WEBSHOT_CUTYCAPT)){  //退出执行并记录,CutyCapt未被安装return $this->error("CutyCapt is not installed. $instr");}//如果xvfb不存在if(! is_file(WEBSHOT_XVFB)){  //退出执行并记录,xvfb未被安装return $this->Error("Xvfb is not installed. $instr");}//CUTYCAPT地址$cuty = WEBSHOT_CUTYCAPT;//xvfb地址$xv = WEBSHOT_XVFB;//截图屏幕宽度$screenX = WEBSHOT_SCREEN_X;//截图屏幕高度$screenY = WEBSHOT_SCREEN_Y;//截图色深$colDepth = WEBSHOT_COLOR_DEPTH;//截图保存格式$format = WEBSHOT_IMAGE_FORMAT;//截图超时时间,单位ms$timeout = WEBSHOT_TIMEOUT * 1000;//USER_AGENT头$ua = WEBSHOT_USER_AGENT;//是否启用js$jsOn = WEBSHOT_JAVASCRIPT_ON ? 'on' : 'off';//是否启用java$javaOn = WEBSHOT_JAVA_ON ? 'on' : 'off';//是否启用其他插件$pluginsOn = WEBSHOT_PLUGINS_ON ? 'on' : 'off';//是否启用代理$proxy = WEBSHOT_PROXY ? ' --http-proxy=' . WEBSHOT_PROXY : '';//在缓存文件目录,建立一个具有唯一文件名的文件,文件名前缀为timthumb_webshot,用户存储截图后的图片$tempfile = tempnam($this->cacheDirectory, 'timthumb_webshot');//目标网站地址$url = $this->src;//验证url合法性if(! preg_match('/^https?:\/\/[a-zA-Z0-9\.\-]+/i', $url)){  //不合法退出执行return $this->error("Invalid URL supplied.");}//过滤掉非法字符$url = preg_replace('/[^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=]+/', '', $url);//优先使用CUTYCAPTif(WEBSHOT_XVFB_RUNNING){  //设置系统变量,配置图形输出显示。  putenv('DISPLAY=:100.0');//组装shell命令$command = "$cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";//否则使用XVFB} else {$command = "$xv --server-args=\"-screen 0, {$screenX}x{$screenY}x{$colDepth}\" $cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";}//写日志,记录执行的命令,级别3$this->debug(3, "Executing command: $command");//执行命令并捕获输出$out = `$command`;//写日志,记录输出,级别3$this->debug(3, "Received output: $out");//如果刚刚创建的唯一文件名的文件失败if(! is_file($tempfile)){  //设置404错误  $this->set404();  //推出脚本return $this->error("The command to create a thumbnail failed.");}//启用裁剪$this->cropTop = true;//对截取到的图片文件处理并生成缓存if($this->processImageAndWriteToCache($tempfile)){  //成功的话写日志,并从缓存读取此图片  $this->debug(3, "Image processed succesfully. Serving from cache");//返回从缓存中读取的文件内容return $this->serveCacheFile();//没成功就返回假咯} else {return false;}}/*此函数用来从外部url获取图像*/protected function serveExternalImage(){  //验证url合法性if(! preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+/i', $this->src)){$this->error("Invalid URL supplied.");return false;}//生成临时缓存文件$tempfile = tempnam($this->cacheDirectory, 'timthumb');//写日志,记录读取外部图像到临时文件,级别3$this->debug(3, "Fetching external image into temporary file $tempfile");//将临时缓存文件加入到待删除列表$this->toDelete($tempfile);//请求url并将结果写入到临时缓存文件中,如果没有成功if(! $this->getURL($this->src, $tempfile)){  //删除此缓存文件  @unlink($this->cachefile);//再创建一个新的缓存文件touch($this->cachefile);//写日志,记录错误信息,级别3$this->debug(3, "Error fetching URL: " . $this->lastURLError);//写错误信息,并退出$this->error("Error reading the URL you specified from remote host." . $this->lastURLError);return false;}//得到获取到图片的MIME类型$mimeType = $this->getMimeType($tempfile);//如果不在这三种类型中if(! preg_match("/^image\/(?:jpg|jpeg|gif|png)$/i", $mimeType)){  //写日志,记录错误信息,级别3  $this->debug(3, "Remote file has invalid mime type: $mimeType");//删除现有缓存文件@unlink($this->cachefile);//创建新缓存文件touch($this->cachefile);//写错误信息并退出$this->error("The remote file is not a valid image.");return false;}//处理图像并缓存if($this->processImageAndWriteToCache($tempfile)){  $this->debug(3, "Image processed succesfully. Serving from cache");  //成功的话返回缓存信息return $this->serveCacheFile();} else {  //失败返回假return false;}}/*此函数用来将curl获取到的数据写入对应文件中*/public static function curlWrite($h, $d){  //将数据写入文件  fwrite(self::$curlFH, $d);//记录数据长度self::$curlDataWritten += strlen($d);//如果图片大小超过了配置文件的限制,则返回0if(self::$curlDataWritten > MAX_FILE_SIZE){  return 0;//否则返回图片大小} else {return strlen($d);}}/*此函数用来读取并输出服务端缓存*/protected function serveCacheFile(){  //写日志,记录读取缓存的地址  $this->debug(3, "Serving {$this->cachefile}");//如果缓存地址无效if(! is_file($this->cachefile)){  //添加到错误记录  $this->error("serveCacheFile called in timthumb but we couldn't find the cached file.");//停止执行脚本return false;}//缓存地址有效的话,已只读方式打开文件$fp = fopen($this->cachefile, 'rb');//如果打开失败,直接退出脚本,并记录错误信息if(! $fp){ return $this->error("Could not open cachefile."); }//设定文件指针跳过filePrependSecurityBlock值,也就是跳过安全头后开始读fseek($fp, strlen($this->filePrependSecurityBlock), SEEK_SET);//读出文件的mime类型$imgType = fread($fp, 3);//再跳过这个mime类型的值fseek($fp, 3, SEEK_CUR);//如果现在文件的指针不是在安全头后6个字符的位置,说明缓存文件可能已损坏if(ftell($fp) != strlen($this->filePrependSecurityBlock) + 6){  //删除此缓存文件  @unlink($this->cachefile);//记录错误并退出执行return $this->error("The cached image file seems to be corrupt.");}//缓存图片的实际大小应该是文件大小 - 安全头大小$imageDataSize = filesize($this->cachefile) - (strlen($this->filePrependSecurityBlock) + 6);//设置输出必要的HTTP头$this->sendImageHeaders($imgType, $imageDataSize);//输出文件指针处所有剩余数据$bytesSent = @fpassthru($fp);//关闭文件资源fclose($fp);//如果此方法执行成功,则返回真if($bytesSent > 0){return true;}//如果fpassthru不成功,则用file_get_contents读取并输出$content = file_get_contents ($this->cachefile);//如果读取成功if ($content != FALSE) {  //截取掉安全头  $content = substr($content, strlen($this->filePrependSecurityBlock) + 6);//输出图像echo $content;//写日志,记录读取缓存的方式$this->debug(3, "Served using file_get_contents and echo");return true;//读取失败的话记录错误信息并退出执行} else {$this->error("Cache file could not be loaded.");return false;}}/*此函数设置图片输出必要的http头*/protected function sendImageHeaders($mimeType, $dataSize){  //补全图片的mime信息if(! preg_match('/^image\//i', $mimeType)){$mimeType = 'image/' . $mimeType;}//将jpg的mime类型写标准,这里不标准的原因是在验证文件安全头时追求了便利性if(strtolower($mimeType) == 'image/jpg'){$mimeType = 'image/jpeg';}//浏览器缓存失效时间$gmdate_expires = gmdate ('D, d M Y H:i:s', strtotime ('now +10 days')) . ' GMT';//文档最后被修改时间,用来让浏览器判断是否需要重新请求页面$gmdate_modified = gmdate ('D, d M Y H:i:s') . ' GMT';// 设置HTTP头header ('Content-Type: ' . $mimeType);header ('Accept-Ranges: none'); header ('Last-Modified: ' . $gmdate_modified);header ('Content-Length: ' . $dataSize);//如果配置文件禁止浏览器缓存,则设置相应的HTTP头信息if(BROWSER_CACHE_DISABLE){$this->debug(3, "Browser cache is disabled so setting non-caching headers.");header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');header("Pragma: no-cache");header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));//否则按配置文件设置缓存时间} else {$this->debug(3, "Browser caching is enabled");header('Cache-Control: max-age=' . BROWSER_CACHE_MAX_AGE . ', must-revalidate');header('Expires: ' . $gmdate_expires);}//运行成功返回真return true;}/*自定义的验证函数*/protected function securityChecks(){}/*此函数用来获取$_GET数组中的参数,并允许设置默认值*/protected function param($property, $default = ''){  //如果参数存在则返回此参数if (isset ($_GET[$property])) {  return $_GET[$property];//不存在的话返回默认值} else {return $default;}}/*此函数根据传入mime类型,打开图像资源*/protected function openImage($mimeType, $src){switch ($mimeType) {case 'image/jpeg':$image = imagecreatefromjpeg ($src);break; case 'image/png':$image = imagecreatefrompng ($src);break; case 'image/gif':$image = imagecreatefromgif ($src);break;//不是这三种的话,脚本退出default:$this->error("Unrecognised mimeType");}//返回图像资源return $image;}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
/*没啥说的,获取客户端IP*/protected function getIP(){$rem = @$_SERVER["REMOTE_ADDR"];$ff = @$_SERVER["HTTP_X_FORWARDED_FOR"];$ci = @$_SERVER["HTTP_CLIENT_IP"];if(preg_match('/^(?:192\.168|172\.16|10\.|127\.)/', $rem)){ if($ff){ return $ff; }if($ci){ return $ci; }return $rem;} else {if($rem){ return $rem; }if($ff){ return $ff; }if($ci){ return $ci; }return "UNKNOWN";}}/*debug运行日志函数,用来向系统日志记录操作信息*/protected function debug($level, $msg){  //如果开启了debug,并且$level也就是调试级别小于等于配置文件中的值,则开始记录  if(DEBUG_ON && $level <= DEBUG_LEVEL){//格式化并记录开始时间,保留小数点后6位,这个时间代表实例化类后到这个debug执行所经历的时间  $execTime = sprintf('%.6f', microtime(true) - $this->startTime);//这个值代表从上次debug结束,到这次debug的用时$tick = sprintf('%.6f', 0);//如果上次debug时间存在,则用当前时间减去上次debug时间,得出差值if($this->lastBenchTime > 0){$tick = sprintf('%.6f', microtime(true) - $this->lastBenchTime);}//将时间更新$this->lastBenchTime = microtime(true);//将debug信息写到系统日志中error_log("TimThumb Debug line " . __LINE__ . " [$execTime : $tick]: $msg");}}/*此函数用来记录未知BUG*/protected function sanityFail($msg){  //记录BUG信息return $this->error("There is a problem in the timthumb code. Message: Please report this error at <a href='http://code.google.com/p/timthumb/issues/list'>timthumb's bug tracking page</a>: $msg");}/*此函数用来返回图片文件的MIME信息*/protected function getMimeType($file){  //获取图片文件的信息  $info = getimagesize($file);//成功则返回MIME信息if(is_array($info) && $info['mime']){return $info['mime'];}//失败返回空return '';}/*此函数用来检测并设置php运行时最大占用内存的值*/protected function setMemoryLimit(){  //获取php.ini中的最大内存占用的值  $inimem = ini_get('memory_limit');//将上面得到的值转换为以字节为单位的数值$inibytes = timthumb::returnBytes($inimem);//算出配置文件中内存限制的值$ourbytes = timthumb::returnBytes(MEMORY_LIMIT);//如果php配置文件中的值小于自己设定的值if($inibytes < $ourbytes){  //则将php.ini配置中关于最大内存的值设置为自己设定的值  ini_set ('memory_limit', MEMORY_LIMIT);  //写日志,记录改变内存操作,级别3$this->debug(3, "Increased memory from $inimem to " . MEMORY_LIMIT);//如果自己设置的值小于php.ini中的值} else {  //则不进行任何操作,写日志记录此条信息即可,级别3$this->debug(3, "Not adjusting memory size because the current setting is " . $inimem . " and our size of " . MEMORY_LIMIT . " is smaller.");}}/*此函数将G, KB, MB 转为B(字节)*/protected static function returnBytes($size_str){  //取最后一个单位值,进行转换操作,并返回转换后的值switch (substr ($size_str, -1)){case 'M': case 'm': return (int)$size_str * 1048576;case 'K': case 'k': return (int)$size_str * 1024;case 'G': case 'g': return (int)$size_str * 1073741824;default: return $size_str;}}/*此函数用来将url中的资源读取到tempfile文件中*/protected function getURL($url, $tempfile){  //重置上次url请求错误信息  $this->lastURLError = false;  //进行url编码$url = preg_replace('/ /', '%20', $url);//优先使用curl扩展if(function_exists('curl_init')){  //写日志,记录将使用curl扩展访问url,级别3  $this->debug(3, "Curl is installed so using it to fetch URL.");//打开文件self::$curlFH = fopen($tempfile, 'w');//如果打开失败,记录错误信息并退出if(! self::$curlFH){$this->error("Could not open $tempfile for writing.");return false;}//重置写入长度self::$curlDataWritten = 0;//写日志,记录访问的url信息,级别3$this->debug(3, "Fetching url with curl: $url");//初始化curl$curl = curl_init($url);//curl选项设置curl_setopt ($curl, CURLOPT_TIMEOUT, CURL_TIMEOUT);curl_setopt ($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30");curl_setopt ($curl, CURLOPT_RETURNTRANSFER, TRUE);curl_setopt ($curl, CURLOPT_HEADER, 0);curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, FALSE);//关闭会话时执行curlWritecurl_setopt ($curl, CURLOPT_WRITEFUNCTION, 'timthumb::curlWrite');@curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, true);@curl_setopt ($curl, CURLOPT_MAXREDIRS, 10);//执行本次请求,并将结果赋给$curlResult$curlResult = curl_exec($curl);//释放文件资源fclose(self::$curlFH);//获取最后一个受到的HTTP码$httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);//如果是404,那么设置404错误并退出if($httpStatus == 404){$this->set404();}//如果请求成功if($curlResult){  //关闭curl,并执行curlWrite将数据写到文件中  curl_close($curl);  //返回真,请求完成return true;//如果请求不成功} else {  //记录错误信息  $this->lastURLError = curl_error($curl);//关闭资源curl_close($curl);//执行不成功return false;}//如果不支持curl,用file_get_contents获取数据} else {  //获取数据  $img = @file_get_contents ($url);//如果获取失败if($img === false){  //记录返回的错误信息数组  $err = error_get_last();  //如果记录到了,并且有错误信息if(is_array($err) && $err['message']){  //则记录这个错误信息  $this->lastURLError = $err['message'];//否则的话记录整个错误信息} else {$this->lastURLError = $err;}//如果错误信息中有404,则设置为404错误if(preg_match('/404/', $this->lastURLError)){$this->set404();}//返回假return false;}//如果将读取的图片写入文件失败if(! file_put_contents($tempfile, $img)){  //写错误信息并退出执行$this->error("Could not write to $tempfile.");return false;}//没问题的话执行成功return true;} }/*此函数输出指定的图片,用于输出错误信息中*/protected function serveImg($file){  //获取图像信息  $s = getimagesize($file);//如果获取不到图像信息,推出if(! ($s && $s['mime'])){return false;}//设置http头,输出图片header ('Content-Type: ' . $s['mime']);header ('Content-Length: ' . filesize($file) );header ('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');header ("Pragma: no-cache");//使用readfile输出图片$bytes = @readfile($file);if($bytes > 0){return true;}//如果失败,使用file_get_contents和echo输出图片$content = @file_get_contents ($file);if ($content != FALSE){echo $content;return true;}//还失败的话返回假return false;}/*此函数设置404 错误码*/protected function set404(){$this->is404 = true;}/*此函数返回404错误码*/protected function is404(){return $this->is404;}}

附:

timthumb.php缩略图访问地址结构:
1
http://localhost/timthumb.php?src=http://localhost/200.jpg&amp;w=200&amp;h=300&amp;q=100&amp;f=3,9|4,2&amp;s=1&amp;ct=1
参数都是get提交的,参数说明:
  • src : 需要进行图片缩放的源图片地址,或者是需要进行截图操作的网页地址

  • webshot : 如果此值为真则进行截图操作

  • w : 生成图片的宽度,如果宽度或高度只设置了一个值,则根据其中一个值进行等比缩放

  • h : 生成图片的高度,如果高度和宽度都没有指定,则默认为100*100

  • zc : 生成图片的缩放模式,可选值0, 1, 2, 3, 默认为1,每个值的不同之处可看下面文件的第100行注释

  • q : 生成图片的质量,默认90

  • a : 超出部分的裁剪位置,和缩放模式有关,可选值t, b, l, r, 默认为从顶部裁剪

  • f : 需要对生成后的图片使用一些过滤器的话,则在这里传不同过滤器的代码和值,具体操作方法可见下面文件的第821行注解

  • s : 是否对生产的图片进行锐化处理

  • cc : 生成图片的背景画布颜色

  • ct : 生成png图片时背景是否透明

打赏支付宝打赏微信打赏
  • QQ交流群
  • 互相指导
  • 博客主微信
  • 方便沟通

没有评论,留下你的印记,证明你来过。


发表评论:取消回复

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。