Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Starting a Windows process in PHP and get it's PID?

Tags:

php

windows

I can't seem to get this working.

So I'm attempting to write a script for my game that connects to the server passing a few parameters for game name/type/players/etc. and the server script then sets up a new instance of the game server as it needs, runs the new instance of the server, finds which port it's running on, and sends all that info back to the game.

I've gotten up to the part where the script needs to execute the server game exe, and get it's PID (so I can get which port it's using, etc).

The server script is a PHP script, which is to execute the new instance of the server. (PHP seemed like a good choice, and is relatively in my knowledge).


The script must be able to finish executing, while keeping the game server running in the background.

Being able to run multiple game servers simultaneously is a necessity.


I've tried using proc_open but it gives the wrong PID of the process, which makes it useless. (though, it does execute the program right)

<?php

    $startDir = "C:/Torque/My Projects/Grim/game";
    $runExe = "$startDir/Grimwood.exe";
    $envars = " -dedicated -mission \"core/levels/Empty Terrain.mis\"";

    $runPath = $runExe . $envars;

    chdir($startDir);

    $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
    );

    $prog = proc_open($runPath, $descriptorspec, $pipes, $startDir, NULL);

    sleep(4);

    if (is_resource($prog)) 
    {
        $stats = proc_get_status($prog);
        $pid = $stats['pid'];

        $task = shell_exec("tasklist /fi \"PID eq $pid\"");

        echo("\nProcess: \n$task"); // echos cmd.exe, not process ran
    }

?>

The PID it prints belongs to the console window it's executing it from, and not the program it actually executed.


Next I tried using the MS script host WScript.Shell, and its exec/run methods.

<?php

    $startDir = "C:/Torque/My Projects/Grim/game";
    $runExe = "$startDir/Grimwood.exe";
    $envars = " -dedicated -mission \"core/levels/Empty Terrain.mis\"";

    $runPath = $runExe . $envars;

    chdir($startDir);    

    try
    {
        $WshShell = new COM("WScript.Shell");

        // gets right process ID
        // but process doesn't start properly with params
        $oExec = $WshShell->exec($runPath);
        echo("PID: " . $oExec->ProcessId);

        sleep(4);

        // executes properly
        // but doesn't return PID
        $oExec = $WshShell->run($runPath);
        echo("PID: " . $oExec->ProcessId);

    }
    catch (Exception $e)
    {
        // never gets hit
        echo("Failed to execute");
    }

?>

Running the exec command, it gives the right PID, but the program doesn't start properly (just shows a blank terminal window, doing nothing).

Running the run command, it start the program correctly (shows all the text it's supposed to in the terminal window), though, the command doesn't return the PID.


Any help on the matter would be greatly appreciated. I'm not sure what I'm doing wrong with the WScript.Shell->exec command for it to not be executing right, so all help on that matter would be appreciated.

If it's possible, I would like to use the proc_open method as it's a bit more cross-platform if we ever want to move any server stuff over to *nix.

Thanks for your time, I hope some bright mind can point me in the right direction.


PHP Version: 5.4.3

Dev Machine: Windows 7 Ultimate with SP1

Server Machine: Windows Server 2008 R2

like image 700
Steven Saric Avatar asked Nov 08 '12 13:11

Steven Saric


2 Answers

I managed to get it. I used proc_open to execute, which returns the PPID of the game server ran (the cmd.exe executable).

As start /b exit's the cmd.exe once it has executed the program, the only thing that should have that PPID is the game server, thus the rest of it to find the PID was relatively easy.

This also works when multiple instances are made at once, and when multiple instances are already running.

This is the end script to get the PID with proc_open, if anyone else wonders across this thread and may happen to need it:

<?php

    $startDir = "C:/Torque/My Projects/Grim/game";
    $runExe   = "$startDir/Grimwood.exe";
    $envars   = " -dedicated -mission \"core/levels/Empty Terrain.mis\"";

    $runPath = $runExe . $envars;

    chdir($startDir);

    $descriptorspec = array (
        0 => array("pipe", "r"),
        1 => array("pipe", "w"),
    );

    if ( is_resource( $prog = proc_open("start /b " . $runPath, $descriptorspec, $pipes, $startDir, NULL) ) )
    {
        $ppid = proc_get_status($prog)['pid'];
    }
    else
    {
        echo("Failed to execute!");
        exit();
    }

    $output = array_filter(explode(" ", shell_exec("wmic process get parentprocessid,processid | find \"$ppid\"")));
    array_pop($output);
    $pid = end($output);

    echo("\nProcess ID: $pid ; Parent's Process ID: $ppid\n");

    // returns right process
    $task = shell_exec("tasklist /fi \"PID eq $pid\"");
    echo("\n\nProcess: \n$task\n\n");

    // returns no process found
    $task = shell_exec("tasklist /fi \"PID eq $ppid\"");
    echo("\n\nParent Process: \n$task\n\n");

?>
like image 134
Steven Saric Avatar answered Nov 01 '22 15:11

Steven Saric


I believe you can get the results you want this way, since your developing for Windows OS.

First make your .exe to be run as a service. (I believe this is the syntax)

sc create SERVICENAME binpath=PATH_TO_EXE

Then I believe you can:

win32_start_service('SERVICENAME');

sleep(4);

$serviceStatus = win32_query_Service_status('SERVICENAME');
var_dump($serviceStatus);

// or
echo $serviceStatus[ProcessId];

PS - Please take in consideration that I didn't test this. but i believe that this will work. give it a try.

Meanwhile visit this link http://www.php.net/manual/en/book.win32service.php for more info on Windows Services.

like image 1
njasm Avatar answered Nov 01 '22 14:11

njasm