【问题标题】:PHP Execute shell command asynchronously and retrieve live outputPHP异步执行shell命令并检索实时输出
【发布时间】:2017-02-14 10:45:59
【问题描述】:

我想在 PHP 中异步执行一个 shell 命令。 IE。 PHP 不应等待命令完成才能继续执行。然而,与 Stackoverflow 上关于该主题的众多问题相比,我确实关心程序的输出。特别是我想做这样的事情:

exec("some command", $output_array, $has_finished);
while(count($output_array) > 0 && !$has_finished)
{
    if(count($output_array) > 0)
    {
        $line = array_shift($output_array);
        do_something_with_that($line);
    } else
        sleep(1);
}

do_something_with_that($line)
{
    echo $line."\n";
    flush();
}

如果exec 会立即返回,同时仍在向数组添加元素,并且如果有方法可以检查进程是否已终止,则上述代码将起作用。

有没有办法做到这一点?

【问题讨论】:

  • 您可以生成一个执行此操作的线程并检查该线程的状态。可能有很多资源可以检查。但是你不能用原生 PHP 做到这一点,需要一个模块或库。
  • @apokryfos proc_open 是一个非常原生的 PHP 函数。 Libs 只是让使用它更方便。

标签: php exec


【解决方案1】:

我通过将输出 STDIN 传送到一个临时文件然后从中读取来解决了这个问题。

这是我的

实施

class ExecAsync {

    public function __construct($cmd) {
        $this->cmd = $cmd;
        $this->cacheFile = ".cache-pipe-".uniqid();
        $this->lineNumber = 0;
    }

    public function getLine() {
        $file = new SplFileObject($this->cacheFile);
        $file->seek($this->lineNumber);
        if($file->valid())
        {
            $this->lineNumber++;
            $current = $file->current();
            return $current;
        } else
            return NULL;
    }

    public function hasFinished() {
        if(file_exists(".status-".$this->cacheFile) ||
            (!file_exists(".status-".$this->cacheFile) && !file_exists($this->cacheFile)))
        {
            unlink($this->cacheFile);
            unlink(".status-".$this->cacheFile);
            $this->lineNumber = 0;
            return TRUE;
        } else
            return FALSE;
    }

    public function run() {
        if($this->cmd) {
            $out = exec('{ '.$this->cmd." > ".$this->cacheFile." && echo finished > .status-".$this->cacheFile.";} > /dev/null 2>/dev/null &");
        }
    }
}

用法

$command = new ExecAsync("command to execute");
//run the command
$command->run();
/*We want to read from the command output as long as
 *there are still lines left to read
 *and the command hasn't finished yet

 *if getLine returns NULL it means that we have caught up
 *and there are no more lines left to read
 */
while(($line = $command->getLine()) || !$command->hasFinished())
{
    if($line !== NULL)
    {
        echo $line."\n";
        flush();
    } else
    {
        usleep(10);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-29
    • 2014-06-24
    • 2021-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-24
    • 2017-12-26
    相关资源
    最近更新 更多