4

I have a very similar setup to the person here:
PHP Background Processes
i.e a very long script that takes up to 10 minutes. However, I need the person who calls the script redirected back to the homepage while the script works. In other words, I need the user experience to be something like this:

  • click the update button
  • script begins to execute, can take up to 10 minutes
  • user is redirected back to the home page immediately

Is this possible using only PHP? I gather I will need

ignore_user_abort(true); 
set_time_limit(0);

But how do I redirect the user? I can't use javascript because output only gets written to the page at long increments, and I want the redirection to be immediate. Can I use headers? Or will that mess with things?

Alternatively, I could use the cron job approach, but I have zero experience in making a cron job or having it run php code (is that even possible?)

Thanks,
Mala

Update:
Using headers to redirect does not work - the page will not load until the script is done. However, eventually the webserver times out and says "Zero-Sized Reply: The requested URL could not be retrieved" (although the script continues running). I guess my only option is to go with the cron job idea. Ick!

Community
  • 1
  • 1
Mala
  • 14,178
  • 25
  • 88
  • 119

4 Answers4

2

The most obvious solution to me would be splitting the redirect and the background calculation in two separate files and let the redirect script execute the 10-minute script:

job.php:

<?php
// do the nasty calculation here

redirect.php:

<?php
// start the script and redirect output of the script to nirvana, so that it
// runs in the background
exec ('php /path/to/your/script/job.php >> /dev/null 2>&1 &'); 

// now the redirect
header ('Location /index.php');

Assumptions for this to work: You should be on a Linux host with either safe_mode disabled or having set the safe_mode_exec_dir appropriately. When you're running under windows, the exec string needs to be adapted, while the rest about safe_mode remains true.

Notice: When you need to pass arguments to the script, use escapeshellarg() before passing it on, see also the PHP manual on exec

Dan Soap
  • 10,114
  • 1
  • 40
  • 49
1

I've tried several methods and none seems to work, I've even tried to use register_shutdown_function() but that also failed. I guess you're stuck with making a cron job.

I just remembered something (but I haven't tested it), you can try to do something like this:

set_time_limit(0);
ignore_user_abort(true);

ob_start(); // not sure if this is needed

// meta refresh or javascript redirect

ob_flush(); // not sure if this is needed
flush();

// code to process here

exit();

Not sure if it'll work but you can try it out.

Alix Axel
  • 151,645
  • 95
  • 393
  • 500
  • Thanks. I want to avoid "soft" redirects if at all possible, so I suppose I'm off to make a cron job! How would you suggest doing it? Have a cron job run a "Script manager" type script, or just directly run the godawful update script? – Mala Dec 13 '09 at 09:48
  • I'm not sure if I fully understand you, but before you go into CRON jobs I think you should try Cassy's solution since both method use need the same requirements. – Alix Axel Dec 13 '09 at 09:54
  • Also, have you considered AJAX as an option? The user clicks something, a PHP page is processed in the background and upon completion you could have a "job done" message show up on the webpage. – Alix Axel Dec 13 '09 at 09:55
  • The ignore_user_abort works only by scripts called from cli. I tried it out by browser called scripts, but browser timeout stopped them. – inf3rno Feb 09 '11 at 18:09
  • @inf3rno: I've used `ignore_user_abort` in non-CLI environments and although it isn't nearly as "responsive", it works. – Alix Axel Feb 09 '11 at 20:37
0

I have a similar situation with processing logins. To keep it short... I get a PDT, IPN and each sends me a logging email. An email is sent to client on IPN VERIFIED to give serial number and password to client. As PDT and IPN I use goto to send me a logging email instead of a bunch of sequential ifs. On reading many answers I studied each to figure what would suit my isssue. I finally used...

<?php
  ignore_user_abort(TRUE); // at very top

As I worked through the progressive checks (no ifs), if they failed I use for example...

  $mcalmsg .= "Check [serialnbr]\r\n";
  if (empty($_POST['serialnbr']))
    {    header('Location: '.$returnurl.'?error=1');
      $mcalmsg .= "Missing [serialnbr]\r\n";
      goto mcal_email; // Last process at end of script        
    }
    else
    {$serialnbr=strtoupper(htmlspecialchars(trim($_POST['serialnbr'])));
     $mcalmsg .= "[serialnbr]=$serialnbr\r\n";
    }

This (so far) is working just as needed. Of course there is more in the script but follows the same concept. Where this says location, there are also 3 information pages that can each be displyed using the same concept.

mcal_email: //last process before ending, always gets here after all else from goto or clearing all checks.
 // compose email and send
?> // end of script
-1

Why not try the header approach and see what happens? You could also try a call to php header method and see if this does the trick. I would work on trial and error to see what will solve your problem.

Toby Allen
  • 10,997
  • 11
  • 73
  • 124