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实现框架(二)
Oct 09 PHP
社区(php&amp;&amp;mysql)一
Oct 09 PHP
让PHP支持页面回退的两种方法[转]
Feb 14 PHP
php中删除字符串中最先出现某个字符的实现代码
Feb 03 PHP
php生成随机字符串可指定纯数字、纯字母或者混合的
Apr 18 PHP
php通过分类列表产生分类树数组的方法
Apr 20 PHP
php中header跳转使用include包含解决参数丢失问题
May 08 PHP
使用PHP下载CSS文件中的所有图片【几行代码即可实现】
Dec 14 PHP
详解thinkphp实现excel数据的导入导出(附完整案例)
Dec 29 PHP
php实现支付宝当面付(扫码支付)功能
May 30 PHP
Thinkphp框架使用list_to_tree 实现无限级分类列出所有节点示例
Apr 04 PHP
Yii框架多语言站点配置方法分析【中文/英文切换站点】
Apr 07 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
PHP安全编程之加密功能
2006/10/09 PHP
给多个地址发邮件的类
2006/10/09 PHP
hadoop常见错误以及处理方法详解
2013/06/19 PHP
动态表单验证的操作方法和TP框架里面的ajax表单验证
2017/07/19 PHP
php测试kafka项目示例
2020/02/06 PHP
yii 框架实现按天,月,年,自定义时间段统计数据的方法分析
2020/04/04 PHP
jquery load()在firefox(火狐)下显示不正常的解决方法
2011/04/05 Javascript
动态加载js的方法汇总
2015/02/13 Javascript
实例详解jQuery Mockjax 插件模拟 Ajax 请求
2016/01/12 Javascript
vue实现app页面切换动画效果实例
2017/05/23 Javascript
分析JS单线程异步io回调的特性
2017/12/01 Javascript
vue项目中用cdn优化的方法
2018/01/03 Javascript
vue-cli配置文件——config篇
2018/01/04 Javascript
vue keep-alive请求数据的方法示例
2018/05/16 Javascript
babel7.x和webpack4.x配置vue项目的方法步骤
2019/05/12 Javascript
微信小程序canvas截取任意形状的实现代码
2020/01/13 Javascript
redux处理异步action解决方案
2020/03/22 Javascript
vue 实现setInterval 创建和销毁实例
2020/07/21 Javascript
ant-design-vue中tree增删改的操作方法
2020/11/03 Javascript
使用PYTHON创建XML文档
2012/03/01 Python
Python实现的数据结构与算法之基本搜索详解
2015/04/22 Python
Python测试人员需要掌握的知识
2018/02/08 Python
基于Python socket的端口扫描程序实例代码
2018/02/09 Python
tensorflow构建BP神经网络的方法
2018/03/12 Python
解决更改AUTH_USER_MODEL后出现的问题
2020/05/14 Python
基于PyTorch的permute和reshape/view的区别介绍
2020/06/18 Python
Django def clean()函数对表单中的数据进行验证操作
2020/07/09 Python
PyCharm Ctrl+Shift+F 失灵的简单有效解决操作
2021/01/15 Python
德国健康生活方式网上商店:Landkaufhaus Mayer
2019/03/12 全球购物
G-Form护具官方网站:美国运动保护装备
2019/09/04 全球购物
健康教育评估方案
2014/05/25 职场文书
民生工作实施方案
2014/05/31 职场文书
防暑降温通知书
2015/04/27 职场文书
Python中for后接else的语法使用
2021/05/18 Python
javascript条件式访问属性和箭头函数介绍
2021/11/17 Javascript
Hive HQL支持2种查询语句风格
2022/06/25 数据库