使用404被动生成缩略图

在我们的项目中,图片是根据模板的不同显示不同的规格,所以无法预先生成缩略图。而图片是存储在专门的图片文件服务器上的,我们要求图片请求除第一次生成之外,访问的是真实的图片文件。主要思路是通过404跳转生成缩略图。具体方法:

1. 图片上传到文件服务器,图片的相对路径保存到相应的数据字段中。


2.模板显示的时候,根据模板要求,生成该图片缩略图的URL,缩略图URL中包含有图片原始地址,缩略图大小,缩略规则,水印规则

	/**
	 * 根据原图名获取缩略图的访问地址,规格段需要进行加密
	 *
	 * @param String $filename 文件名
	 * @param int $width 宽度
	 * @param int $height 高度
	 * @param Char $tyep f:fix,fw:fix width,fh:fix height,c:cut,a:auto,n:原图,不做任何处理,图片生成方式
	 * @param $watermark 水印规则,0表示不加水印
	 * @param String $toJpeg 是否转换为jpg y:转换 n:不转换
	 * @return String 缩略图访问地址
	 */
	public static function getImgUrl($filename,$width=0,$height=0,$type='f',$watermark=0,$toJpeg='n')
	{
		//如果是远程路径,直接返回
		if(strpos($filename,"http://") === 0){
				return $filename;
		}
		$base_img_url = IMG_BASE_URL;
		if($filename == ""){
			return DEFAULT_IMG_URL;
		}
		if($type == 'n'){
			return $base_img_url.$filename;
		}
		$extend = pathinfo($filename);
		$ext    = strtolower($extend["extension"]);
		
		//是否转换为jpg
		if(($ext == 'png') && ($toJpeg == 'y')){
			$format = 'jpg';
		}else{
			$format = $ext;
		}
		//$url = str_replace("images",$base_img_url,$filename);
		$url = $base_img_url.$filename;
		$width = intval($width);
		$height = intval($height);
		if($watermark===0){
			return str_replace(".$ext",'_'.$ext.'_cacheimages'.'_H_'.Util::encrypt_unrand($width.'_'.$height."_$type").".".$format,$url);
		}else{
			return str_replace(".$ext",'_'.$ext.'_cacheimages'.'_H_'.Util::encrypt_unrand($width.'_'.$height."_$type"."_".$watermark).".".$format,$url);
		}
	}

3.浏览器向图片服务器请求缩略图的URL,该URL 对应的图片如果已经生成则正常访问

4.如果该图片不存在,则触发404跳转,跳转到我们设定的缩略图生成文件。这一步需要在web服务中设置,将默认的404文件 改成我们的缩略图生成文件,我的是Apache,

<VirtualHost *>
serverName img.xxx.com
Header set Access-Control-Allow-Origin http://www.xxx.com
DocumentRoot D:/www/xxx/trunk/static/
	<Directory "D:/www/xxx/trunk/static/">
	    Options Indexes FollowSymLinks MultiViews
	    AllowOverride All
	    Order allow,deny
	    Allow from all
	</Directory>
<span style="background-color: rgb(255, 255, 153);">ErrorDocument 404 /imageServer/404.php</span>
</VirtualHost>

5.缩略图生成文件时,先解析URL,得出缩略图的原图和各种规则,然后生成,并保存到URL所指定的地址,然后直接输出缩略图数据,显示在浏览器中。

/**
 * 404错误页面处理图片缩略图生成
 */
include "config.php";
$imgpath = $_SERVER['REDIRECT_URL'] ? $_SERVER['REDIRECT_URL'] : $_SERVER['REQUEST_URI'];
$imgpath = substr($imgpath,1,strlen($imgpath)-1);
$pos = strpos($imgpath,'?');
if($pos !== false){
	$imgpath = substr($imgpath,0,$pos);
}
$imgarr = pathinfo($imgpath);

if(!in_array(trim(strtolower($imgarr['extension'])),array('jpg','jpeg','gif','png','bmp'))){
	exit;
}
$filename = $imgarr['filename'];
$arr = explode("_",$filename);
$arr_len = count($arr);

