Referer原理与图片防盗链实现方法详解


Posted in PHP onJuly 03, 2019

本文实例讲述了Referer原理与图片防盗链实现方法。分享给大家供大家参考,具体如下:

1、图片防盗链

在一些大型网站中,比如百度贴吧,该站点的图片采用了防盗链的规则,以至于使用下面代码会发生错误。

简单代码:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title></title>
  <link rel="stylesheet" href="">
</head>
<body>
  <!--引用一张百度贴吧的图片-->
  <img src="http://imgsrc.baidu.com/forum/pic/item/03a4462309f79052204229be04f3d7ca7acbd5d5.jpg"/>
</body>
</html>

出现的问题:

Referer原理与图片防盗链实现方法详解

出错的原因

主要是该站点的图片采用了防盗链的规则,其实这个规则也比较简单, 和大家一说就知道啦,主要是该站点在得知有请求时,会先判断请求头中的信息,如果请求头中有Referer信息,然后根据自己的规则来判断Referer头信息是否符合要求,Referer 信息是请求该图片的来源地址。

浏览器中的请求头信息:

(1)正常使用百度贴吧查看图片的请求头信息

Referer原理与图片防盗链实现方法详解

(2)我的代码的头信息

Referer原理与图片防盗链实现方法详解

相信读者看到这,也就明白了,为什么我的代码不能访问到图片,而是显示一张警告盗链图片,因为我们的Referer头信息和百度贴吧的不同,当我的请求发出去时,该站点查看Referer头信息,一看来源不是本站,就重定向到另外一张图片了。

给自己的站点配置图片防盗链:

(1)在web服务器中开启mod_rewrite模块

#LoadModule rewrite_module modules/mod_rewrite.so,//将前面的#给去掉,然后重新启动服务器

(2)在需要防盗的网站或目录中,写.htaccess文件,并指定防盗链规则

步骤:

新建一个.htaccess文件,在windows中使用另存为的方式来新建此文件
查找手册,在.htaccess文件中利用正则判断

指定规则:

如果是图片资源且referer头信息是来自于本站,则通过

重写规则如下:

假定我的服务器是localhost,规则的意思是,如果请求的是图片资源,但是请求来源不是本站的话,就重定向到当前目录的一张no.png的图片上

RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} .*\.(jpg|jpeg|png|gif) [NC]
RewriteCond %{HTTP_REFERER} !localhost [NC]
RewriteRule .* no.png

来自localhost的访问:

Referer原理与图片防盗链实现方法详解

来自于其他站点的访问:

Referer原理与图片防盗链实现方法详解

至此,关于防盗链的知识我们学完了,但是不急,既然是一个请求头,当然是可以伪造的,下面我们来说一下反防盗链的规则。

2、反防盗链

上面我的服务器配置了图片防盗链,现在以它来讲解反防盗链,如果我们在采集图片的时候,遇到使用防盗链技术的站点,我们可以在采集图片的时候伪造一个Referer头信息。

下面的代码是从一个配置了图片防盗链的站点下载一张图片。

<?php
/**
 * 下载图片
 * @author webbc
 */
require './Http.class.php';//这个类是我自己封装的一个用于HTTp请求的类
$http = new Http("http://localhost/booledu/http/apple.jpg");
//$http->setHeader('Referer:http://tieba.baidu.com/');//设置referer头
$res = $http->get();
$content = strstr($res,"\r\n\r\n");
file_put_contents('./toutupian.jpg',substr($content,4));
echo "ok";
?>

不加Referer头信息下载的结果:

Referer原理与图片防盗链实现方法详解

加Referer头信息下载的结果:

Referer原理与图片防盗链实现方法详解

相应大家看到这,应该能看出来如何反防盗链吧,其实就是加上一个Referer头信息,那么,每个站点的Referer头信息从哪里找呢?这个应该抓包分析就可以得出来了!

3、封装的Http请求类

<?php
/**
 * Http请求类
 * @author webbc
 */
