PHP抓取远程图片(含不带后缀的)教程详解


Posted in PHP onOctober 21, 2016

一、创建项目

作为演示,我们在www根目录创建项目grabimg,创建一个类GrabImage.php和一个index.php。

二、编写类代码

我们定义一个和文件名相同的类:GrabImage

class GrabImage{

}

三、属性

接下来定义几个需要使用的属性。

      1、首先定义一个需要抓取的图片地址:$img_url

      2、再定义一个$file_name用来存储文件的名称,但是不携带拓展名,因为可能涉及到拓展名更换,所以这里拆开定义

      3、紧接着就是拓展名$extension

      4、然后我们定义一个$file_dir,该属性的作用是,远程图片抓取到本地后所存储的目录,一般相对于PHP入口文件所在的位置作为起始。但是该路径一般不保存到数据库。

      5、最后我们定义一个$save_dir,顾名思义,该路径是用来直接保存的数据库的目录。这里说明下,我们不直接存储文件保存路径到数据库,一般是为了之后如果系统迁移,方便更换路径做准备。我们这里的$save_dir一般为日期 + 文件名,如果需要使用时候取出,在前方拼上所需要的路径。

四、方法

属性弄完了,接下来我们正式开始抓取工作。

首先我们定义一个对外开放的方法getInstances用来获取一些数据,比如抓取图片地址,和本地保存路径。同时将其放入属性中。

public function getInstances($img_url , $base_dir)
{
 $this->img_url = $img_url;
 $this->save_dir = date("Ym").'/'.date("d").'/'; // 比如:201610/19/
 $this->file_dir = $base_dir.'/'.$this->save_dir.'/'; // 比如:./uploads/image/2016/10/19/
}

图片保存路径拼接完成,下面我们要注意一个问题,目录是否存在。日期在一天天走,但是目录并不会自动创建。所以,在保存图片之前,首先需要检查一下,如果当前目录不存在我们需要即时创建。

我们创建设置目录方法setDir。属性我们设置了private,安全

/**
 * 检查图片需要保持的目录是否存在
 * 如果不存在,则立即创建一个目录
 * @return bool
 */
private function setDir()
{
 if(!file_exists($this->file_dir))
 {
  mkdir($this->file_dir,0777,TRUE);
 }

 $this->file_name = uniqid().rand(10000,99999);// 文件名,这里只是演示,实际项目中请使用自己的唯一文件名生成方法

 return true;
}

接下来就是抓取核心代码

第一步,解决一个问题,我们需要抓取的图片可能没有后缀名。按照传统的抓取方法,先抓取图片,然后截取后缀名的方案不可行。

我们必须通过其它方法来获得图片类型。办法就是从文件流信息中获取文件头信息,从而判断文件mime信息,就可以知道文件后缀名。

为了方便,先定义一个mime和文件拓展名映射。

$mimes=array(
 'image/bmp'=>'bmp',
 'image/gif'=>'gif',
 'image/jpeg'=>'jpg',
 'image/png'=>'png',
 'image/x-icon'=>'ico'
);

这样,当我获取了类型是image/gif的时候,我就可以知道是.gif图片了。

利用php函数get_headers,获取文件流头信息。当其值不为false时候我们将其赋值给变量$headers

取出Content-Type的值即为mime的值。

if(($headers=get_headers($this->img_url, 1))!==false){
 // 获取响应的类型
 $type=$headers['Content-Type'];
}

使用上面我们定义的映射表,我们可以很轻松的获取后缀名。

$this->extension=$mimes[$type];

当然上面获取的$type,可能不存在我们的映射表中,说明这种类型文件并不是我们想要的,直接抛弃就好了,不用管它。

下面的步骤就和传统抓取文件一样。

$file_path = $this->file_dir.$this->file_name.".".$this->extension;
// 获取数据并保存
$contents=file_get_contents($this->img_url);
if(file_put_contents($file_path , $contents))
{
 // 这里返回出去的值是直接保存到数据库的路径 + 文件名,形如:201610/19/57feefd7e2a7aY5p7LsPqaI-lY1BF.jpg
 return $this->save_dir.$this->file_name.".".$this->extension;
}

首先获取本地保图片存完整路径$file_path,接下来使用file_get_contents抓取数据,然后使用file_put_contents保存到刚刚的文件路径。

最后我们返回一个可以直接保存到数据库中的路径,而不是文件存储路径。

该抓取方法完整版是:

