【问题标题】:How to get PID from PHP function exec() in Windows?如何从 Windows 中的 PHP 函数 exec() 获取 PID?
【发布时间】:2010-09-09 18:55:18
【问题描述】:

我一直用:

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

但我正在使用 XP 虚拟机开发网络应用程序,但我不知道如何在 windows 中获取 pid。

我在 cmd 上试过这个:

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

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

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

【问题讨论】:

  • 我投票决定将该问题移至 serverfault.com,因为基本上它可以折叠为“如何在 Windows 命令行上获取进程 ID”。也许 superuser.com 更适合?

标签: php windows background exec background-process


【解决方案1】:

我正在使用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,但它可以完成工作

【讨论】:

  • 这对我有用,但是由于某种原因弹出了一个额外的控制台窗口
【解决方案2】:

多亏了谷歌,我才来到这里,并决定这个十年前的帖子需要更多基于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 以便稍后将其杀死。

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

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

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

【讨论】:

  • 这是一个非常好的解决方法,但它确实有效。谢谢你。不过,检查 is_resource 应该与分配 $prog 分开。
  • 是的,通过 cmets 阅读,嘿嘿。我后来注意到了。现在我用 NodeJS 做这件事。很高兴这对您有所帮助!
【解决方案3】:

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

更新

经过一番搜索,您可能会查看tasklist,巧合的是,您可以使用 PHP exec 命令来获得您想要的东西。

【讨论】:

  • 谢谢,无论如何我想我会在 linux 虚拟机上设置一个服务器,我只是不喜欢在我的主操作系统上安装一个网络服务器,而我唯一的一个是 win。
  • 已更新,找到了一个内置于 xp 中的程序,名为tasklist,它可以为所欲为。
【解决方案4】:

这是 SeanDowney 答案的一个稍微不那么“hacky”的版本。

PsExec 返回生成进程的 PID 作为其整数退出代码。所以你只需要这样:

<?php

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

    echo spawn('phpinfo.php');

?>

-accepteula 参数仅在您第一次运行 PsExec 时才需要,但如果您正在分发您的程序,每个用户都会第一次运行它,并且每次都保留它并没有什么坏处后续执行。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 2012-12-31
    • 2020-05-10
    • 2018-01-05
    • 2012-11-20
    • 1970-01-01
    相关资源
    最近更新 更多