29
Jun
6

PHP Tutorial – Forking using wget or php cli in the background

I see a lot of people asking on how to use a fork to run a php script or web page in the background.

Here's a quick script I created using linux's wget to run another process in the background. You could use this to automatically upload something to another server, or just about anything that needs to happen after a user action.

Note: you must have exec enabled for this to work. This is a security risk, so make sure you know the potential damage that can be done by enabling exec, and by the script that you are running. Make absolutely sure to sanitize any input being transferred to the executed script.

In my case, I needed to initiate a file upload to a remote server after a certain action was taken. Because of the nature of the upload, it would have taken about 30 seconds before displaying any response to my user, which is an unacceptable delay.

First, make the script that needs to run in the background.

PHP:
  1. <?php
  2.  
  3. //ALWAYS USE THIS FOR UNATTENDED SCRIPTS, YOU DON'T WANT THEM RUNNING FOREVER
  4.  
  5. /*
  6. SCRIPT THAT DOES SOMETHING YOU WANT TO RUN IN THE BACKGROUND
  7. THIS SCRIPT CAN DO ANYTHING. IT IS A NORMAL PHP SCRIPT
  8. HOWEVER, DO NOT MAKE A SCRIPT THAT WILL OUTPUT TO THE BROWSER
  9. AS NOBODY WILL EVER SEE IT
  10. */
  11.  
  12. //YOU CAN ALSO USE sleep($seconds) TO RUN THIS AFTER A SPECIFIED AMOUNT OF TIME
  13. sleep(30);
  14.  
  15. $output = 'SOME DATA THAT I GENERATED';
  16.  
  17. $ftp_user_name = 'user';
  18. $ftp_user_pass = 'pass';
  19. $ftp_server = 'ftp.someplace.com';
  20. $ftp_dir='/this_folder/';
  21.  
  22. $destination_file = date('Y-m-d');
  23.  
  24. // connect, login, and transfer the file
  25. $conn_id = @ftp_connect($ftp_server);
  26. $login_result = @ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
  27. @ftp_put($conn_id, $destination_file.'.csv', $output);

Next, make the script that executes the background script.

PHP:
  1. <?php
  2.  
  3. //DO A BUNCH OF STUFF HERE...
  4.  
  5. //LOCATION OF THE PAGE YOU WANT TO EXECUTE IN THE BACKGROUND
  6. $page_to_execute = 'http://www.mysite.com/background_script.php';
  7.  
  8. /*
  9. COMMAND TO EXECUTE THE PAGE USING WGET
  10. YOU CAN SEND GET VARIABLES USING THIS
  11. BE ABSOLUTELY SURE TO PROTECT AGAINST INJECTION
  12. */
  13. $command = 'wget -q '.$page_to_execute;
  14.  
  15. //ALTERNATELY TO WGET YOU COULD USE SOMETHING LIKE
  16. //$command = "nohup /usr/local/bin/php -f ".$page_to_execute;
  17.  
  18. /*
  19. NOW EXECUTE THE PAGE IN THE BACKGROUND
  20. THIS WILL NOT RETURN ANY ERROR IF IT FAILS
  21. YOU WILL NEED TO WATCH YOUR SERVER LOGS
  22. TO PROPERLY DEBUG
  23. */
  24.  
  25. @exec( "$command> /dev/null &", $arrOutput );

There you have it. This will run a script in the background (any web page that you specify). I do not use a local path to the file, because it will often break and can pose additional security risks. Using the above code, the server can only execute wget, and the actual page is parsed just like any other page on your website.

Again, make sure you understand the potential problems enabling exec can cause. There are also other ways of doing this such as running php from the exec command (path/to/php my_script). These can pose much greater security risks if they are not properly coded.

Lastly, this should be run on user or administrator initiated event, and not on events such as page views. This could spawn a huge number of processes if it is ever allowed to run based on every page view or something similar.

Enjoyed reading this post?
Subscribe to the RSS feed and have all new posts delivered straight to you.
6 Comments:
  1. Jonathan 29 Jun, 2009

    Are the two scripts on different machines? Why not simply call the php CLI from exec?

  2. jestep 29 Jun, 2009

    In this case they were.

    Normally I would go with php cli:
    php -f /path/to/page > /dev/null &

  3. Brian Lewis Design 17 Mar, 2010

    now hoe do you keep people from directly accessing the file http://www.mysite.com/background_script.php? So that exec() is the only way to run it?

  4. jestep 23 Mar, 2010

    You would need to use php via the command line, and place the file outside of the home directory. Assuming your home directory is /home/username/web/, /home/username/public_html/ or something similar, you would use something like:


    $command = "nohup /usr/local/bin/php -f /home/username/execute.php";

    //Then:

    @exec( "$command> /dev/null &", $arrOutput );

  5. Simon Holywell 12 May, 2010

    You can use wget and just pass it a secret key to stop others from accessing the script as I have described here: http://blog.simonholywell.com/post/374209271/linux-to-windows-server-migrating-and-securing-your-cron

  6. Jason 30 May, 2010

    to make sure normal webusers are not accessing this unless im missing something, just pass and argv value in the command and check for it in the script. As far as i know ARGV can not be POSTED, so only a command line method can pass this value. So only your script and a terminal can call it.

Post your comment



Copyright © 2010 SayNoToFlash, Jamie Estep, All Rights Reserved · Theme design by Themes Boutique