private function getRemoteImg()
{
 // mime 和 扩展名 的映射
 $mimes=array(
  'image/bmp'=>'bmp',
  'image/gif'=>'gif',
  'image/jpeg'=>'jpg',
  'image/png'=>'png',
  'image/x-icon'=>'ico'
 );
 // 获取响应头
 if(($headers=get_headers($this->img_url, 1))!==false)
 {
  // 获取响应的类型
  $type=$headers['Content-Type'];
  // 如果符合我们要的类型
  if(isset($mimes[$type]))
  {
   $this->extension=$mimes[$type];
   $file_path = $this->file_dir.$this->file_name.".".$this->extension;
   // 获取数据并保存
   $contents=file_get_contents($this->img_url);
   if(file_put_contents($file_path , $contents))
   {
    // 这里返回出去的值是直接保存到数据库的路径 + 文件名,形如:201610/19/57feefd7e2a7aY5p7LsPqaI-lY1BF.jpg
    return $this->save_dir.$this->file_name.".".$this->extension;
   }
  }
 }
 return false;
}

最后,为了简单,我们想在其他地方只要调用其中一个方法就可以完成抓取。所以,我们将抓取动作直接放入到getInstances中,在配置完路径后,直接抓取,所以,在初始化配置方法getInstances里新增代码。

if($this->setDir())
{
 return $this->getRemoteImg();
}
else
{
 return false;
}

测试

我们去刚刚创建的index.php文件内试试。

<?php
require_once 'GrabImage.php';
$object = new GrabImage();
$img_url = "http://www.bidianer.com/img/icon_mugs.jpg"; // 需要抓取的远程图片
$base_dir = "./uploads/image"; // 本地保存的路径
echo $object->getInstances($img_url , $base_dir);
?>

的确抓取过来了

PHP抓取远程图片(含不带后缀的)教程详解

完整代码

<?php
/**
 * 抓取远程图片到本地,可以抓取不带有后缀的图片
 * @author YanYing <yanyinghq@163.com>
 * @link bidianer.com
 */
class GrabImage{

 /**
  * @var string 需要抓取的远程图片的地址
  * 例如:http://www.bidianer.com/img/icon_mugs.jpg
  * 有一些远程文件路径可能不带拓展名
  * 形如:http://www.xxx.com/img/icon_mugs/q/0
  */
 private $img_url;

 /**
  * @var string 需要保存的文件名称
  * 抓取到本地的文件名会重新生成名称
  * 但是,不带拓展名
  * 例如:57feefd7e2a7aY5p7LsPqaI-lY1BF
  */
 private $file_name;

 /**
  * @var string 文件的拓展名
  * 这里直接使用远程图片拓展名
  * 对于没有拓展名的远程图片,会从文件流中获取
  * 例如:.jpg
  */
 private $extension;

 /**
  * @var string 文件保存在本地的目录
  * 这里的路径是PHP保存文件的路径
  * 一般相对于入口文件保存的路径
  * 比如:./uploads/image/201610/19/
  * 但是该路径一般不直接存储到数据库
  */
 private $file_dir;

 /**
  * @var string 数据库保存的文件目录
  * 这个路径是直接保存到数据库的图片路径
  * 一般直接保存日期 + 文件名,需要使用的时候拼上前面路径
  * 这样做的目的是为了迁移系统时候方便更换路径
  * 例如:201610/19/
  */
 private $save_dir;

 /**
  * @param string $img_url 需要抓取的图片地址
  * @param string $base_dir 本地保存的路径,比如:./uploads/image,最后不带斜杠"/"
  * @return bool|int
  */
 public function getInstances($img_url , $base_dir)
 {
  $this->img_url = $img_url;
  $this->save_dir = date("Ym").'/'.date("d").'/'; // 比如:201610/19/
  $this->file_dir = $base_dir.'/'.$this->save_dir.'/'; // 比如:./uploads/image/2016/10/19/
  return $this->start();
 }

 /**
  * 开始抓取图片
  */
 private function start()
 {
  if($this->setDir())
  {
   return $this->getRemoteImg();
  }
  else
  {
   return false;
  }
 }

 /**
  * 检查图片需要保持的目录是否存在
  * 如果不存在,则立即创建一个目录
  * @return bool
  */
 private function setDir()
 {
  if(!file_exists($this->file_dir))
  {
   mkdir($this->file_dir,0777,TRUE);
  }

  $this->file_name = uniqid().rand(10000,99999);// 文件名,这里只是演示,实际项目中请使用自己的唯一文件名生成方法

  return true;
 }

 /**
  * 抓取远程图片核心方法,可以同时抓取有后缀名的图片和没有后缀名的图片
  *
  * @return bool|int
  */
 private function getRemoteImg()
 {
  // mime 和 扩展名 的映射
  $mimes=array(
   'image/bmp'=>'bmp',
   'image/gif'=>'gif',
   'image/jpeg'=>'jpg',
   'image/png'=>'png',
   'image/x-icon'=>'ico'
  );
  // 获取响应头
  if(($headers=get_headers($this->img_url, 1))!==false)
  {
   // 获取响应的类型
   $type=$headers['Content-Type'];
   // 如果符合我们要的类型
   if(isset($mimes[$type]))
   {
    $this->extension=$mimes[$type];
    $file_path = $this->file_dir.$this->file_name.".".$this->extension;
    // 获取数据并保存
    $contents=file_get_contents($this->img_url);
    if(file_put_contents($file_path , $contents))
    {
     // 这里返回出去的值是直接保存到数据库的路径 + 文件名,形如:201610/19/57feefd7e2a7aY5p7LsPqaI-lY1BF.jpg
     return $this->save_dir.$this->file_name.".".$this->extension;
    }
   }
  }
  return false;
 }
}

总结

以上就是这篇文章的全部内容了,希望能对大家学习或者使用PHP能有所帮助,如果有疑问大家可以留言交流。

PHP 相关文章推荐
PHP+javascript模拟Matrix画面
Oct 09 PHP
php基础知识:类与对象(4) 范围解析操作符(::)
Dec 13 PHP
php中常用编辑器推荐
Jan 02 PHP
PHP递归调用的小技巧讲解
Feb 19 PHP
php绘制一条弧线的方法
Jan 24 PHP
php如何实现只替换一次或N次
Oct 29 PHP
PHP简单检测网址是否能够正常打开的方法
Sep 04 PHP
Yii框架实现图片上传的方法详解
May 20 PHP
Laravel配置全局公共函数的方法步骤
May 09 PHP
Laravel推荐使用的十个辅助函数
May 10 PHP
使用laravel的Eloquent模型如何获取数据库的指定列
Oct 17 PHP
PHP设计模式之建造者模式(Builder)原理与用法案例详解
Dec 12 PHP
PHP Header用于页面跳转时的几个注意事项
Oct 21 #PHP
phpcms中的评论样式修改方法
Oct 21 #PHP
PHP+jquery+CSS制作头像登录窗(仿QQ登陆)
Oct 20 #PHP
PHP中的多种加密技术及代码示例解析
Oct 20 #PHP
php rmdir使用递归函数删除非空目录实例详解
Oct 20 #PHP
PHPCMS V9 添加二级导航的思路详解
Oct 20 #PHP
php实现登陆模块功能示例
Oct 20 #PHP
You might like
延长phpmyadmin登录时间的方法
2011/02/06 PHP
PHP数组操作汇总 php数组的使用技巧
2011/07/17 PHP
解析PHP SPL标准库的用法(遍历目录,查找固定条件的文件)
2013/06/18 PHP
PHP生成二维码的两个方法和实例
2014/07/01 PHP
php使用pdo连接报错Connection failed SQLSTATE的解决方法
2014/12/15 PHP
javascript URL锚点取值方法
2009/02/25 Javascript
深入理解Javascript中this的作用域
2014/08/12 Javascript
JavaScript将字符串转换为整数的方法
2015/04/14 Javascript
JavaScript中的substr()方法使用详解
2015/06/06 Javascript
通过Jquery.cookie.js实现展示浏览网页的历史记录超管用
2015/10/23 Javascript
跟我学习javascript创建对象(类)的8种方法
2015/11/20 Javascript
AngularJS报错$apply already in progress的解决方法分析
2017/01/30 Javascript
jQuery实现按比例缩放图片的方法
2017/04/29 jQuery
vue-cli项目如何使用vue-resource获取本地的json数据(模拟服务端返回数据)
2017/08/04 Javascript
webpack4 升级迁移的实现
2018/09/12 Javascript
openlayers4实现点动态扩散
2020/08/17 Javascript
用python + openpyxl处理excel2007文档思路以及心得
2014/07/14 Python
详解使用Python处理文件目录的相关方法
2015/10/16 Python
Python实现单词翻译功能
2017/06/06 Python
python中map()函数的使用方法示例
2017/09/29 Python
python如何使用正则表达式的前向、后向搜索及前向搜索否定模式详解
2017/11/08 Python
Python-OpenCV基本操作方法详解
2018/04/02 Python
python写入并获取剪切板内容的实例
2018/05/31 Python
css3和jquery实现自定义checkbox和radiobox组件
2014/04/22 HTML / CSS
CSS3实现头像旋转效果
2017/03/13 HTML / CSS
CSS3 仿微信聊天小气泡实例代码
2017/04/05 HTML / CSS
Crocs卡骆驰洞洞鞋日本官方网站:Crocs日本
2016/08/25 全球购物
实习销售业务员自我鉴定
2013/09/21 职场文书
销售文员岗位职责
2013/11/29 职场文书
机电专业个人求职信范文
2013/12/30 职场文书
小学庆六一活动方案
2014/02/28 职场文书
高中同学会活动方案
2014/08/14 职场文书
杭州黄龙洞导游词
2015/02/10 职场文书
2016春季运动会开幕词
2016/03/04 职场文书
Python list去重且保持原顺序不变的方法
2021/04/03 Python
vue实现无缝轮播效果(跑马灯)
2021/05/14 Vue.js