Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

So....I have a PHP page that involves a lot of backend execution, namely 'exec' calls to run shell commands on the host server.

This can take upwards of a few minutes depending on the calls involved. (If you look below, each recursion through the exec calls is mounting a LUN; I'd like to sometimes do upwards of 100 per execution.) I'm curious on what I can do to send content back to the browser (and prevent it from timing out).

<!DOCTYPE html>
<html>
  <head>
    <title>sfvmtk</title>
  </head>
  <body>
    <?php
      // TEMPORARY VARIABLES FOR TESTING
      $hba = 'vmhba38';
      $svip = '10.10.20.100';
      $targets = array ( 0 => array ( 'iqn' => 'iqn.2010-01.com.sf:t5np.esxtest.41',
                                      'account' => 'esx',
                                      'isecret' => 'isecret00000',
                                      'tsecret' => 'tsecret00000'
                                    ),
                         1 => array ( 'iqn' => 'iqn.2010-01.com.sf:t5np.esxtest2.42',
                                      'account' => 'esx2',
                                      'isecret' => 'isecret00001',
                                      'tsecret' => 'tsecret00001'
                                    )
                       );

      $hostname = $_REQUEST['hostname'];
      $username = $_REQUEST['username'];
      $password = $_REQUEST['password'];

      foreach ($targets as $ctarget) {
        exec('esxcli -s '.$hostname.' -u '.$username.' -p '.$password.' iscsi adapter discovery statictarget add -A '.$hba.' -a '.$svip.' -n '.$ctarget['iqn'], $out);
        exec('esxcli -s '.$hostname.' -u '.$username.' -p '.$password.' iscsi adapter target portal auth chap set -A '.$hba.' -a '.$svip.' -N '.$ctarget['account'].' -d uni -l required -n '.$ctarget['iqn'].' -S '.$ctarget['isecret'], $out);
        exec('esxcli -s '.$hostname.' -u '.$username.' -p '.$password.' iscsi adapter target portal auth chap set -A '.$hba.' -a '.$svip.' -N '.$ctarget['account'].' -d mutual -l required -n '.$ctarget['iqn'].' -S '.$ctarget['tsecret'], $out);
      }
      exec('vicfg-rescan --server '.$hostname.' --username '.$username.' --password '.$password.' '.$hba, $out);
    ?>
  </body>
</html>
share|improve this question

4 Answers 4

You would need to use proc_open http://www.php.net/manual/en/function.proc-open.php, proc_get_status http://php.net/manual/en/function.proc-get-status.php, stream_set_blocking http://php.net/manual/en/function.stream-set-blocking.php as well sleep http://php.net/manual/en/function.sleep.php and echoing and flushing should be working OK.

This prevents PHP from timing out and killed from parent apache handler whatever it is, so you need to flush PHP buffer to apache, however this doesnt mean that the data will be sent to the client, because there is cashing, compression and so on, so in this case, you need to use http/xml request (ajax), to check with the another process, and you could use either DB, filesystem, cache or session to handle this information. Even further you require to secure it properly, you would run the processes and website from different account, so nobody can run commands from your website.

share|improve this answer
    
No - frequent flushing from php has no impact on timeout, nor does it impact when the webserver decides to send data back to the browser (i.e. you can't force chunked encoding/progressing rendering of pages from php) –  symcbean Jun 27 '12 at 8:18
    
Yes its true, but what I meant to use flush not for the browser but the server, so the server will not time out the unresponsive PHP process, so it's keeps sending data and flushing, so it doesnt stay at PHP, but gets to the apache. Normally this would have to be handled by separate request like ajax and return via http/xml request. –  Andrew Smith Jun 27 '12 at 9:54

For any long running process invoked over HTTP, the solution is usually to handle it asynchronously (i.e. in a seperate process group from the webserver).

You can get away with with very long requests on a webserver specifically optimized to handle them - but only if all the intervening HTP aware devices are prepared to play along (using SSL can help). But it's not possible in this configuration to show the extent of the processing OTOH poling a log file generated by a seperate process can be done with short, automatically refreshing HTTP requests.

share|improve this answer

Have you considered a layer of abstraction for such tasks such as Gearman? You could poll the backend and still maintain a responsive front end or locking the user to a page while it executes.

share|improve this answer
    
I'll have to look into this and the solution that Andrew Smith suggested. They're both along the lines of what I was looking for, but I'm still fairly new to the PHP landscape. Thanks! –  Matt Malesky Jun 27 '12 at 0:01

Use jQuery and Ajax to handle the above task in a DIV. For timeout, you'll need to tweak php.ini for the webserver (or modify it in .htaccess for Apache). There's no real way for the script itself to report back as its thread is busy working.

You can try putting an echo or printf in each loop, I have tried this trick many times and often, the output won't buffer until the script finishes. This requires trial and error. If you have many many records and this trick DOES work, I'll do this each loop:

echo ".";
if( $i++%100 == 0 )
    echo "\n";

This way, dots grow across the page until 100 columns/loops/records then starts a new line.

share|improve this answer
    
See Comment on Andrew Smith's answer. –  symcbean Jun 28 '12 at 8:01

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.