如何从Windows中的PHP函数exec()获取PID?

时间:2010-09-09 18:55:19

标签: php windows background exec background-process

我一直用:

$pid = exec("/usr/local/bin/php file.php $args > /dev/null & echo \$!");

但我正在使用XP虚拟机来开发一个Web应用程序,我不知道如何在Windows中获取pid。

我在cmd上尝试了这个:

C:\\wamp\\bin\\php\\php5.2.9-2\\php.exe "file.php args" > NUL & echo $!

它会执行文件,但输出为“$!”

如何将pid放入var $ pid? (使用php)

4 个答案:

答案 0 :(得分:9)

我正在使用Pstools,它允许您在后台创建一个进程并捕获它的pid:

// use psexec to start in background, pipe stderr to stdout to capture pid
exec("psexec -d $command 2>&1", $output);
// capture pid on the 6th line
preg_match('/ID (\d+)/', $output[5], $matches);
$pid = $matches[1];

有点hacky,但它完成了工作

答案 1 :(得分:1)

多亏了谷歌,我才来到这里,并根据 How to invoke/start a Process in PHP and kill it using Process ID...

决定这篇十年前的帖子需要更多信息

想象一下你想执行一个命令(这个例子使用 ffmpeg 将 windows 系统上的文件流式传输到 rtmp 服务器)。你可以这样命令:

ffmpeg -re -i D:\wicked_video.mkv -c:v libx264 -preset veryfast -b:v 200k -maxrate 400k -bufsize 6000k -pix_fmt yuv420p -g 50 -c:a aac -b:a 160k -ac 2 -ar 44100 -f flv rtmp://<IP_OF_RMTP_SERVER>/superawesomestreamkey > d:\demo.txt 2> d:\demoerr.txt

第一部分解释了 here,该命令的最后一部分输出到具有该名称的文件以用于记录目的:

> d:\demo.txt 2> d:\demoerr.txt

所以让我们假设该命令有效。你测试过了。 要使用 php 运行该命令,您可以使用 exec 执行它,但这需要时间(另一个主题,请检查 set_time_limit),它是由 ffmpeg 通过 php 处理的视频。不是要走的路,但在这种情况下正在发生。

您可以在后台运行该命令,但该进程的 pid 是多少? 由于某种原因,我们想杀死它,psexec 只提供用户运行的“进程 ID”。在这种情况下,只有一个用户。 我们希望同一用户有多个进程。

这是一个在 php 中获取已运行进程的 pid 的示例:

// the command could be anything:
// $cmd = 'whoami';

// This is a f* one, The point is: exec is nasty.
// $cmd = 'shutdown -r -t 0'; // 

// but this is the ffmpeg example that outputs seperate files for sake
$cmd = 'ffmpeg -re -i D:\wicked_video.mkv -c:v libx264 -preset veryfast -b:v 200k -maxrate 400k -bufsize 6000k -pix_fmt yuv420p -g 50 -c:a aac -b:a 160k -ac 2 -ar 44100 -f flv rtmp://10.237.1.8/show/streamkey1 > d:\demo.txt 2> d:\demoerr.txt';

// we assume the os is windows, pipe read and write
$descriptorspec = [  
    0 => ["pipe", "r"],  
    1 => ["pipe", "w"],  
];

// start task in background, when its a recource, you can get Parent process id
if ( $prog = is_resource( proc_open("start /b " . $cmd, $descriptorspec, $pipes ) ) )  
{  
    // Get Parent process Id  
    $ppid = proc_get_status($prog);  

    // this is the 'child' pid
    $pid = $ppid['pid'];

    // use wmic to get the PID
    $output = array_filter( explode(" ", shell_exec("wmic process get parentprocessid,processid | find \"$pid\"" ) ) );  
    array_pop($output);   
    
    // if pid exitst this will not be empty
    $pid = end($output);  

    // outputs the PID of the process 
    echo $pid;  
}  

上面的代码应该与 'inBackground' 运行的进程的 pid 相呼应。

请注意,如果它仍在运行,您需要保存pid以便稍后将其杀死。

现在你可以这样做来终止进程:(假设 pid 是 1234)

//'F' to Force kill a process  
exec("taskkill /pid 1234 /F"); 

这是我在 stackoverflow 上的第一篇文章, 我希望这会帮助某人。度过一个美好而不寂寞的圣诞节♪♪

答案 2 :(得分:0)

您必须安装extra extension,但找到位于Uniformserver's Wiki的解决方案。

<强>更新

经过一些搜索后,您可能会同时查看tasklist,您可以使用PHP exec命令来获取您所追求的内容。

答案 3 :(得分:0)

这是SeanDowney回答的“骇人听闻”版本。

PsExec返回生成的进程的PID作为其整数退出代码。因此,您所需要做的就是这个:

<?php

    function spawn($script)
    {
      @exec('psexec -accepteula -d php.exe ' . $script . ' 2>&1', $output, $pid);
      return $pid;
    } // spawn

    echo spawn('phpinfo.php');

?>

仅在第一次运行PsExec时才需要-accepteula参数,但是,如果要分发程序,则每个用户都将第一次运行它,并且对于每个人来说都保留它不会有任何损害随后执行。

PSTools是一种快速简便的安装程序(只需将PSTools解压缩到某个位置并将其文件夹添加到您的路径中),因此没有充分的理由不使用此方法。