Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Here's one solution, not the greatest, but will work fine on Linux:</p> <p>Split the processing PHP into a separate CLI scripts in which: </p> <ul> <li>The command line inputs include `$id` and `$item` <li>The script writes its PID to a file in `/tmp/$id.$item.pid` <li>The script echos results as XML or something that can be read into PHP to stdout <li>When finished the script deletes the `/tmp/$id.$item.pid` file </ul> <p>Your master script (presumably on your webserver) would do: </p> <ul> <li>`exec("nohup php myprocessing.php $id $item > /tmp/$id.$item.xml");` for each item <li>Poll the `/tmp/$id.$item.pid` files until all are deleted (sleep/check poll is enough) <li>If they are never deleted kill all the processing scripts and report failure <li>If successful read the from `/tmp/$id.$item.xml` for format/output to user <li>Delete the XML files if you don't want to cache for later use </ul> <p>A backgrounded <code>nohup</code> started application will run independent of the script that started it.</p> <p>This interested me sufficiently that I decided to write a POC.</p> <p>test.php</p> <pre><code>&lt;?php $dir = realpath(dirname(__FILE__)); $start = time(); // Time in seconds after which we give up and kill everything $timeout = 25; // The unique identifier for the request $id = uniqid(); // Our "items" which would be supplied by the user $items = array("foo", "bar", "0xdeadbeef"); // We exec a nohup command that is backgrounded which returns immediately foreach ($items as $item) { exec("nohup php proc.php $id $item &gt; $dir/proc.$id.$item.out &amp;"); } echo "&lt;pre&gt;"; // Run until timeout or all processing has finished while(time() - $start &lt; $timeout) { echo (time() - $start), " seconds\n"; clearstatcache(); // Required since PHP will cache for file_exists $running = array(); foreach($items as $item) { // If the pid file still exists the process is still running if (file_exists("$dir/proc.$id.$item.pid")) { $running[] = $item; } } if (empty($running)) break; echo implode($running, ','), " running\n"; flush(); sleep(1); } // Clean up if we timeout out if (!empty($running)) { clearstatcache(); foreach ($items as $item) { // Kill process of anything still running (i.e. that has a pid file) if(file_exists("$dir/proc.$id.$item.pid") &amp;&amp; $pid = file_get_contents("$dir/proc.$id.$item.pid")) { posix_kill($pid, 9); unlink("$dir/proc.$id.$item.pid"); // Would want to log this in the real world echo "Failed to process: ", $item, " pid ", $pid, "\n"; } // delete the useless data unlink("$dir/proc.$id.$item.out"); } } else { echo "Successfully processed all items in ", time() - $start, " seconds.\n"; foreach ($items as $item) { // Grab the processed data and delete the file echo(file_get_contents("$dir/proc.$id.$item.out")); unlink("$dir/proc.$id.$item.out"); } } echo "&lt;/pre&gt;"; ?&gt; </code></pre> <p>proc.php</p> <pre><code>&lt;?php $dir = realpath(dirname(__FILE__)); $id = $argv[1]; $item = $argv[2]; // Write out our pid file file_put_contents("$dir/proc.$id.$item.pid", posix_getpid()); for($i=0;$i&lt;80;++$i) { echo $item,':', $i, "\n"; usleep(250000); } // Remove our pid file to say we're done processing unlink("proc.$id.$item.pid"); ?&gt; </code></pre> <p>Put test.php and proc.php in the same folder of your server, load test.php and enjoy.</p> <p>You will of course need nohup (unix) and PHP cli to get this to work.</p> <p>Lots of fun, I may find a use for it later.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload