PHP设置系统调用的脚本超时,set_time_limit不起作用

我有一个命令行PHP脚本,使用foreach的数组中的每个成员运行一个wget请求。 这个wget请求有时可能需要很长时间,所以我希望能够设置一个超时时间,例如,如果超过15秒,就会终止该脚本。 我禁用了PHP安全模式,并在脚本的早期尝试了set_time_limit(15),但它无限期地继续。 更新:感谢Dor指出这是因为set_time_limit()不尊重system()调用。

所以我试图在执行15秒后find其他杀死脚本的方法。 但是,我不确定是否有可能在同时处于wget请求中间的情况下检查脚本运行的时间(do while循环不起作用)。 也许用一个计时器分叉一个进程,并设置它在一段时间后杀死父进程?

感谢您的任何提示!

更新:下面是我的相关代码。 $ url是从命令行传递的,并且是一个包含多个URL的数组(抱歉,最初没有发布):

foreach( $url as $key => $value){ $wget = "wget -r -H -nd -l 999 $value"; system($wget); } 

Solutions Collecting From Web of "PHP设置系统调用的脚本超时,set_time_limit不起作用"

你可以使用“–timeout”和time()的组合。 首先确定你有多少时间,并且在脚本运行的时候降低超时时间。

例如:

 $endtime = time()+15; foreach( $url as $key => $value){ $timeleft = $endtime - time(); if($timeleft > 0) { $wget = "wget -t 1 --timeout $timeleft $otherwgetflags $value"; print "running $wget<br>"; system($wget); } else { print("timed out!"); exit(0); } } 

注意:如果你不使用-t,wget会尝试20次,每次等待 – 超时秒数。

下面是一些使用proc_open / proc_terminate的示例代码(@Josh的建议):

 $descriptorspec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w") ); $pipes = array(); $endtime = time()+15; foreach( $url as $key => $value){ $wget = "wget $otherwgetflags $value"; print "running $wget\n"; $process = proc_open($wget, $descriptorspec, $pipes); if (is_resource($process)) { do { $timeleft = $endtime - time(); $read = array($pipes[1]); stream_select($read, $write = NULL, $exeptions = NULL, $timeleft, NULL); if(!empty($read)) { $stdout = fread($pipes[1], 8192); print("wget said--$stdout--\n"); } } while(!feof($pipes[1]) && $timeleft > 0); if($timeleft <= 0) { print("timed out\n"); proc_terminate($process); exit(0); } } else { print("proc_open failed\n"); } } 

set_time_limit()之外,尝试使用wget命令行参数--timeout

请记住set_time_limit(15) 从零重新启动超时计数器,所以不要在一个循环内调用它(为了您的目的)

man wget

–timeout =秒

将网络超时设置为秒。 这相当于同时指定–dns-timeout,–connect-timeout和–read-timeout。

在与网络进行交互时,Wget可以检查超时并在需要太长时间的情况下中止操作。 这可以防止像挂读和无限连接的异常。 默认情况下启用的唯一超时是900秒的读取超时。 将超时设置为0将完全禁用它。 除非您知道自己在做什么,否则最好不要更改默认的超时设置。

所有与超时相关的选项都接受小数值,以及亚秒值。 例如,0.1秒是超时的合法(尽管是不明智的)选择。 亚秒超时对于检查服务器响应时间或测试网络延迟非常有用。

编辑:好的。 我明白你现在在做什么 你应该做的是使用proc_open而不是system ,并使用time()函数来检查时间,如果wget tskes太长,调用proc_terminate 。

您可以将wget程序的输出导向一个文件,然后立即返回。
另请参阅:

注意:set_time_limit()函数和配置指令max_execution_time仅影响脚本本身的执行时间。 在确定脚本运行的最长时间时,不包括使用system()系统调用,流操作,数据库查询等脚本执行之外发生的任何活动时间。 在测量时间是真实的Windows上,这是不正确的。

来源: set_time_limit() @ php.net