PHP: set_time_limit (), кажется, не имеет никакого эффекта - PullRequest
6 голосов
/ 30 марта 2011

Я пытаюсь использовать PHP set_time_limit () в обычном PHP-скрипте apache (не CLI), чтобы ограничить его максимальное время выполнения.Он ничего не делает с системными вызовами или чем-то подобным, мы не используем безопасный режим (мы владельцы, а не администраторы сервера).Это PHP 5.2.4 в Linux (Ubuntu).

Простой тестовый пример:

ini_set('max_execution_time', 1);
set_time_limit(1);
$i=0;
while ($i++<100000000000) {} // or anything other arbitrary that takes time
die('Done');

Ожидаемый результат : что-то, связанное с превышением времени выполнения скрипта

Фактический результат : Готово печатается.

Я делаю что-то явно не так? (Кстати, да, сценарий действительно должен и может работать слишком долго и должен быть прерван, к сожалению, этого нельзя избежать. Здесь дело не в этом.)

Ответы [ 6 ]

3 голосов
/ 30 марта 2011

Цитирование из руководства:

Примечание:

Функция set_time_limit () и директива конфигурации max_execution_time влияют только на время выполнения самого скрипта,Любое время, потраченное на действия, которые происходят вне выполнения сценария, такие как системные вызовы с использованием system (), потоковые операции, запросы к базе данных и т. Д., Не учитывается при определении максимального времени выполнения сценария.Это не так в Windows, где измеренное время является действительным.

sleep () относится к числу тех функций, которые не влияют на время выполнения скрипта

см. Комментарий MPHH кСтраница sleep () руководства

Примечание. Функция set_time_limit () и директива конфигурации max_execution_time влияют только на время выполнения самого скрипта.Любое время, затрачиваемое на действия, происходящие вне выполнения сценария, такие как системные вызовы с использованием system (), функции sleep (), запросов к базе данных и т. Д., Не учитывается при определении максимального времени выполнения сценария.

1 голос
/ 20 мая 2014

И max_execution_time (...), и ini_set ('max_execution_time', ...) не будут учитывать стоимость времени sleep (), file_get_contents (), shell_exec (), mysql_query () и т. Д., Поэтому я собираю Следующая функция my_background_exec () запускает статический метод для фонового / отдельного процесса и, когда время истекает, автоматически уничтожает его:

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";//php by default use "sh", and "sh" don't support "<&0"
          my_timeout_exec($my_background_exec, json_encode($params), 2);
         }

function my_timeout_exec($cmd, $stdin='', $timeout)
         {$start=time();
          $stdout='';
          $stderr='';
          //file_put_contents('debug.txt', time().':cmd:'.$cmd."\n", FILE_APPEND);
          //file_put_contents('debug.txt', time().':stdin:'.$stdin."\n", FILE_APPEND);

          $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']);    //seperate pgid(process group id) from parent's pgid

          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)
                    {//proc_terminate($process, 9);    //only terminate subprocess, won't terminate sub-subprocess
                     posix_kill(-$status['pid'], 9);    //sends SIGKILL to all processes inside group(negative means GPID, all subprocesses share the top process group, except nested my_timeout_exec)
                     //file_put_contents('debug.txt', time().":kill group {$status['pid']}\n", FILE_APPEND);
                     return array('return'=>'1', 'stdout'=>$stdout, 'stderr'=>$stderr);
                    }

                 $status=proc_get_status($process);
                 //file_put_contents('debug.txt', time().':status:'.var_export($status, true)."\n";
                 if (!$status['running'])
                    {fclose($pipes[1]);
                     fclose($pipes[2]);
                     proc_close($process);
                     return $status['exitcode'];
                    }

                 usleep(100000); 
                }
         }
?>

test.php:

<?php
my_background_exec('A::jack', array('hello ', 'jack'), 'require "my_exec.php";require "a_class.php";', 8);
?>

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);
           }
}
?>
1 голос
/ 30 марта 2011

Попробуйте, чтобы ваш скрипт действительно что-то сделал, время сна не учитывается во время выполнения, поскольку, пока скрипт спит, он не выполняется.

РЕДАКТИРОВАТЬ: Проверить этот отчет об ошибках http://bugs.php.net/37306 Последний комментарий заключается в том, что это было исправлено в "CVS HEAD, PHP_5_2 и PHP_5_1".так что, возможно, ваша версия PHP имеет эту ошибку.Может быть, вы можете попробовать изменить max_input_time.

1 голос
/ 30 марта 2011

Это связано с тем, что функция sleep игнорируется ограничением по времени, она прекращает отсчет времени, когда активирован режим сна, и начинает подсчет снова, когда он деактивирован.

1 голос
/ 30 марта 2011

В некоторых системах ini_set и аналогичные функции отключены по соображениям безопасности и совместного использования ресурсов. Обратитесь к администратору, чтобы узнать, существуют ли такие ограничения.

0 голосов
/ 30 марта 2011

Проверьте, работает ли ваш ini_set, проверив флаг disable_functions в php.ini. Если он не отключен, выведите phpinfo () сразу после вашего ini_set ('max_execution_time', 1); выше. Если значение изменяется под локальным столбцом, то вы знаете, что ini_set работает. В противном случае ваш сценарий не установил максимальное время выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...