Tutorial: Cross-platform background process forking without extensions in PHP

There are plenty of ways to fork new processes in PHP. You can use shell functions like exec() or shell(), the pcntl_* function set in the Process Control extension or stream/filesystem functions such as popen(). In this article, we're going to look at the latter of these, and learn:

  • How to make it work on both Windows and Linux
  • How to make the forked process run in the background
  • How to communicate with the forked process
  • How to fork more than one process
  • How to cleanly terminate the forked process from the parent script

Why would we want to fork processes from PHP anyway?

The most common reason is because we want to get results from an external application and use them in the main script. We may also want to run a process that performs some action that is awkward in PHP, for example creating tarballs in backup scripts or modifying system configuration in maintenance scripts. You may want to create worker threads which do a long-running task and periodically report back their status. Finally, we may want to run processes periodically on a timer (see my PHPCron article for details on that).

Some things are better served by using threads due to the reduced overhead and lack of need to communicate between processes, but threading support in PHP is quite disastrous so forking a new process is a bit more bulletproof.

Forking a new process

You can fork a new process like this:

function startFork($path, $file, $args)
{
  chdir($path);

  if (substr(PHP_OS, 0, 3) == 'WIN')
    $proc = popen('start /b php "' . $path . '\\' . $file . '" ' . $args, 'r');
  else
    $proc = popen('php ' . $path . '/' . $file . ' ' . $args . ' &', 'r');
	
  return $proc;
}

This particular example assumes you're running another PHP script; if you're not, just remove the references to 'php ' from the code above. Note that changing the current directory with chdir() might have unpredictable consequences, so only do so if necessary, or change the directory back afterwards.

In Windows, start /b forks a new process without opening a new shell window, and makes it run in the background. In UNIX, appending the call with & also makes the process run in the background. The appropriate command is generated depending which platform PHP is running on by examining the PHP_OS constant.

Receiving data from the process

popen() returns a stream resource which can be manipulated just like a regular file. As the process outputs data, you can retrieve it as follows:

while (!feof($proc)) {
  $data = fgets($proc);

  // Do something with the data
}

The 'end of the file' will never be reached until the process stops running, so the while loop will merely stall until data is received. fgets() will stall until a newline is read, thereby retrieving one line of data at a time. You can use other stream reading functions instead if you want different behaviour.

If you're writing the child process yourself, you can make life easier by designing it to output data in a machine-readable format that can be easily parsed by PHP with functions like split() or regular expression functions.

When the process ends, call:

pclose($proc);

to close the stream.

Notice that if an error occurs, popen() will still return a resource handle so that the error text can be read. Make sure you check for this when parsing the incoming data.

Under UNIX, if the errors are sent to stderr, append 2>&1 to the line which forks the process to cause stderr to be redirected to stdout.

Running a background process and ignoring its output

If you don't care what happens to the child process, you can simply use the following line to invoke it:

pclose(startFork($path, $file, $args));

and the output will be discarded. The child process will run in the background without stalling the parent script.

Terminating a forked process from the parent script

There are various ways to do this but a simple one is to just create a so-called "kill file" that is monitored by the child process and triggers it to quit when found.

In the parent process:

$killFile = dirname(__FILE__) . '/child.die';
...

function stopFork()
{
  global $proc, $killFile;
	
  touch($killFile);
  sleep(2);
  pclose($proc);
}

In the child process:

$killFile = dirname(__FILE__) . '/child.die';

while (!file_exists($killFile)) {
  // Do worker task and output status
}

while (file_exists($killFile)) {
  @unlink($killFile);
  sleep(1);
  clearstatcache();
}

The child process runs its repetitive task in the first while loop, continuing as long as the kill file hasn't been created. Once it has been created, it moves to the second while loop which keeps trying to delete it until it succeeds, then the child process exits (make sure your directory permissions are set correctly to avoid an infinite loop).

When stopFork() is called in the parent process, the kill file is created with touch(), a short pause is made and then the process handle is closed. Not introducing a pause before closing the stream can cause the kill file not to be deleted and the child process to hang.

The above code assumes that the parent and child are both running in the same directory. If this is not the case, you will need to alter the definition of $killFile appropriately.

Ensuring child processes are always killed when the parent script ends

It's vital that child processes which act as worker threads aren't left hanging around after the main script has finished executing. If you leave orphan processes running, they may behave undesirably, create memory leaks, and on Windows if you call the CLI version of PHP the prompt will become unusable. To avoid this, attach stopFork() to the shutdown handler as follows:

register_shutdown_function('stopFork');

This will make sure that - however the main script is ended - the child processes are always killed off first.

Forking more than one process

This is as simple as repeating the above steps for as many processes as you need; however, if you are using the kill file technique to signal the child processes to end, you need to use a different kill file for each process. If you are forking the same process multiple times (multiple identical worker threads), you will want to pass the name of the kill file for each as an argument to the child process, eg:

