php file_get_contents抓取Gzip网页乱码的三种解决方法


Posted in PHP onNovember 12, 2013

把抓取到的内容转下编码即可($content=iconv("GBK", "UTF-8//IGNORE", $content);),我们这里讨论的是如何抓取开了Gzip的页面。怎么判断呢?获取的头部当中有Content-Encoding: gzip说明内容是GZIP压缩的。用FireBug看一下就知道页面开了gzip没有。下面是用firebug查看我的博客的头信息,Gzip是开了的。

请求头信息原始头信息
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Connection keep-alive
Cookie __utma=225240837.787252530.1317310581.1335406161.1335411401.1537; __utmz=225240837.1326850415.887.3.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=%E4%BB%BB%E4%BD%95%E9%A1%B9%E7%9B%AE%E9%83%BD%E4%B8%8D%E4%BC%9A%E9%82%A3%E4%B9%88%E7%AE%80%E5%8D%95%20site%3Awww.nowamagic.net; PHPSESSID=888mj4425p8s0m7s0frre3ovc7; __utmc=225240837; __utmb=225240837.1.10.1335411401
Host www.nowamagic.net
User-Agent Mozilla/5.0 (Windows NT 5.1; rv:12.0) Gecko/20100101 Firefox/12.0

下面介绍一些解决方案:

1. 使用自带的zlib库
如果服务器已经装了zlib库,用下面的代码可以轻易解决乱码问题。

$data = file_get_contents("compress.zlib://".$url);

2. 使用CURL代替file_get_contents

function curl_get($url, $gzip=false){
 $curl = curl_init($url);
 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
 curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
 if($gzip) curl_setopt($curl, CURLOPT_ENCODING, "gzip"); // 关键在这里
 $content = curl_exec($curl);
 curl_close($curl);
 return $content;
}

3. 使用gzip解压函数

function gzdecode($data) { 
  $len = strlen($data); 
  if ($len < 18 || strcmp(substr($data,0,2),"\x1f\x8b")) { 
    return null;  // Not GZIP format (See RFC 1952) 
  } 
  $method = ord(substr($data,2,1));  // Compression method 
  $flags  = ord(substr($data,3,1));  // Flags 
  if ($flags & 31 != $flags) { 
    // Reserved bits are set -- NOT ALLOWED by RFC 1952 
    return null; 
  } 
  // NOTE: $mtime may be negative (PHP integer limitations) 
  $mtime = unpack("V", substr($data,4,4)); 
  $mtime = $mtime[1]; 
  $xfl   = substr($data,8,1); 
  $os    = substr($data,8,1); 
  $headerlen = 10; 
  $extralen  = 0; 
  $extra     = ""; 
  if ($flags & 4) { 
    // 2-byte length prefixed EXTRA data in header 
    if ($len - $headerlen - 2 < 8) { 
      return false;    // Invalid format 
    } 
    $extralen = unpack("v",substr($data,8,2)); 
    $extralen = $extralen[1]; 
    if ($len - $headerlen - 2 - $extralen < 8) { 
      return false;    // Invalid format 
    } 
    $extra = substr($data,10,$extralen); 
    $headerlen += 2 + $extralen; 
  } 
  $filenamelen = 0; 
  $filename = ""; 
  if ($flags & 8) { 
    // C-style string file NAME data in header 
    if ($len - $headerlen - 1 < 8) { 
      return false;    // Invalid format 
    } 
    $filenamelen = strpos(substr($data,8+$extralen),chr(0)); 
    if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) { 
      return false;    // Invalid format 
    } 
    $filename = substr($data,$headerlen,$filenamelen); 
    $headerlen += $filenamelen + 1; 
  } 
  $commentlen = 0; 
  $comment = ""; 
  if ($flags & 16) { 
    // C-style string COMMENT data in header 
    if ($len - $headerlen - 1 < 8) { 
      return false;    // Invalid format 
    } 
    $commentlen = strpos(substr($data,8+$extralen+$filenamelen),chr(0)); 
    if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) { 
      return false;    // Invalid header format 
    } 
    $comment = substr($data,$headerlen,$commentlen); 
    $headerlen += $commentlen + 1; 
  } 
  $headercrc = ""; 
  if ($flags & 1) { 
    // 2-bytes (lowest order) of CRC32 on header present 
    if ($len - $headerlen - 2 < 8) { 
      return false;    // Invalid format 
    } 
    $calccrc = crc32(substr($data,0,$headerlen)) & 0xffff; 
    $headercrc = unpack("v", substr($data,$headerlen,2)); 
    $headercrc = $headercrc[1]; 
    if ($headercrc != $calccrc) { 
      return false;    // Bad header CRC 
    } 
    $headerlen += 2; 
  } 
  // GZIP FOOTER - These be negative due to PHP's limitations 
  $datacrc = unpack("V",substr($data,-8,4)); 
  $datacrc = $datacrc[1]; 
  $isize = unpack("V",substr($data,-4)); 
  $isize = $isize[1]; 
  // Perform the decompression: 
  $bodylen = $len-$headerlen-8; 
  if ($bodylen < 1) { 
    // This should never happen - IMPLEMENTATION BUG! 
    return null; 
  } 
  $body = substr($data,$headerlen,$bodylen); 
  $data = ""; 
  if ($bodylen > 0) { 
    switch ($method) { 
      case 8: 
        // Currently the only supported compression method: 
        $data = gzinflate($body); 
        break; 
      default: 
        // Unknown compression method 
        return false; 
    } 
  } else { 
    // I'm not sure if zero-byte body content is allowed. 
    // Allow it for now...  Do nothing... 
  } 
  // Verifiy decompressed size and CRC32: 
  // NOTE: This may fail with large data sizes depending on how 
  //       PHP's integer limitations affect strlen() since $isize 
  //       may be negative for large sizes. 
  if ($isize != strlen($data) || crc32($data) != $datacrc) { 
    // Bad format!  Length or CRC doesn't match! 
    return false; 
  } 
  return $data; 
}

