PHP установил тайм-аут для скрипта с системным вызовом, set_time_limit не работает - PullRequest
3 голосов
/ 09 апреля 2010

У меня есть PHP-скрипт командной строки, который выполняет запрос wget, используя каждый элемент массива с foreach. Этот запрос wget может иногда занимать много времени, поэтому я хочу установить тайм-аут для уничтожения сценария, например, если он длится более 15 секунд. У меня отключен безопасный режим PHP и я пытался установить set_time_limit (15) в начале скрипта, однако он продолжается бесконечно. Обновление: Спасибо Дор за то, что указал на это, потому что set_time_limit () не учитывает системные вызовы ().

Поэтому я пытался найти другие способы убить скрипт после 15 секунд выполнения. Однако я не уверен, можно ли проверить время выполнения скрипта, когда он находится в середине запроса wget одновременно (цикл do while не работает). Может быть, форк процесс с таймером и установить его, чтобы убить родителя через установленное количество времени?

Спасибо за любые советы!

Обновление: Ниже мой соответствующий код. $ url передается из командной строки и представляет собой массив из нескольких URL-адресов (извините, что не опубликовал это изначально):

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

Ответы [ 4 ]

6 голосов
/ 09 апреля 2010

Попробуйте использовать аргумент командной строки wget --timeout в дополнение к set_time_limit().

Имейте в виду, set_time_limit(15) перезапускает счетчик таймаута с нуля , поэтому не вызывайте его внутри цикла (для вашей цели)

из man wget:

- время ожидания = секунды

Установить сеть таймаут до секунд, секунд. Это эквивалентно указанию --dns-timeout, --connect-timeout и --read-timeout, все одновременно.

При взаимодействии с сетью Wget может проверить время ожидания и прервать операция, если она занимает слишком много времени. Это предотвращает аномалии, такие как зависание читает и бесконечно соединяется. Единственный тайм-аут включен по умолчанию Тайм-аут чтения 900 секунд. Настройка тайм-аут до 0 отключает его вообще. Если вы не знаете, что делаете, это лучше не менять по умолчанию настройки тайм-аута.

Все опции, связанные с тайм-аутом, принимают десятичные значения, а также подсекунды ценности. Например, 0,1 секунды законный (хотя и неразумный) выбор тайм-аут. Подсекундные тайм-ауты полезно для проверки ответа сервера раз или для тестирования задержки сети.

РЕДАКТИРОВАТЬ: ОК. Я вижу, что ты сейчас делаешь. Вероятно, вам следует использовать proc_open вместо system и использовать функцию time() для проверки времени, вызывая proc_terminate , если wget слишком длинный.

4 голосов
/ 09 апреля 2010

Вы можете использовать комбинацию «--timeout» и time (). Для начала выясните, сколько у вас есть общего времени, и уменьшите --timeout во время выполнения вашего скрипта.

Например:

$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 раз, каждое ожидание - timeout секунд.

Вот пример кода, использующего proc_open / proc_terminate (предложение @ Джоша):

$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");
  }
}
4 голосов
/ 09 апреля 2010

Вы можете направить вывод программы wget в файл, который затем немедленно возвращается.
Также см .:

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

Источник: set_time_limit () @ php.net

0 голосов
/ 25 марта 2018

Я думаю, что лучший способ - справиться с уничтожением самой командой, по крайней мере, в Linux (Ubuntu 17.10). Никакие другие средства не сработали для меня ... proc_terminate из другого ответа не сработало, но вывод не дал бы.

В приведенном ниже примере я добавляю волшебную строку, которая проверяет, работает ли еще ваш процесс. Если он работает дольше, чем $sec, он немедленно завершает процесс, оставляя сообщение «Timeout!».

Таким образом, я уверен, что команда не превысит время ожидания, и я получу все необходимые stdout / stderr.

$wget = "wget -r -H -nd -l 999 $value"; // your command

$sec = 5; // timeout in seconds
$cmd = $wget . " & ii=0 && while [ \"2\" -eq \"`ps -p $! | wc -l \" ]; do ii=$((ii+1)); if [ \$ii -gt ".($sec)."0 ]; then echo 'Timeout!';kill $!; break;fi; sleep 0.1; done"
system($cmd); // system call
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...