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 相关文章推荐
判“新”函数:得到今天与明天的秒数
Oct 09 PHP
mysql5的sql文件导入到mysql4的方法
Oct 19 PHP
PHP 命名空间实例说明
Jan 27 PHP
从康盛产品(discuz)提取出来的模板类
Jun 28 PHP
使用php验证复选框有效性的示例
Nov 13 PHP
PHP的MVC模式实现原理分析(一相简单的MVC框架范例)
Apr 29 PHP
PHP面向对象程序设计之类常量用法实例
Aug 20 PHP
PHP数组和explode函数示例总结
May 08 PHP
Symfony模板的快捷变量用法实例
Mar 17 PHP
thinkPHP框架对接支付宝即时到账接口回调操作示例
Nov 14 PHP
PHP 实现人民币小写转换成大写的方法及大小写转换函数
Nov 17 PHP
laravel 解决crontab不执行的问题
Oct 22 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
PHP仿博客园 个人博客(1) 数据库与界面设计
2013/07/05 PHP
php强制更新图片缓存的方法
2015/02/11 PHP
浅析iis7.5安装配置php环境
2015/05/10 PHP
php插件Xajax使用方法详解
2017/08/31 PHP
javascript 限制输入和粘贴(IE,firefox测试通过)
2008/11/14 Javascript
JavaScript 继承详解(二)
2009/07/13 Javascript
Fastest way to build an HTML string(拼装html字符串的最快方法)
2011/08/20 Javascript
JS声明变量背后的编译原理剖析
2012/12/28 Javascript
IE网页js语法错误2行字符1、FF中正常的解决方法
2013/09/09 Javascript
Node.js环境下编写爬虫爬取维基百科内容的实例分享
2016/06/12 Javascript
jQuery图片渐变特效的简单实现
2016/06/25 Javascript
jQuery+ajax实现实用的点赞插件代码
2016/07/06 Javascript
浅析Javascript ES6中的原生Promise
2016/08/25 Javascript
BootStrap中Table隐藏后显示问题的实现代码
2017/08/31 Javascript
前端常见跨域解决方案(全)
2017/09/19 Javascript
浅谈Vue-cli 命令行工具分析
2017/11/22 Javascript
Angular利用内容投射向组件输入ngForOf模板的方法
2018/03/05 Javascript
vue awesome swiper异步加载数据出现的bug问题
2018/07/03 Javascript
vue解决使用webpack打包后keep-alive不生效的方法
2018/09/01 Javascript
详解vue-cli3 中跨域解决方案
2019/04/10 Javascript
微信小程序拼接图片链接无底洞深入探究
2019/09/03 Javascript
Vue实现将数据库中带html标签的内容输出(原始HTML(Raw HTML))
2019/10/28 Javascript
Javascript执行上下文顺序的深入讲解
2020/11/04 Javascript
vue 递归组件的简单使用示例
2021/01/14 Vue.js
[01:54]TI珍贵瞬间系列(三):翻盘
2020/08/28 DOTA
在Apache服务器上同时运行多个Django程序的方法
2015/07/22 Python
Python Matplotlib库安装与基本作图示例
2019/01/09 Python
Python中的元组介绍
2019/01/28 Python
在django admin详情表单显示中添加自定义控件的实现
2020/03/11 Python
Python接口自动化测试的实现
2020/08/28 Python
HTML5 form标签之解放表单验证、增加文件上传、集成拖放的使用方法
2013/04/24 HTML / CSS
加拿大女包品牌:Matt & Nat
2017/05/12 全球购物
《三顾茅庐》教学反思
2014/04/10 职场文书
中学生英语演讲稿
2014/04/26 职场文书
基层干部个人对照检查及整改措施
2014/10/28 职场文书
你喜欢篮球吗?Python实现篮球游戏
2021/06/11 Python