/** 加密后,解密 **/
$spec = explode("_",decrypt2($arr[$arr_len-1]));
$w = $spec[0];
$h = $spec[1];
if($arr[$arr_len-2] != 'H'){
	$w = ceil($w/2);
	$h = ceil($h/2);
}
$spec['2'] = trim($spec['2']);
$type = in_array($spec['2'],array('a','f','fw','fh','c','tc','cc')) ? $spec['2'] : 'a';
$watermark = isset($spec['3']) ? $spec['3'] : 0;
include "imageResize.func.php";
//获取原图路径
$arr1 = explode("_cacheimages_",$filename);
$src_name = $arr1[0];
if($arr_len == 6){
	$file = IMG_DIR.$imgarr['dirname'].'/'.$arr[0].'_'.$arr[1].'.'.$arr[$arr_len-4];
}else{
	$arr2 = explode("_",$src_name);
	$arr2_len = count($arr2);
	if($arr2_len == 1){
		$file = IMG_DIR.$imgarr['dirname'].'/'.$arr2[0].".".$imgarr['extension'];
	}else{
		$ex = strtolower ($arr2[$arr2_len-1]);
		if($ex == 'png' || $ex == 'jpg' || $ex == 'gif' || $ex == 'bmp'){
			$file = IMG_DIR.$imgarr['dirname'].'/'.$arr2[0].".".$ex;
		}else{
			$file = IMG_DIR.$imgarr['dirname'].'/'.$arr2[0].'_'.$arr2[1].".".$imgarr['extension'];
		}
	}
}

//获取缩略图文件名
//$imgpath = str_replace('.'.$imgarr['extension'],'.'.$arr[$arr_len-3],$imgpath);
$newfile = IMG_DIR.$imgpath;
if(imageResize($file,$newfile,$w,$h,$type)){
	ob_clean();
<span style="color:#ffffff;">	</span><span style="background-color: rgb(255, 255, 153);">header("HTTP/1.1 200 OK");</span><span style="color:#ffffff;">
</span>	header("Expires: ".gmdate("D, d M Y H:i:s", time()+315360000)." GMT");
	header("Cache-Control: max-age=315360000");
	header("Content-type: image/jpeg");
	if($watermark==1){
		imageWaterMark($newfile,9,'../images/watermark150.png');
	}elseif($watermark==2){
		imageWaterMark($newfile,9,'../images/watermark200.png');
	}elseif($watermark==3){
		imageWaterMark($newfile,9,'../images/watermark250.png');
	}
	echo file_get_contents($newfile);
}else{
	ob_clean();
	<span style="background-color: rgb(255, 255, 153);">header("HTTP/1.1 200 OK");</span>
	header("Expires: ".gmdate("D, d M Y H:i:s", time()+315360000)." GMT");
	header("Cache-Control: max-age=315360000");
	header("Content-type: image/jpeg");
	$newfile = IMG_DIR."images/default.png";
	echo file_get_contents($newfile);
}

