I'm trying to launch a really time-consuming script from a browser such that the user can start the script and then continue to browse other material while the long script runs in the background. I've got this working quite well for linux here, and I've been trying this solution from Drakla for windows and it's just not working for me.

My script, launch.php, looks as follows:

<?php

$cmd = 'php long_script.php'; // just a script that sleeps a lot and updates a mysql table with its progress
echo 'cmd:' . $cmd . '<br>';
$result = run_in_bg($cmd); 
print_r($result);

function run_in_bg($cmd, $winStyle = 0, $waitOnReturn = false){
    $WshShell = new COM("WScript.Shell");
    $oExec = $WshShell->Run($cmd, $winStyle, $waitOnReturn);
# this line causes error
 #   $WshShell->Release();

return $oExec;
}
?>

The output of the script looks like this:

cmd:php long_script.php
0

both launch.php and long_script.php live in the same directory. I access launch.php via a browser but long_script.php never reports any progress. I turned on error_logging in my PHP.ini on this windows machine and discovered that long_script.php was running but PHP was dying of a fatal error when trying to include these scripts inside long_script.php:

include_once "../framework/scripts/framework_cli.php";
include_once "util.php";
include_once "constants.php";

These includes work and make complete sense when evaluated relative to the file long_script.php (or relative to launch.php) but do not work when one assumes the current working dir is C:\Program Files\Apache Software Foundation\Apache2.2. For some reason, this is what PHP on windows assumes when I invoke a script in this manner.

Can someone explain this to me? The windows behavior is totally different than the linux behavior and i bet it has something to do with the gnarly PATH var I have on my windows server -- or perhaps something to do with 'WScript.Shell'.

I'm both looking for some reason to this madness but also a good way to deal with it. The idea of putting a chdir() statement in every script I'd like to invoke with this method sounds like a pretty bad way to do it. NogDog suggested this but I'm still thinking it's pretty ugly:

chdir(dirname(__FILE__));

EDIT: I made various changes for clarity.

    If you can't get this solved, but still need a dirty solution then try this - but you've got to output buffer or just call the function first thing and then go to the rest of your script.

    You'd need to put this at the top of a script you'd call directly with the browser, or that simulated through file_get_contents or curl or whatever.

    ob_start();
    
    for ($i = 0; $i < 10; $i++)
    {
    	echo "I am running... $i<br />";
    }
    
    ob_start();	// to test full buffering
    
    for (; $i < 20; $i++)
    {
    	echo "I am running... $i<br />";
    }
    
    dirty_close();
    
    sleep(2);
    
    echo "You won't seee meeeee.... (if things went right)";
    
    
    /**
    *
    */
    
    function dirty_close()
    {
    	$content = '';
    	$len = 0;
    
    while (ob_get_level())
    {
    	$len += ob_get_length();
    	$content = ob_get_clean() . $content;
    }
    
    if ($len == 0)
    {
    	$content = ' ';
    	$len = 1;
    }
    
    header('Connection: close');
    header('Content-length: '.$len);
    
    echo $content;
    flush();
    }

      WTF is that?? More scary stuff from the lord of the undead.

      I'm not sure, but it looks like you are using the buffering functionality to suppress output while some elaborate script runs. Where does my time-consuming script go in this abomination? I'm afraid yes but also intrigued.

        Basically after you call dirty close then do your script stuff there. So basically

        ignore_user_abort(true);
        set_time_limit(394092);
        
        echo "Hey, you can close this script - I'm serious!";
        
        dirty_close();
        
        my_big_evil_function();

        You're right - the script tells the browser it's outputting X bytes then closing up shop, so the browser should (it doesn't always) just take X bytes and be happy to go along its way.

        Give it a go - make the script write the time to a file, sleep for 10 seconds then write the time again, something simple.

          Write a Reply...