php实现远程图片本地化的方法

      web应用特别是cms管理系统,经常出现远程图片本地化的需求实现,很多已插件方式提供,很多只是配置使用,但是做到自己定制化实现特定的需求可能就力不从心了。我们来实现一下远程图片本地化的功能。

      远程图片本地化,主要实现思路是,远程图片可能是一个url地址,也可能是一个base64编码的图片,我们只要将这个图片通过方法下载到当前服务器路径下,然后改变存储路径,一般可能是一篇文章中包含的图片,那么我们只要遍历其中的图片,用上述方法做本地化,然后把这个文章的html串中的图片远程路径替换成本地化的路径,再重新保存就可以了。还有一个需求是将一篇文章的第一张图片保存成文章封面,这个就将那个html串中的第一个图片路径提取出来,保存为封面路径即可。实现思路大致这些,可能其中会遇到各种各样的问题。

我们先看下代码:

远程图片url获取到本地的函数

 private static function grabImage($a_url,$a_savePath){
	if($a_url != ""){	//如果图片地址为空
	  $a_url=str_replace(['&'],['&'],$a_url); //url中特定字符替换
		//获取图片信息大小
	  $imgSize = getImageSize($a_url);
	  if(!in_array($imgSize['mime'],array('image/jpg', 'image/gif', 'image/png', 'image/jpeg'),true)){  return ''; }
 	  //获取后缀名
	  $_mime = explode('/', $imgSize['mime']);
	  $ext = '.'.end($_mime);
		$new_file = $a_savePath ."/";
        if (!file_exists($new_file)) {
            //检查是否有该文件夹,如果没有就创建,并给予最高权限
            mkdir($new_file, 0700);
        }
		$filename_r = time().rand(10,9000).$ext;	//给图片命名
		$filename = $new_file.$filename_r;//.'/'
		ob_start();	//打开缓冲区
		readfile($a_url);	
		$imgInfo = ob_get_contents();	//获得缓冲区的内容
		ob_end_clean(); //清除并关闭缓冲区
		//$fp = fopen($filename,'a');		fwrite($fp,$imgInfo);	fclose($fp);
	
		$fp = fopen($filename, 'a');
		$imgLen = strlen($imgInfo);    //计算图片源码大小
		$_inx = 1024;   //每次写入1k
		$_time = ceil($imgLen/$_inx);
		for($i=0; $i<$_time; $i++){
			fwrite($fp,substr($imgInfo, $i*$_inx, $_inx));
		}
		fclose($fp);	unset($imgInfo,$a_url);
		return $filename;
	}else{
		return '';
	}
  }

Base64图片保存到本地 

private static function base64_image($a_img_htmls, $a_path){
		//正则匹配出图片的格式
		if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $a_img_htmls, $result)) {
			$type = $result[2];  //获取图片格式
			$new_file = $a_path .  "/";
			if (!file_exists($new_file)) {
				//检查是否有该文件夹,如果没有就创建,并给予最高权限
				mkdir($new_file, 0700);
			}
			$new_file = $new_file . time() . ".{$type}";
			if (file_put_contents($new_file, base64_decode(str_replace($result[1], '', $a_img_htmls)))) {
				return  $new_file; //'/' .
			} else {
				return '';
			}
		} else {
			return '';
		}
	}

取得文章中第一张图片
    

private function get_html_first_imgurl($a_contents){
      $result="";
      $pattern= '~<img.*?src=["\']+(.*?)["\']+~';
      preg_match_all($pattern,$a_contents,$matchContent); 
      //return var_dump('matchContent=',$matchContent);
      if(!empty($matchContent)){ $result=$matchContent[1][0]; 
         $result=str_replace('/'.C('C_DATA_DIR'),'',$result);
      }
      return $result;
}

转换内容html串中的图片本地化并解析替换

public static function transImgLocal($html_contents,$a_baseSavePath,$a_localPathFlag){
	$result=$html_contents;
    $html_contents = stripslashes($html_contents);//返回已剥离反斜杠的字符串
	//echo $html_contents; exit;
	$img_array = array();
	//处理远程图片url
	preg_match_all("/(src|SRC)=[\"|'| ]{0,}((http|https):\/\/(.*).(gif|jpg|jpeg|bmp|png))/isU", $html_contents, $img_array );
	// 匹配出来的不重复图片
	if(!empty($img_array)&& count($img_array)>=2){
		$img_array = array_unique ( $img_array [2] );
		//var_dump('img_array=',$img_array); exit;
		//echo $img_array[0];
		foreach($img_array as $item){
		 if(strpos($item,$a_localPathFlag) !== false){ continue; }
		 $filename=self::grabImage($item,$a_baseSavePath);
		//echo $filename;
		 $html_contents=str_replace($item,'/'.$filename,$html_contents);
		}
	}
	//处理base64图片格式
	preg_match_all("/(src|SRC)=[\"|'| ]{0,}(data:image\/(\w+);base64,(.*))(\")/isU", $html_contents, $img_array2);
	if(!empty($img_array2)){
	  $img_array2 = array_unique ( $img_array2 [2] );
	  //var_dump('img_array2=',$img_array2); exit;
		foreach($img_array2 as $item){
		 if(strpos($item,$a_localPathFlag) !== false){ continue; }	
		 $filename=self::base64_image($item,$a_baseSavePath);
		//echo $filename; exit;
		 if(!empty($filename)){ $html_contents=str_replace($item,'/'.$filename,$html_contents); }
		}
	}
	$result=$html_contents;
	
	return $result;
  }

这样,我们调用transImgLocal,传入参数,即可将内容hmtl串中图片本地化,如果指定特定目录,或者其他需求,在此基础上改造即可。

遇到的问题

  • 转换图片本地化后,发现转换成莫名其妙的图片,并不是需要指定的远程的图片,是类似这样,如下(原始图片不是这样)

解决:原来是代码中解析的url路径中包含&amp;被当做特定路径字符串进行解析了,解析成这样的图片资源,后来替换成&,重新下载即可解决。

  • 不能转换远程地址

现象:有时发现有些图片地址不能解析成本地化,仍然保持网络链接的地址。

解决:原来有些图片地址是伪链接,如:https://p6-tt.byteimg.com/origin/pgc-image/72964e39d4dd4054b456fcf9d6b8baf3?from=pc。不包含.jpg,或.png等图片后缀,这样需要修改识别图片链接的正则表达式,

如改为:$reg="/(src|SRC)=[\"|'| ]{0,}((http|https):\/\/(.*))(\")/isU";  调用正则表达式即可解决。

 

本文持续改进完善...

Guess you like

Origin blog.csdn.net/yan_dk/article/details/110467257