PHP CLI: Process Running
PHP CLI : Introduction | Paths | PHP INI | Process Running | Detached Processes | Hidden Process | User Input | Files | Search & Replace | Recursive Search & Replace
|
|
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.
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
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.
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.
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.
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
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
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 |
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
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 |
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 ?> ?> |
Note: Function exec($command) only a single parameter is required we are ignoring any returned data. |
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.
MPG (Ric) |