简体   繁体   English

即使在Windows上的backgroud中运行命令后,PHP脚本仍卡在exec上

[英]PHP script stuck on exec even after running command in backgroud on Windows

I want a php script from which I can execute a program, and terminate it if it doesn't complete execution in 2 seconds. 我想要一个可以执行程序的php脚本,如果它在2秒钟内未完成执行,则终止它。 I am using Windows. 我正在使用Windows。 I have tried the following code: 我尝试了以下代码:

exec("start /B program.exe");
sleep(2);
exec('taskkill /F /IM "program.exe"');

This doesn't seem to work as script is stuck on the first exec statement as long as program.exe is not finished execution. 只要未将program.exe执行完毕,脚本就停留在第一个exec语句上,这似乎不起作用。 I can't figure out how to do fix this issue. 我不知道如何解决此问题。

Right, exec() will block until execution completes. 是的, exec()将阻塞直到执行完成。 This question has great answers for how to do an exec() with a timeout. 这个问题对于如何使用超时exec()有很好的答案。 I think this will probably work best for you. 我认为可能最适合您。 I'll post the code here for completeness (but I can't take any credit!): 为了完整起见,我将代码发布在这里(但我不能功劳!):

/**
 * Execute a command and return it's output. Either wait until the command exits or the timeout has expired.
 *
 * @param string $cmd     Command to execute.
 * @param number $timeout Timeout in seconds.
 * @return string Output of the command.
 * @throws \Exception
 */
function exec_timeout($cmd, $timeout) {
  // File descriptors passed to the process.
  $descriptors = array(
    0 => array('pipe', 'r'),  // stdin
    1 => array('pipe', 'w'),  // stdout
    2 => array('pipe', 'w')   // stderr
  );

  // Start the process.
  $process = proc_open('exec ' . $cmd, $descriptors, $pipes);

  if (!is_resource($process)) {
    throw new \Exception('Could not execute process');
  }

  // Set the stdout stream to none-blocking.
  stream_set_blocking($pipes[1], 0);

  // Turn the timeout into microseconds.
  $timeout = $timeout * 1000000;

  // Output buffer.
  $buffer = '';

  // While we have time to wait.
  while ($timeout > 0) {
    $start = microtime(true);

    // Wait until we have output or the timer expired.
    $read  = array($pipes[1]);
    $other = array();
    stream_select($read, $other, $other, 0, $timeout);

    // Get the status of the process.
    // Do this before we read from the stream,
    // this way we can't lose the last bit of output if the process dies between these     functions.
    $status = proc_get_status($process);

    // Read the contents from the buffer.
    // This function will always return immediately as the stream is none-blocking.
    $buffer .= stream_get_contents($pipes[1]);

    if (!$status['running']) {
      // Break from this loop if the process exited before the timeout.
      break;
    }

    // Subtract the number of microseconds that we waited.
    $timeout -= (microtime(true) - $start) * 1000000;
  }

  // Check if there were any errors.
  $errors = stream_get_contents($pipes[2]);

  if (!empty($errors)) {
    throw new \Exception($errors);
  }

  // Kill the process in case the timeout expired and it's still running.
  // If the process already exited this won't do anything.
  proc_terminate($process, 9);

  // Close all streams.
  fclose($pipes[0]);
  fclose($pipes[1]);
  fclose($pipes[2]);

  proc_close($process);

  return $buffer;
}

Edit 编辑

The 'exec' part of the proc_open() probably won't work on Windows, but it's probably unnecessary. proc_open()的“ exec”部分可能无法在Windows上运行,但可能没有必要。

Are you doing this with php cli (command line) ? 您是否正在使用php cli(命令行)执行此操作? Open a command prompt as administrator . 以管理员身份打开命令提示符
To not being blocked by waiting for the program close the process of opening the program . 为了不被等待程序阻塞而关闭程序的打开过程

php myscript.php php myscript.php

pclose(popen("start /B program.exe", "r"));
sleep(2);
exec('taskkill /F /IM program.exe');
exit(0);

Would also be fine to put the exec start into a separate script and fire this script using exec exec开始放入一个单独的脚本并使用exec触发该脚本也可以

The first comment of the exec() manual page shows a very simple example. exec()手册页的第一条注释显示了一个非常简单的示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM