tags:

views:

292

answers:

6

I have an HTML form that submits to a PHP page which initiates a script. The script can take anywhere from 3 seconds to 30 seconds to run - the user doesn't need to be around for this script to complete.

Is it possible to initiate a PHP script, immediately print "Thanks" to the user (or whatever) and let them go on their merry way while your script continues to work?

In my particular case, I am sending form-data to a php script that then posts the data to numerous other locations. Waiting for all of the posts to succeed is not in my interest at the moment. I would just like to let the script run, allow the user to go and do whatever else they like, and that's it.

+2  A: 

Place your long term work in another php script, for example

background.php:

sleep(10);
file_put_contents('foo.txt',mktime());

foreground.php

$unused_but_required = array();
proc_close(proc_open ("php background.php &", array(), $unused_but_required));
echo("Done);

You'll see "Done" immediately, and the file will get written 10 seconds later.

I think proc_close works because we've giving proc_open no pipes, and no file descriptors.

Daniel Von Fange
Could you be a bit more descriptive in your answer?
Jonathan Sampson
Could you explain how it works? Looks like it tries to close the process immediately after it opens. According to proc_close documentation, it will wait for the process to terminate - isn't this what we wanted to avoid?
thomasrutter
I use this method to do threading and works really well
Gabriel Sosa
Updated with more sample code.
Daniel Von Fange
Daniel, how would you pass the $_POST/$_GET values to the background.php script?
Jonathan Sampson
You could write them into a database table, and pass it the id as a argument, or you could serialize() the $_REQUEST and pass it as an argument (make sure to have it escaped)
Daniel Von Fange
I'd say you should avoid passing parameters to the script over the command line at all costs. All it takes is one poorly sanitized input and you've seriously compromised your system.
Bob Somers
A: 

You could try the flush and related output buffer functions to immediately send the whatever is in the buffer to the browser:

TenebrousX
+1  A: 

In the script you can set:

<?php
 ignore_user_abort(true);

That way the script will not terminate when the user leaves the page. However be very carefull when combining this whith

 set_time_limit(0);

Since then the script could execute forever.

Pim Jager
+1  A: 

You can use set_time_limit and ignore_user_abort, but generally speaking, I would recommend that you put the job in a queue and use an asynchronous script to process it. It's a much simpler and durable design.

troelskn
A: 

Theres an API wrapper around pcntl_fork() called php_fork.

But also, this question was on the Daily WTF... don't pound a nail with a glass bottle.

John Ellinwood
A: 

I ended up with the following.

<?php

  // Ignore User-Requests to Abort
  ignore_user_abort(true);
  // Maximum Execution Time In Seconds
  set_time_limit(30);

  header("Content-Length: 0");
  flush();

  /*

    Loooooooong process

  */

?>
Jonathan Sampson