Asynchronous Processing With PHP

Several weeks ago I was looking on line for a way to have PHP execute a background process, so that the page didn’t hang while some functionality happened. One way to do that is to use fsockopen() to open a URL to exec what you want. But I wanted to see if there was another way. This is what I came up with.

I should note that this isn’t that well tested. I ran it on a Windows and Linux system without incident to test it, but I haven’t given it a very thorough exam. Also note $call is completely unsanitized. If you’re using this and accepting anything from the web, you need to make really sure that $call is completely sane and free of evil.

  1. < ?php
  2. /* Note that the call itself isn’t sanitized in any way, so it’s
  3.    important to make sure that this can’t be exploited, see
  4.    docs for escapeshellcmd() for details
  5. */
  6.  
  7. // Demonstration
  8. if(launchBackgroundProcess(‘touch testfile.txt’)){
  9.     print ‘Successfully launched background process’;
  10. }
  11.  
  12.  
  13.  
  14. /**
  15. * Launch Background Process
  16. *
  17. * Launches a background process (note, provides no security itself, $call must be sanitized prior to use)
  18. * @param string $call the system call to make
  19. * @author raccettura
  20. */
  21. function launchBackgroundProcess($call) {
  22.  
  23.     // Windows
  24.     if(is_windows()){
  25.         pclose(popen(’start /b ‘.$call., ‘r’));
  26.     }
  27.  
  28.     // Some sort of UNIX
  29.     else {
  30.         pclose(popen($call.‘ /dev/null &’, ‘r’));
  31.     }
  32.     return true;
  33. }
  34.  
  35.  
  36. /**
  37. * Is Windows
  38. *
  39. * Tells if we are running on Windows Platform
  40. * @author raccettura
  41. */
  42. function is_windows(){
  43.     if(PHP_OS == ‘WINNT’ || PHP_OS == ‘WIN32′){
  44.         return true;
  45.     }
  46.     return false;
  47. }
  48. ?>

To run a PHP process you can obviously use launchBackgroundProcess('PHP /path/to/script.php');.

Now say we wanted to load a page while retrieving data from a process to display inline. We don’t want to wait for the entire command to finish, since that could take a while, and the user may believe something is wrong and reload (slowing down the system even more). A good example of this is an online traceroute utility. Here’s a quick example of that:

  1. < ?php
  2.     /****
  3.      * Again notice this is unsanitized since we trust ourselves.  Coming from the web
  4.      * it would need to be sanitized to ensure it’s safe to use.  see escapeshellarg()
  5.      ****/
  6.     $hostname = ‘accettura.com’;
  7. ?>
  8. < !DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
  9. <HTML xmlns="http://www.w3.org/1999/xhtml">
  10. <head>
  11.     <title>Traceroute to $hostname</title>
  12. </head>
  13. <body>
  14. < ?php
  15.     if(is_windows()){
  16.         $cmd = ‘tracert -w 10′;    
  17.     } else {
  18.         $cmd = ‘traceroute -w 10′;
  19.     }
  20.     $handle = popen("$cmd $hostname 2>&1", ‘r’);
  21.  
  22.     while(!feof($handle)) {
  23.         $buffer = fgets($handle);
  24.         $buffer = ‘<p>’.trim(htmlspecialchars($buffer)).‘</p>’;
  25.  
  26.         echo $buffer;
  27.         ob_flush();
  28.         flush();
  29.     }
  30.     pclose($handle);
  31.  
  32.  
  33.  
  34.    /**
  35.     * Is Windows
  36.     *
  37.     * Tells if we are running on Windows Platform
  38.     * @author raccettura
  39.     */
  40.     function is_windows(){
  41.         if(PHP_OS == ‘WINNT’ || PHP_OS == ‘WIN32′){
  42.             return true;
  43.         }
  44.         return false;
  45.     }
  46. ?>
  47. </body>
  48. </HTML>

Isn’t that simple?

There’s more than 1 way to approach a problem, and there may be better ways out there. I won’t be so cocky as to think these are by any means perfect. But they may be of help to someone who also notices the lack of documentation on little (but important) things like this.

Just remember: always sanitize your input when working with stuff like this, or your putting your system at risk.

Tags: , ,



9 Responses to “Asynchronous Processing With PHP”

  1. silentcoder.com » Blog Archive » Asynchronous Processing With PHP Says:

    [...] http://robert.accettura.com/ar.....-with-PHP/ [...]

  2. Скакунов Ð?лекÑ?андр Says:

    Very nice!

    It would be cooler if you could pass a callback function name.

  3. sean Says:

    This looks good; I am trying to figure out a way to get a PHP script to run in the background on a Windows server.

    However, I can’t figure out your use of quotes, they seem to be uneven.

    What am I missing?

  4. Robert Says:

    Sean: you can use both ' or " in PHP as long as you use them as “This “.’that’. Single quotes won’t be evaluated. For example:

    1. $test = ‘value’;
    2.  
    3. print "This is a $test"; // will be: This is a value
    4. print ‘This is a $test’; // will be: This is a $test
  5. How To Run A PHP Script In The Background | MT-Soft Website Development Says:

    [...] a background process in an OS-independent fashion you’d can use the function below (snatched from this post) [...]

  6. johny why Says:

    this ain’t workin. any ideas? running on a linux host:

    if this is shelling out to the system, then i don’t have shell access. is there way way to do an asynchronous call to a PHP script WITHOUT calling the shell?

    thanks

  7. johny why Says:

    the code:

    pclose(popen(’PHP http://picnictoimpeach.us/remote.php5‘, ‘r’));

  8. diiar Says:

    This doesn’t work with me. I don’t know what’s wrong, but lauchBackgroundProcess() doesn’t do anything. However, if I add fgets() as in the second script, it works. But, it’s not an asynchronous call!!

  9. Robert Says:

    @diiar: It’s possible your host prohibits the use of popen() for security reasons. You should check with your admin.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

By submitting a comment here you grant this site a perpetual license to reproduce your words and name/web site in attribution.