startFork($path, $file, '/path/to/killfile1 ' . $args);
startFork($path, $file, '/path/to/killfile2 ' . $args);

In the child process, retrieve the name of the kill file to monitor as follows:

$killFile = $argv[1];

Usage example

I use the techniques above to measure the bitrate of several streaming audio servers. The rate of incoming data must be measured per second for several servers and therefore this requires background worker threads (or processes in this case). The background worker is another PHP script which is instanced once for each server to measure.

The child processes return one line of data every second in a format like:

X Y Z

where X is a count of the amount of data received in the last second, and Y and Z are moving averages. The intervals of each moving average to measure are passed as parameters to the child script. To parse the data in the parent is easy:

$movingAverages = split(' ', fgets($proc));
$lastSecond = array_shift($movingAverages);

This leaves X in $lastSecond and all the remaining numbers in the $movingAverages array. This is a perfect of example of why it's important to format your child process output as something that is easily parsable by the parent script.

I hope you found this article useful. Please leave any comments below!

Looking For discountchanel

Looking For discountchanel

replica
Beautifulgucci handbags for sale
油墨
Balenciagafor sale
Looking For discountchanel
If you want to buylouis

vuitton
丝印器材
Looking For discountchanel

handbags
Beautifulgucci for sale
The store online sells theBalenciaga

bags
different kinds oflouis vuitton for

cheap
网版烤箱
ghd straighteners for Cheap

Wholesale
If you want to buylouis vuitton

bag
different kinds oflouis vuitton

handbag for cheap
replica louis vuitton bag for for

Cheap Wholesale
ghd very cheap
china Wholesale
ghd hair straighteners for Cheap

Wholesale
移印器材
replica louis vuitton bag for

Cheap Wholesale

常德SEO

陈水博客从事专业常德网站建设常德网站优化与网站建设培训,为常德企业提供常德seo,常德SEO优化,常德网站建设,有着多年的seo优化服务网站策划经验。

Cheap Timberland Boots Sale

Cheap Timberland Boots Sale - More than 1000 customers have got thecheap timberland boots ,
Timberland Boots on sale
. We hold the most competitive price, the first class service,buy now!

pink ghd straighteners

Ghd straighteners uk - buy the cheapest pink ghd straighteners in the UK.Use Compare ghd to find the biggest savings on ghd iv pink mk4,ghd flat Irons,ghd iv styelers and ghd Hair Straighteners pink.Cheap ghd uk hair straighteners found here.

tall black uggs

We supply UGG Boots UK ,black tall ugg boots,UGG Bailey Button,low price,offerWoolboots.com must be your best choice!

chi hair straightener

Save 60% off chi hair straighteners,we offer best Pink CHI Flat Iron ,Chi Camo Blue Ceramic Flat Iron in the market and 100% Quality Guarantee.

Paolo discount gucci shoes

Paolo discount gucci shoes have their own logo and are Paolo's one works in the current world of gucci women shoes. These watches are still recognized for the quality that has always been part of the Gucci name.

Re

Sometimes different people have assignments to compose the politics essays related to this post. But a lot of them are inexperienced writers. Thus, what should they do under such circumstances? Some specialists instantly recommend to buy term paper in the online writing service.

ugg boots

Very grateful to God, so I saw this article, let me learn a lot.ugg boots saleonline,cheap uggs saleanduggs sale,Feeling very excited:ugg boots sale,gucci shoes,mbt shoes,cheap mbt shoes.Welcome to our site,thank you.

Ro Zeny

As a new player , you may need some game guides or information to enhance yourself.
Ro Zeny
is one of the hardest theme for every class at the beginning . You must have a good way to manage your Cheap Ro Zeny.If you are a lucky guy ,you can earn so many Ragnarok Zenyby yourself . But if you are a not , I just find a nice way to get Ragnarok Online Zeny. If you need , you can Buy Ro Zeny at our website . Go to the related page and check the detailed information . Once you have any question , you can connect our customer service at any time .

GHD hair straightener

thanks for sharing this nice post .ghd hair straightener always make you surprise
after you use it .just do as you like .

Chi flat iron, Chi Hair Straightener

well ,good article .chi hair iron in this season also make amazing by fashionable
people.make style with it .nice.

UGG Boots UK | Classic UGG Boots

this is a so nice post .ugg boots make this winter
so beautiful ,and we are attracted by many girls who wear
cardy ugg boots
on the street ,so fashion ,i am just thinking about it .

As the business grows,

As the business grows, replica rolex paypal has also jumped into an international brand. It is worth mentioning that, rolex replica is the ancestor of today's brand-oriented, in order to protect the quality and brand name will be printed on their products, the history of fashion in the world, is the first one first. replica watch paypal,replica watches paypal,fake rolex paypal.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <b> <i> <u> <pre> <sup> <sub> <h2> <h3> <h4>
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Copy the characters (respecting upper/lower case) from the image.

Latest articles