function realImage($url,$key = "imgkey"){
    //本地要去除项目目录(autowebsite3g_svn)
    $url = parse_url($url,PHP_URL_PATH);
    if (substr($url, 0, 14) != "/_cache_images") {
        return false;
    } else {
        $url = substr($url, 15);
    }    
    $h = substr($url,0,2);
    $url = substr($url,2);
    $extend = pathinfo($url);
    if($h=='H0'){
    	$real_url = Util::decrypt($extend['filename'],$key);
    	$real_url_info = pathinfo($real_url);
    	$file_info = explode('_', $real_url_info['filename']);
    	$widthandheight_info = explode('x', $file_info[count($file_info)-2]);
    	$new_widthandheight = strval(intval($widthandheight_info[0])/2)."x".strval(intval($widthandheight_info[1])/2);
    	return str_replace($file_info[count($file_info)-2],$new_widthandheight,$real_url);
    }else{
    	return decrypt($extend['filename'],$key);
    }
}
    
    function decrypt2($txt, $key = 'anihc ctI') {
    	if($key == 'ewebsoft'){
    		return $txt;
    	}
    	$txt = str_replace("@","_",$txt);
        $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
        $ikey = "-x6g6ZWm2G9g_vr0Bo.pOq3kRIxsZ6rm";
        $knum = 0;
        $i = 0;
        $tlen = strlen($txt);
        while (isset($key{$i}))
            $knum +=ord($key{$i++});
        $ch1 = $txt{$knum % $tlen};
        $nh1 = strpos($chars, $ch1);
        $txt = substr_replace($txt, '', $knum % $tlen--, 1);
        if(strlen($txt)==0){
        	//TODO错误处理
        	echo '非法参数';exit;
        }
        $ch2 = $txt{$nh1 % $tlen};
        $nh2 = strpos($chars, $ch2);
        $txt = substr_replace($txt, '', $nh1 % $tlen--, 1);
    	if(strlen($txt)==0){
    		//TODO错误处理
        	echo '非法参数';exit;
        }
        $ch3 = $txt{$nh2 % $tlen};
        $nh3 = strpos($chars, $ch3);
        $txt = substr_replace($txt, '', $nh2 % $tlen--, 1);
        $nhnum = $nh1 + $nh2 + $nh3;
        $mdKey = substr(md5(md5(md5($key . $ch1) . $ch2 . $ikey) . $ch3), $nhnum % 8, $knum % 8 + 16);
        $tmp = '';
        $j = 0;
        $k = 0;
        $tlen = strlen($txt);
        $klen = strlen($mdKey);
        for ($i = 0; $i < $tlen; $i++) {
            $k = $k == $klen ? 0 : $k;
            $j = strpos($chars, $txt{$i}) - $nhnum - ord($mdKey{$k++});
            while ($j < 0)
                $j+=64;
            $tmp .= $chars{$j};
        }
        $tmp = str_replace(array('-', '#', '.','@'),array('+', '/', '=','_'),  $tmp);
        return base64_decode($tmp);
    } 
    
    
    /*
* 功能:PHP图片水印 (水印支持图片或文字)
* 参数:
*$groundImage 背景图片,即需要加水印的图片,暂只支持GIF,JPG,PNG格式;
*$waterPos水印位置,有10种状态,0为随机位置;
*1为顶端居左,2为顶端居中,3为顶端居右;
*4为中部居左,5为中部居中,6为中部居右;
*7为底端居左,8为底端居中,9为底端居右;
*$waterImage图片水印,即作为水印的图片,暂只支持GIF,JPG,PNG格式;
*$waterText文字水印,即把文字作为为水印,支持ASCII码,不支持中文;
*$textFont文字大小,值为1、2、3、4或5,默认为5;
*$textColor文字颜色,值为十六进制颜色值,默认为#FF0000(红色);
*
* 注意:Support GD 2.0,Support FreeType、GIF Read、GIF Create、JPG 、PNG
*$waterImage 和 $waterText 最好不要同时使用,选其中之一即可,优先使用 $waterImage。
*当$waterImage有效时,参数$waterString、$stringFont、$stringColor均不生效。
*加水印后的图片的文件名和 $groundImage 一样。
* 作者:longware @ 2004-11-3 14:15:13
*/

