Both set_time_limit(...) and ini_set('max_execution_time',...); won't count the time cost of sleep,file_get_contents,shell_exec,mysql_query etc, so i build this function my_background_exec(), to run static method/function in background/detached process and time is out kill it:
my_exec.php:
<?php
function my_background_exec($function_name, $params, $str_requires, $timeout=600)
{$map=array('"'=>'\"', '$'=>'\$', '`'=>'\`', '\\'=>'\\\\', '!'=>'\!');
$str_requires=strtr($str_requires, $map);
$path_run=dirname($_SERVER['SCRIPT_FILENAME']);
$my_target_exec="/usr/bin/php -r \"chdir('{$path_run}');{$str_requires} \\\$params=json_decode(file_get_contents('php://stdin'),true);call_user_func_array('{$function_name}', \\\$params);\"";
$my_target_exec=strtr(strtr($my_target_exec, $map), $map);
$my_background_exec="(/usr/bin/php -r \"chdir('{$path_run}');{$str_requires} my_timeout_exec(\\\"{$my_target_exec}\\\", file_get_contents('php://stdin'), {$timeout});\" <&3 &) 3<&0";my_timeout_exec($my_background_exec, json_encode($params), 2);
}
function my_timeout_exec($cmd, $stdin='', $timeout)
{$start=time();
$stdout='';
$stderr='';
$process=proc_open($cmd, [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $pipes);
if (!is_resource($process))
{return array('return'=>'1', 'stdout'=>$stdout, 'stderr'=>$stderr);
}
$status=proc_get_status($process);
posix_setpgid($status['pid'], $status['pid']); stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
fwrite($pipes[0], $stdin);
fclose($pipes[0]);
while (1)
{$stdout.=stream_get_contents($pipes[1]);
$stderr.=stream_get_contents($pipes[2]);
if (time()-$start>$timeout)
{posix_kill(-$status['pid'], 9); return array('return'=>'1', 'stdout'=>$stdout, 'stderr'=>$stderr);
}
$status=proc_get_status($process);
if (!$status['running'])
{fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
return $status['exitcode'];
}
usleep(100000);
}
}
?>
a_class.php:
<?php
class A
{
static function jack($a, $b)
{sleep(4);
file_put_contents('debug.txt', time().":A::jack:".$a.' '.$b."\n", FILE_APPEND);
sleep(15);
}
}
?>
test.php:
<?php
require 'my_exec.php';
my_background_exec('A::jack', array('hello', 'jack'), 'require "my_exec.php";require "a_class.php";', 8);
?>