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.ini 中文版
Oct 28 PHP
php 常用字符串函数总结
Mar 15 PHP
php zip文件解压类代码
Dec 02 PHP
PHP程序员面试 切忌急功近利(更需要注重以后的发展)
Sep 01 PHP
php中spl_autoload详解
Oct 17 PHP
PHP+jQuery+Ajax实现分页效果 jPaginate插件的应用
Oct 09 PHP
学习php设计模式 php实现桥梁模式(bridge)
Dec 07 PHP
php fread读取文件注意事项
Sep 24 PHP
php中this关键字用法分析
Dec 07 PHP
PHP实现网站访问量计数器
Oct 27 PHP
Laravel程序架构设计思路之使用动作类
Jun 07 PHP
php 将json格式数据转换成数组的方法
Aug 21 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
WAMP环境中扩展oracle函数库(oci)
2015/06/26 PHP
PHP文件上传之多文件上传的实现思路
2016/01/27 PHP
PHP中OpenSSL加密问题整理
2017/12/14 PHP
实例讲解php将字符串输出到HTML
2019/01/27 PHP
在Laravel中使用MongoDB的方法示例
2019/11/11 PHP
JS控制显示隐藏兼容问题(IE6、IE7、IE8)
2010/04/01 Javascript
通过$(this)使用jQuery包装后的方法或属性
2014/05/18 Javascript
js拆分字符串并将分割的数据放到数组中的方法
2015/05/06 Javascript
nodejs学习笔记之路由
2017/03/27 NodeJs
ES6新特性之模块Module用法详解
2017/04/01 Javascript
在vue-cli搭建的项目中增加后台mock接口的方法
2018/04/26 Javascript
jQuery实现的电子时钟效果完整示例
2018/04/28 jQuery
详解es6超好用的语法糖Decorator
2018/08/01 Javascript
React+Webpack快速上手指南(小结)
2018/08/15 Javascript
基于nodejs的雪碧图制作工具的示例代码
2018/11/05 NodeJs
JavaScript eval()函数定义及使用方法详解
2020/07/07 Javascript
[01:56]2014DOTA2西雅图邀请赛 MVP外卡赛老队长精辟点评
2014/07/09 DOTA
[01:29]2017 DOTA2国际邀请赛官方英雄手办展示
2017/03/18 DOTA
[06:07]DOTA2-DPC中国联赛 正赛 Ehome vs VG 选手采访
2021/03/11 DOTA
Python translator使用实例
2008/09/06 Python
使用python解析xml成对应的html示例分享
2014/04/02 Python
基于python实现微信模板消息
2015/12/21 Python
python爬虫爬取某站上海租房图片
2018/02/04 Python
opencv python 2D直方图的示例代码
2018/07/20 Python
Django学习笔记之为Model添加Action
2019/04/30 Python
python中从for循环延申到推导式的具体使用
2019/11/29 Python
乌克兰在线商店的价格比较:Price.ua
2019/07/26 全球购物
小学二年级学生评语
2014/04/21 职场文书
委托书怎么写
2014/07/31 职场文书
2014年小学工作总结
2014/11/26 职场文书
教师个人考察材料
2014/12/16 职场文书
小学班主任工作总结2015
2015/04/07 职场文书
证券公司客户经理岗位职责
2015/04/09 职场文书
举起手来观后感
2015/06/09 职场文书
2019各种承诺书范文
2019/06/24 职场文书
Python机器学习三大件之一numpy
2021/05/10 Python