function imageWaterMark($groundImage,$waterPos=0,$waterImage="",$waterText="",$textFont=5,$textColor="#FF0000"){
    $isWaterImage = FALSE;
    $formatMsg = "暂不支持该文件格式,请用图片处理软件将图片转换为GIF、JPG、PNG格式。";
    //读取水印文件
    if(!empty($waterImage) && file_exists($waterImage)){
        $isWaterImage = TRUE;
        $water_info = getimagesize($waterImage);
        $water_w = $water_info[0];//取得水印图片的宽
        $water_h = $water_info[1];//取得水印图片的高 
        switch($water_info[2]){//取得水印图片的格式
            case 1:$water_im = imagecreatefromgif($waterImage);break;
            case 2:$water_im = imagecreatefromjpeg($waterImage);break;
            case 3:$water_im = imagecreatefrompng($waterImage);break;
            default:die($formatMsg);
        }
    }
    //读取背景图片
    if(!empty($groundImage) && file_exists($groundImage)){
        $ground_info = getimagesize($groundImage);
        $ground_w = $ground_info[0];//取得背景图片的宽
        $ground_h = $ground_info[1];//取得背景图片的高
        switch($ground_info[2])//取得背景图片的格式
        {
            case 1:$ground_im = imagecreatefromgif($groundImage);break;
            case 2:$ground_im = imagecreatefromjpeg($groundImage);break;
            case 3:$ground_im = imagecreatefrompng($groundImage);break;
            default:die($formatMsg);
        }
    }else{
        die("需要加水印的图片不存在!");
    }
    //水印位置
    if($isWaterImage)//图片水印
    {
        $w = $water_w;
        $h = $water_h;
        $label = "图片的";
    }else{//文字水印
        $temp = imagettfbbox(ceil($textFont*5),0,"./cour.ttf",$waterText);//取得使用 TrueType 字体的文本的范围
        $w = $temp[2] - $temp[6];
        $h = $temp[3] - $temp[7];
        unset($temp);
        $label = "文字区域";
    }
    if( ($ground_w<$w) || ($ground_h<$h) ){
        echo "需要加水印的图片的长度或宽度比水印".$label."还小,无法生成水印!";
        return;
    }
    switch($waterPos){
        case 0://随机
            $posX = rand(0,($ground_w - $w));
            $posY = rand(0,($ground_h - $h));
            break;
        case 1://1为顶端居左
            $posX = 0;
            $posY = 0;
            break;
        case 2://2为顶端居中
            $posX = ($ground_w - $w) / 2;
            $posY = 0;
            break;
        case 3://3为顶端居右
            $posX = $ground_w - $w;
            $posY = 0;
            break;
        case 4://4为中部居左
            $posX = 0;
            $posY = ($ground_h - $h) / 2;
            break;
        case 5://5为中部居中
            $posX = ($ground_w - $w) / 2;
            $posY = ($ground_h - $h) / 2;
            break;
        case 6://6为中部居右
            $posX = $ground_w - $w;
            $posY = ($ground_h - $h) / 2;
            break;
        case 7://7为底端居左
            $posX = 0;
            $posY = $ground_h - $h;
            break;
        case 8://8为底端居中
            $posX = ($ground_w - $w) / 2;
            $posY = $ground_h - $h;
            break;
        case 9://9为底端居右
            $posX = $ground_w - $w - 10;   // -10 是距离右侧10px 可以自己调节
            $posY = $ground_h - $h - 0;   // -10 是距离底部10px 可以自己调节
            break;
        default://随机
            $posX = rand(0,($ground_w - $w));
            $posY = rand(0,($ground_h - $h));
            break;
    }
    //设定图像的混色模式
    imagealphablending($ground_im, true);
    if($isWaterImage){//图片水印
        imagecopy($ground_im, $water_im, $posX, $posY, 0, 0, $water_w,$water_h);//拷贝水印到目标文件 
    }else{//文字水印
        if( !emptyempty($textColor) && (strlen($textColor)==7) ){
            $R = hexdec(substr($textColor,1,2));
            $G = hexdec(substr($textColor,3,2));
            $B = hexdec(substr($textColor,5));
        }else{
            die("水印文字颜色格式不正确!");
        }
        imagestring ( $ground_im, $textFont, $posX, $posY, $waterText, imagecolorallocate($ground_im, $R, $G, $B)); 
    }
    //生成水印后的图片
    @unlink($groundImage);
    switch($ground_info[2]){//取得背景图片的格式
        case 1:imagegif($ground_im,$groundImage);break;
        case 2:imagejpeg($ground_im,$groundImage);break;
        case 3:imagepng($ground_im,$groundImage);break;
        default:die($errorMsg);
    }
    //释放内存
    if(isset($water_info)) unset($water_info);
    if(isset($water_im)) imagedestroy($water_im);
    unset($ground_info);
    imagedestroy($ground_im);
}
    
注意上面高亮的部分,这是将返回状态从404改回到200。否则在第一次生成的时候,浏览器发现状态是404就不显示图片了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值