PHP CLI: Process Running

 

MPG UniCenter

UniServer 5.0-Nano
PHP CLI.

PHP CLI Check if a process (program) is running

One the previous page I covered installing extension php_win32ps.dll which allows you to list statics for all currently running processes. This page covers using the extension to check if a process is running strictly speaking this extension is not required. UniSerer already includes a small utility that performs a similar function it has the extra capability of killing a named process. For completeness both are covered allowing you to select the most suitable for your application.

General note: Always consider alternatives however never be temped to use something that is OS version specific! A particular utility may not be included across the whole family range (XP,Vista etc) or may be renamed between OS versions. Always go for the lowest common denominator otherwise your scripts will be killed when run on another machine that is not running a compatible OS version.

Initial test setup

Note: It really is a shame; still unable to find a version of php_win32ps.dll that is compatible with PHP 5.3.0 hence for these examples I am assuming you are running one of the UniServer Mona series. At UniServer pskill.exe and the reset of this tutorial will switch back to using Uniform Server 5.0-Nano.

Edit our two test files Run.bat and test_1.php contained in folder UniServer to have the following content:

Run.bat test_1.php;
TITLE CLI TEST BAT
COLOR B0
@echo off
cls
echo.
udrive\usr\local\php\php.exe test_1.php
echo.
pause
<?php
  print_r(win32_ps_list_procs());
  echo "Hello World";
exit(0); // Script ran OK
?>

Note: Above assumes you have installed the extension php_win32ps.dll as described on the previous page.

Top

Extension php_win32ps.dll

Run the batch file (double click on Run.bat), all current running processes are displayed along with some useful statistics.

Reduce output

Running the above example produces an overwhelming amount of data lets reduce this by displaying only pids and executable path-names, edit test_1.php as follows:

<?php
//print_r(win32_ps_list_procs());

@$processList = win32_ps_list_procs();
foreach ($processList as $processArray)
{
$pid = $processArray['pid'];
$exe = $processArray['exe'];
echo "$pid   $exe \n";
}
//echo "Hello World";
exit(0); // Script ran OK
?>

This produces a list of all running processes similar to this small extract:

3240   C:\Program Files\Mozilla Firefox\firefox.exe
3660   C:\WINDOWS\System32\svchost.exe
3796   F:\uc_media_wiki\Uniform Server\unicon.exe
3640   Z:\usr\local\apache2\bin\Apache.exe
3900   Z:\usr\local\mysql\bin\mysqld-opt.exe
1396   Z:\usr\local\apache2\bin\Apache.exe
2788   C:\Program Files\JGsoft\EditPadLite\EditPadLite.exe
3484   C:\WINDOWS\system32\cmd.exe
2988   C:\WINDOWS\system32\cmd.exe
2916   H:\z_test_42\UniServer\udrive\usr\local\php\php.exe
…… etc

Top

Check a process is running

This script shows how to target a process by name (example targets cmd.exe) and check if it is currently running, change test_1.php as follows:

<?php
$processName = 'cmd.exe';
@$processList = win32_ps_list_procs();
foreach ($processList as $processArray){
  $pid = $processArray['pid'];
  $exe = $processArray['exe'];
  if (basename($processArray['exe']) == $processName){
     echo "\n Process $processName is running\n";
     echo "$pid   $exe \n";
     break;
  }
}
exit(0); // Script ran OK
?>

Run the batch file (double click on Run.bat) output will be similar to this:

 Process cmd.exe is running
1896   C:\WINDOWS\system32\cmd.exe

The above can be converted into a function for general purpose however there is a small problem.

Top

Problem

I purposefully masked an issue with the above script. Comment out the break line as shown.

<?php
$processName = 'cmd.exe';
@$processList = win32_ps_list_procs();
foreach ($processList as $processArray){
  $pid = $processArray['pid'];
  $exe = $processArray['exe'];
  if (basename($processArray['exe']) == $processName){
     echo "\n Process $processName is running\n";
     echo "$pid   $exe \n";
//     break;
  }
}
exit(0); // Script ran OK
?>

Run the batch file (double click on Run.bat) several times

Result similar to this>

 Process cmd.exe is running
3860   C:\WINDOWS\system32\cmd.exe

 Process cmd.exe is running
604   C:\WINDOWS\system32\cmd.exe

 Process cmd.exe is running
3788   C:\WINDOWS\system32\cmd.exe

There are three command processes running each with an identical name, if you were to kill the process by name all three processes are killed. To kill a single process use its PID this is always unique.

If you wish to avoid this issue and kill processes by name make sure each process has a unique name.

