最近我的一位同事在做数据抓取,需要从别人的网站上下载图片到本地。
图片链接是从远程服务器的数据库中读取出来的,他用的办法是每次从远程数据库中读取一定的记录,
然后使用双重循环下载图片。可以代码在执行的时候遇到了问题,就是有些链接是无效的,会发生连接超时
(图片下载方法是内置readfile函数)。本来超时了也没什么大不了,顶多是图片没下载下来。但是结果却是:
如果有一个链接发生超时,那么整个程序就会跑飞了,很是奇怪。我仔细看了一下代码,找到了问题所在:
readfile函数默认超时时间大约在1分钟左右,因为这段时间mysql连接一直没有活动,所以连接被中断了,而他
又没有重新连接,所以mysql_query的时候会报错。
既然知道原因了问题就很好解决了,从两个方面下手:
1、将readfile函数的超时时间设置短一些
2、mysql_query之前判断是否存在连接,没有就重新连接
第二个好办,使用mysql_ping()就可以了(需要提醒大家的是:如果连接远程数据库,最好要有连接失败重试,因为
一次mysql_connect()不能保证100%的连接成功率,可以使用do,while在一次连接失败后多连几次)。
第一个有点棘手,readfile函数中好像没有超时设置。如果把下载文件的方法改成fsockopen方式下载,这个函数是支持超时
设置的,只是这样有点麻烦。还是去网上看看吧,结果还真的找到了,原来readfile也是支持超时设置的,使用第三个参数
$context。这是一个资源类型的变量。
直接看代码示例吧:
这样readfile函数的超时时间就设置成了10秒,如果你够细心的话,还会发现数组中还有一些其他的配置,
第一维中的http是指定使用的网络协议,二维中的method批的是http的请求方法get,post,head等,timeout就是
超时时间了。我想很多人会使用php内置的file_get_contents函数来下载网页,因为这个函数使用起来够简单。
很多人也都很简单的使用它,只要传递一个链接它就可以自动的发送get请求,并将网页内容下载下来。
如果比较复杂的情况,比如使用POST请求,使用代理下载,定义User-Agent等等,这时很多人就会认为这个
函数做不了这样的事情,就会选择其他方式,如curl,来实现。实际上,这些事情file_get_contents也可以做到,
就是通过它的第三个参数,设置http请求的context。
支持的设置和使用方式见官方说明:http://www.php.net/manual/en/context.http.php
附:目前我知道的支持context参数的php内置函数有file_get_contents,file_put_contents,readfile,file,fopen,copy(估计这一类的函数都支持吧,待确认)。