class Http{
  const CRTF = "\r\n";
  private $errno = -1;
  private $errstr = '';
  private $timeout = 5;
  private $url = null;//解析后的url数组
  private $version = 'HTTP/1.1';//http版本
  private $requestLine = array();//请求行信息
  private $header = array();//请求头信息
  private $body = array();//请求实体信息
  private $fh = null;//连接端口后返回的资源
  private $response = '';//返回的结果
  //构造函数
  public function __construct($url){
    $this->connect($url);
    $this->setHeader('Host:'.$this->url['host']);//设置头信息
  }
  //通过URL进行连接
  public function connect($url){
    $this->url = parse_url($url);//解析url
    if(!isset($this->url['port'])){
      $this->url['port'] = 80;
    }
    $this->fh = fsockopen($this->url['host'],$this->url['port'],$this->errno,$this->errstr,$this->timeout);
  }
  //设置请求行信息
  public function setRequestLine($method){
    $this->requestLine[0] = $method.' '.$this->url['path'].' '.$this->version;
  }
  //设置请求头信息
  public function setHeader($headerLine){
    $this->header[] = $headerLine;
  }
  //设置请求实体信息
  public function setBody($body){
    $this->body[] = http_build_query($body);
  }
  //发送get请求
  public function get(){
    $this->setRequestLine('GET');//设置请求行
    $this->request();//发送请求
    $this->close();//关闭连接
    return $this->response;
  }
  //发送请求
  private function request(){
    //拼接请求的全部信息
    $reqestArr = array_merge($this->requestLine,$this->header,array(''),$this->body,array(''));
    $req = implode(self::CRTF,$reqestArr);
    //print_r($req);die;
    fwrite($this->fh,$req);//写入信息
    //读取
    while(!feof($this->fh)){
      $this->response .= fread($this->fh,1024);
    }
  }
  //发送post请求
  public function post($body = array()){
    //设置请求行
    $this->setRequestLine("POST");
    //设置实体信息
    $this->setBody($body);
    //设置Content-Type
    $this->setHeader('Content-Type:application/x-www-form-urlencoded');
    //设置Content-Length
    $this->setHeader('Content-Length:'.strlen($this->body[0]));
    //请求
    $this->request();
    $this->close();//关闭连接
    return $this->response;
  }
  //关闭连接
  public function close(){
    fclose($this->fh);
  }
}
//测试get
// $http = new Http("http://news.163.com/16/0915/10/C10ES2HA00014PRF.html");
// $result = $http->get();
// echo $result;
//测试post
/*set_time_limit(0);
$str = 'abcdefghijklmnopqrstuvwxyz0123456789';
while(true){
  $http = new Http("http://211.70.176.138/yjhx/message.php");
  $str = str_shuffle($str);
  $username = substr($str,0,5);
  $email = substr($str,5,10).'@qq.com';
  $content = substr($str,10);
  $message = "发表";
  $http->post(array('username'=>$username,'email'=>$email,'content'=>$content,'message'=>$message));
  //sleep(0.1);
}*/
?>

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
PHP 和 XML: 使用expat函数(三)
Oct 09 PHP
PHP如何抛出异常处理错误
Mar 02 PHP
解析posix与perl标准的正则表达式区别
Jun 17 PHP
php stream_get_meta_data返回值
Sep 29 PHP
30个php操作redis常用方法代码例子
Jul 05 PHP
phpExcel中文帮助手册之常用功能指南
Aug 18 PHP
Yii针对添加行的增删改查操作示例
Oct 18 PHP
AJAX的使用方法详解
Apr 29 PHP
php通过header发送自定义数据方法
Jan 18 PHP
TP(thinkPHP)框架多层控制器和多级控制器的使用示例
Jun 13 PHP
使用composer命令加载vendor中的第三方类库 的方法
Jul 09 PHP
php7 list()、session及其他模块的修改实例分析
May 25 PHP
thinkphp5框架调用其它控制器方法 实现自定义跳转界面功能示例
Jul 03 #PHP
Centos7 Yum安装PHP7.2流程教程详解
Jul 02 #PHP
thinkphp5修改view到根目录实例方法
Jul 02 #PHP
PHP rmdir()函数的用法总结
Jul 02 #PHP
PHP+iframe模拟Ajax上传文件功能示例
Jul 02 #PHP
PHP使用HTML5 FormData对象提交表单操作示例
Jul 02 #PHP
PHP实现带进度条的Ajax文件上传功能示例
Jul 02 #PHP
You might like
雄兵连:天使彦天使彦为爱折翼,彦和炙心同时念动的誓言!
2020/03/02 国漫
PHP 数组实例说明
2008/08/18 PHP
第六章 php目录与文件操作
2011/12/30 PHP
php短网址和数字之间相互转换的方法
2015/03/13 PHP
php post大量数据时发现数据丢失问题解决方法
2015/06/20 PHP
PHP使用pear自带的mail类库发邮件的方法
2015/07/08 PHP
javascript 面向对象的JavaScript类
2010/05/04 Javascript
JavaScript格式化数字的函数代码
2010/11/30 Javascript
jQuery页面图片伴随滚动条逐渐显示的小例子
2013/03/21 Javascript
可选择和输入的下拉列表框示例
2013/11/05 Javascript
前台js调用后台方法示例
2013/12/02 Javascript
js简单网速测试方法完整实例
2015/12/15 Javascript
AngularJS ng-mousedown 指令
2016/08/02 Javascript
Angular2 多级注入器详解及实例
2016/10/30 Javascript
JavaScript优化以及前段开发小技巧
2017/02/02 Javascript
nodejs更改项目端口号的方法
2018/05/13 NodeJs
详解vue移动端项目的适配(以mint-ui为例)
2018/08/17 Javascript
angularJs提交文本框数据到后台的方法
2018/10/08 Javascript
前端插件之Bootstrap Dual Listbox使用教程
2019/07/23 Javascript
javascript设计模式 ? 桥接模式原理与应用实例分析
2020/04/13 Javascript
python通过post提交数据的方法
2015/05/06 Python
python将ansible配置转为json格式实例代码
2017/05/15 Python
详解Pytorch 使用Pytorch拟合多项式(多项式回归)
2018/05/24 Python
基于python图书馆管理系统设计实例详解
2020/08/05 Python
PyCharm vs VSCode,作为python开发者,你更倾向哪种IDE呢?
2020/08/17 Python
Shopee马来西亚:随拍即卖,最佳行动电商拍卖平台
2017/06/05 全球购物
世界上最大的糖果店:Dylan’s Candy Bar
2017/11/07 全球购物
艺术应用与设计个人的自我评价
2013/11/23 职场文书
小学运动会表扬稿
2014/01/19 职场文书
关于环保的建议书
2014/05/12 职场文书
航班延误投诉信
2015/07/02 职场文书
2015年秋季运动会广播稿
2015/08/19 职场文书
2016高三毕业赠言寄语
2015/12/04 职场文书
2016关于预防职务犯罪的心得体会
2016/01/21 职场文书
Python+Appium自动化测试的实战
2021/06/30 Python
python文件与路径操作神器 pathlib
2022/04/01 Python