Note:

You may see only a single cmd process running, if that is the case open a few command prompts before running the script.

Top

Kill process by name

This script uses a function to kill a named process, edit test_1.php and run the script (Run.bat)

<?php
kill_proc("cmd.exe");

function kill_proc($processName){
    @$processList = win32_ps_list_procs();
    foreach ($processList as $processArray){
        $pid = $processArray['pid'];
        if (basename($processArray['exe']) == $processName){           
           `taskkill /f /PID $pid 2>&1`;                   
        }
    }
}
exit(0); // Script ran OK
?>

Well if you are running XP-Pro Run.bat will have been killed. However if you are running XP-Home the process is not killed with taskkill. To keep both XP-Pro and XP-Home happy change the script to:

<?php
kill_proc("cmd.exe");

function kill_proc($processName){
    @$processList = win32_ps_list_procs();
    foreach ($processList as $processArray){
        $pid = $processArray['pid'];
        if (basename($processArray['exe']) == $processName){           
              `tskill $pid `;  
        }
    }
}
exit(0); // Script ran OK
?>

There is no end of these examples where an XP-Pro user (designer) never seeing or considering this type of issue, anyway I think the above vindicates my general note in the opening statement.

That said I have not confirmed (by testing) if tskill works on XP-pro or Vista family.

Top

Clean up

At this stage we have finished exploring extension php_win32ps.dll and have no further use for file php-cli.ini.

I like to remove clutter if you feel the same delete the following:

  • Delete folder: UniServer\udrive\usr\local\php\new_extensions
  • Delete file: UniServer\udrive\usr\local\php\php-cli.ini
  • Pack away UniServer Mona
  • The remainder of this tutorial uses UniServer Nano

Top

UniServer pskill.exe

UniServer pskill.exe utility is battle harden, by this I mean, beta testers have proven its functionality across both XP and Vista families and beta release of Windows 7.

It a dual function utility, can kill a named process or check if a named process is running.

Note: From here on I am assuming you are using UniServer 5.0-Nano or above

Top

Initial test setup

Edit our test file Run.bat contained in folder UniServer to have the following content:

Run.bat
TITLE CLI TEST BAT
COLOR B0
@echo off
cls
echo.
usr\local\php\php.exe -n test_1.php
echo.
pause

Top

Check a process is running

Edit our test file test_1.php contained in folder UniServer to have the following content:

test_1.php;
<?php
 $exe_name = "notepad.exe";                       // process to check
 $command= "unicon\program\pskill.exe $exe_name"; // command line to be run  
 exec($command,$dummy,$return);                   // 0=running 1=not-running 

 if($return == 0){                                // Check return value
  echo  " $exe_name Is running";
 }
 else{
  echo  " $exe_name Not running";
 }
exit(0); // Script ran OK
?>

Test 1:

  • Run Notepad
  • Run the batch file (double click on Run.bat), Process running displayed

Test 2:

  • Close Notepad (and any other open Notepads)
  • Run the batch file (double click on Run.bat), Process Not running displayed

Top

Function exec()

This function exec($command,$dummy,$return) runs the utility pskill.exe and collects data returned.

* $command - Command that will be executed. Path to program to run (pskill.exe) and any parameters to pass to it.
* $dummy - Dummy array filled with every line of output from pskill. We ignore this data. Must have some variable here hence
* $return - This variable holds returned error code from pskill. Named process running = 0 not running = 1

Top

Kill process by name

Edit our test file test_1.php contained in folder UniServer to have the following content:

test_1.php  
<?php
 $exe_name = "notepad.exe";        // process to kill

 // command line to be run note c as second parameter kills
 // the above named process  

 $command= "unicon\program\pskill.exe $exe_name c"; 
 exec($command);                   // runs command  
 exit(0);                          // Script ran OK
?>
?>


Test:

  • Run Notepad
  • Run the batch file (double click on Run.bat), Closes (kills) Notepad

Note:

Function exec($command) only a single parameter is required we are ignoring any returned data.

Top

Summary

The real point of this part of the tutorial was the introduction to UniServer’s pskill.exe with its ability to check for a running process and if required to kill it. It kills by process name not by PID not a real issue if you have control of naming the process (program).

Interestingly to build a fully functional CLI script you require several snippets of code that target problem areas. Consider this scenario, when a script starts another process it generally has to wait for that process to end before executing the next instruction.

Not a problem if you are going to process data from that process; however if all you want to do is kick the process off and then continue, your script will appear to hang if the process takes a long time or never terminates.

A solution to this scenario is covered on the next page.

Top


  MPG (Ric)