经常会使用php中的file_get_contents()函数去抓取远程页面, 对方页面文件过大、对方页面反应时间太久或网络传输慢等原因都可能会导致file_get_contents()执行时间超过php的最大执行时间。而一 旦file_get_contents出错即会终止整个程序。
测试用例
1
2
3
4
5
6
7
8
|
<?php ini_set ( "max_execution_time" , 2); $url = "http://aymoo.cn/files/jQuery1.2API.chm" ; $html = file_get_contents ( $url ); var_dump( $html ); ?> |
上面代码首先将php的最大执行时间设置为2秒,然后去远程读取170KB的文件,按照本人的网络环境下载170KB文件需时超过1s.
现象
Fatal error: Maximum execution time of 2 second exceeded in C:\wamp\www\phptest\timeout.php on line 4
这是由网络造成的php执行超时,在file_get_contents超时时即报错并且程序停止执行。而基本上大多数需求是即使发生错误也要求程序继续向下执行。
解决办法
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?php ini_set ( "max_execution_time" , 2); $url = "http://aymoo.cn/files/jQuery1.2API.chm" ; //$html = file_get_contents($url); $ch = curl_init( $url ); curl_setopt( $ch , CURLOPT_TIMEOUT, 1); curl_setopt( $ch , CURLOPT_RETURNTRANSFER, 1); $html = curl_exec( $ch ); curl_close ( $ch ); var_dump( $html ); ?> |
现象
bool(false)
成功解决了超时导致程序不能继续执行的问题。
这里需要注意的是,设置curl的CURLOPT_TIMEOUT的值应该小于php最大执行时间。
为什么要说应该而不是必须?用两个例子对比来说明,假设抓取页面需4s。
example 1
max_execution_time 为 2
CURLOPT_TIMEOUT 为 3
example 2
max_execution_time 为 10
CURLOPT_TIMEOUT 为 20
我对这个过程的理解是,php监控整个脚本的时间,curl监控抓取页面的时间。对例1, 抓取远程页面的过程中已经达到php最大执行时间,得到的结果和file_get_contents一样。
例2中,整个脚本的执行时间不到5s, 所以不受设定时间的限制.
-------------------------------------------
一、增加超时的时间限制
这里需要注意:set_time_limit只是设置你的PHP程序的超时时间,而不是file_get_contents函数读取URL的超时时间。
我一开始以为set_time_limit也能影响到file_get_contents,后来经测试,是无效的。真正的修改file_get_contents延时可以用resource $context的timeout参数:
复制代码 代码如下:
$opts = array(
‘http'=>array(
‘method'=>”GET”,
‘timeout'=>60,
)
);
$context = stream_context_create($opts);
$html =file_get_contents('http://www.example.com', false, $context);
fpassthru($fp);
二、一次有延时的话那就多试几次
有时候失败是因为网络等因素造成,没有解决办法,但是可以修改程序,失败时重试几次,仍然失败就放弃,因为file_get_contents()如果失败将返回 FALSE,所以可以下面这样编写代码:
复制代码 代码如下:
$cnt=0;
while($cnt < 3 && ($str=@file_get_contents('http…'))===FALSE) $cnt++;