使用:
$html=file_get_contents('https://3water.com/');
$html=gzdecode($html);

就介绍这三个方法,应该能解决大部分gzip引起的抓取乱码问题了。
PHP 相关文章推荐
改进的IP计数器
Oct 09 PHP
利用PHP实现与ASP Banner组件相似的类
Oct 09 PHP
第十节--抽象方法和抽象类
Nov 16 PHP
深入PHP数据加密详解
Jun 18 PHP
关于PHPDocument 代码注释规范的总结
Jun 25 PHP
php中autoload的用法总结
Nov 08 PHP
PHP中feof()函数实例测试
Aug 23 PHP
Codeigniter控制器controller继承问题实例分析
Jan 19 PHP
php 魔术常量详解及实例代码
Dec 04 PHP
cakephp2.X多表联合查询join及使用分页查询的方法
Feb 23 PHP
浅谈关于PHP解决图片无损压缩的问题
Sep 01 PHP
如何在Laravel5.8中正确地应用Repository设计模式
Nov 26 PHP
CodeIgniter使用phpcms模板引擎
Nov 12 #PHP
php用正则表达式匹配URL的简单方法
Nov 12 #PHP
CodeIgniter基本配置详细介绍
Nov 12 #PHP
PHP URL路由类实例
Nov 12 #PHP
PHP set_error_handler()函数使用详解(示例)
Nov 12 #PHP
php inc文件使用的风险和注意事项
Nov 12 #PHP
php防止SQL注入详解及防范
Nov 12 #PHP
You might like
php数组函数序列之array_sum() - 计算数组元素值之和
2011/10/29 PHP
ThinkPHP实现事务回滚示例代码
2014/06/23 PHP
Codeigniter的一些优秀特性总结
2015/01/21 PHP
PHP单例模式详细介绍
2015/07/01 PHP
tp5(thinkPHP5)框架实现多数据库查询的方法
2019/01/10 PHP
laravel 关联关系遍历数组的例子
2019/10/10 PHP
用js实现控制内容的向上向下滚动效果
2007/06/26 Javascript
一个刚完成的layout(拖动流畅,不受iframe影响)
2007/08/17 Javascript
event对象的方法 兼容多浏览器
2009/06/27 Javascript
淘宝搜索框效果实现分析
2011/03/05 Javascript
Jquery图形报表插件 jqplot简介及参数详解
2012/10/10 Javascript
jquery struts 验证唯一标识(公用方法)
2013/03/27 Javascript
JavaScript动态创建div属性和样式示例代码
2013/10/09 Javascript
javascript学习笔记(七)Ajax和Http状态码
2014/10/08 Javascript
jQuery实现购物车数字加减效果
2015/03/14 Javascript
XML、HTML、CSS与JS的区别整理
2016/02/18 Javascript
JavaScript中setter和getter方法介绍
2016/07/11 Javascript
js动态生成form 并用ajax方式提交的实现方法
2016/09/09 Javascript
JavaScript关联数组用法分析【概念、定义、遍历】
2017/03/15 Javascript
JS 调试中常见的报错问题解决方法
2017/05/20 Javascript
详解React 16 中的异常处理
2017/07/28 Javascript
原生js调用json方法总结
2018/02/22 Javascript
Vue 中的受控与非受控组件的实现
2018/12/17 Javascript
javascriptvoid(0)含义以及与&quot;#&quot;的区别讲解
2019/01/19 Javascript
使用vue-router在Vue页面之间传递数据的方法
2019/07/15 Javascript
python 字符串split的用法分享
2013/03/23 Python
初探利用Python进行图文识别(OCR)
2019/02/26 Python
用Python写一个模拟qq聊天小程序的代码实例
2019/03/06 Python
探究 canvas 绘图中撤销(undo)功能的实现方式详解
2018/05/17 HTML / CSS
毕业生求职自荐信怎么写
2014/01/08 职场文书
员工评语大全
2014/01/19 职场文书
村长反四风问题个人对照检查材料
2014/09/21 职场文书
合作合同协议书范本
2015/01/27 职场文书
2015年教师节主持词
2015/07/03 职场文书
七夕情人节问候语
2015/11/11 职场文书
《跨越海峡的生命桥》教学反思
2016/02/18 职场文书