Остановить выполнение внешней программы

KolyaA

Новичок
Любопытна возможность остановливать внешние программы, запущенные из php.

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

Пробовал proc_ open, но кажется это не то. Или не так пробовал.
 

tony2001

TeaM PHPClub
можно сделать stream_select() на рipes, которые возвращаются из proc_open(), и считать сколько времени ты его селектишь в сумме.
при превышении N секунд убивать процесс.
 

KolyaA

Новичок
А есть какая-нибудь ссылка, где кратко описывалась бы вся эта кухня - pipes и прочее?

А то я как в тёмный лес зашёл и наощупь продвигаюсь :)
 

KolyaA

Новичок
А как можно вот это сделать:

считать сколько времени ты его селектишь в сумме
?

Ведь таймаут, который задаётся в stream_select задаёт время ожидания до получения данных. И при начале получения данных, насколько я понял, stream_select сразу возвращает значение.
 

tony2001

TeaM PHPClub
$start = microtime(true);

..stream_select()..

$time_passed = microtime(true) - $start;
if ($time_passed > ... ) {
..всё пропало, мы все умрём..
}


как-то так.
 

KolyaA

Новичок
Так ведь если внешний скрипт зациклился, то это не поможет?

До $time_passed = microtime(true) - $start; дело ведь уже не дойдёт?
 

tony2001

TeaM PHPClub
если внешний процесс затупит, что stream_select() отвалится по таймауту.
 

KolyaA

Новичок
max_execution_time = 10

PHP:
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >  
  <title>Проверка прерывания процесса</title>  
</head>
<body>
  <?php 
    $pipes = array();
    $descriptorspec = array(
                             0 => array('pipe', 'r'),  // stdin is a pipe that the child will read from
                             1 => array('pipe', 'w'),  // stdout is a pipe that the child will write to
                             2 => array("file", "error.txt", "w")   // stderr is a pipe the child will write to
                           );
    
    $command = '"C:\www\proverka\Proverka3.exe"';
    
    $process = proc_open($command, $descriptorspec, $pipes);    

    $write  = array();
    $read   = array($pipes[0]);
    $except = null;
    
    $start = microtime(true);    
    stream_select($read, $write, $except, 10);
    $time_passed = microtime(true) - $start;
    
    print $time_passed;
    
    if ($time_passed > 10)
      die("Всё пропало");
  ?>
</body>
</html>
где Proverka3.exe программа, работающая ровно 20 секунд


На выводе пхп-скрипта получаем: 0.00012111663818359
И время работы пхп-скрипта ~ 20 секунд

:-((
 

tony2001

TeaM PHPClub
понятное дело, stream_select() надо в цикле делать.
у тебя он обнаружил данные в пайпе и сразу вернул.

и да, я предполагаю, что внешний процесс что-то выводит всё время.
иначе, конечно, это надо делать как-то по-другому.
 

KolyaA

Новичок
Что-то не врубаюсь насчёт цикла. Можешь код набросать, где там в цикле делать?
 

KolyaA

Новичок
Я, конечно, попробовал так:

PHP:
    $start = microtime(true);    
    
    while(1>0)
    {
      stream_select($read, $write, $except, 10);
    
      $time_passed = microtime(true) - $start;
    
      if ($time_passed > 10)
      {	  
        die("Конец");
      }
    }
Но сам понимаю, что это тупость. Ничего по таймауту тут не отвалится.....
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
KolyaA
по таймауту закончит ждать stream_select(), если внешняя программа ничего не записала в вывод за время до таймаута

int stream_select ( array &$read , array &$write , array &$except , int $tv_sec [, int $tv_usec = 0 ] )
The tv_sec and tv_usec together form the timeout parameter.
The timeout is an upper bound on the amount of time that stream_select() will wait before it returns.
что именно тебе непонятно?
 

KolyaA

Новичок
Описание функции понятно.

Непонятно, как организовать цикл.

Тем более зацикливание внешней программы может быть разное. Она, наоборот, может всё время что-то выводить.
 

KolyaA

Новичок
На перле оказывается есть библиотека где это всё просто делается. Поэтому можно сделать так:

PHP:
  <?php 
    exec("perl proverka.pl");
  ?>
proverka.pl:
PHP:
#!/usr/bin/perl

use Win32::Process;
$ProcessObj;                
$workdir = "C:\\www\\proverka";
$appname = "$workdir\\Proverka.exe";
$cmdline = "$workdir\\Proverka.exe";

Win32::Process::Create($ProcessObj, $appname, $cmdline, 0, DETACHED_PROCESS, $workdir);
   
$ProcessObj->Wait(10000);
$ProcessObj->Kill($exitcode);
 

KolyaA

Новичок
Странно...

Из командной строки "perl proverka.pl" нормально отрабатывает

Но когда запускаю в пхп exec("perl proverka.pl"), то перловский скрипт запускается, но запустить exe-шный файл уже не может
 

Ярослав

Новичок
Скорее всего, это потому, что процесс запускаеться из под www-data (или дефолтового юзера веб-сервера).
Тут проблему можна решить, дополнительно указав нужного юзера через sudo.
 
Сверху