3

Suppose I'd like to run a server side command with PHP on form submit via my webpage. The command is du -hs which could take several minutes to complete. Could I use exec() or shell_exec() in a way so that the webpage reloads immediately and doesn't wait for the output of the command? An example would be great! Thanks!

<?php
    exec('du -hs');
?>
user2799603
  • 873
  • 3
  • 13
  • 19
  • 2
    This is identified in the [`exec()` documentation](http://us3.php.net/manual/en/function.exec.php) right under the fist Warning section. _If a program is started with this function, in order for it to continue running in the background, the output of the program must be redirected to a file or another output stream. Failing to do so will cause PHP to hang until the execution of the program ends._ – Michael Berkowski Feb 19 '14 at 14:32
  • Have a look at `symfony/process`. No need to reinvent the wheel. – KingCrunch Feb 19 '14 at 14:35
  • Here is your answer http://stackoverflow.com/questions/3819398/php-exec-command-or-similar-to-not-wait-for-result – manan Feb 19 '14 at 14:38
  • 1
    Have you tried adding a ` &` : (`exec('du -hs &');`) ? – Sebastien C. Feb 19 '14 at 14:39

3 Answers3

4

HACK ALERT, but if you don't want to background it (say you need to do something with the result) and don't care when it finishes you could put the command in the destructor method of an object. Note that that while the user will get their response and be free to request another page, the process won't be freed from Apache or PHP-fpm until it's done.

class someClass{

      function __destruct(){   
           exec('du -hs');
       }     
}

NOTE: the robust way to process tasks in the background would be to use a message queue and job service handler build out with gearman, rabbitMQ, or such.

Ray
  • 40,256
  • 21
  • 101
  • 138
  • I've never heard of this before, and I'm glad you added the HACK ALERT. This is kind of scary but also quite clever. Be sure to comment it extensively in the code! – Michael Berkowski Feb 19 '14 at 14:38
  • @MichaelBerkowski I do hack this to avoid using a job queue server for sending a user's data to my email webservice to shoot out a welcome email. This can take a second or so, but i don't want the user to wait once they sign up. – Ray Feb 19 '14 at 14:39
  • @Ray Very interesting hack, but is there a case where this would be preferred over redirecting the output from the command? If so, you should add it to your answer. – FtDRbwLXw6 Feb 19 '14 at 14:40
  • Use caution also, if you plan to instantiate more than one of `someClass`, I suppose, if you don't want to inadvertently launch multiple processes as they're cleaned up. – Michael Berkowski Feb 19 '14 at 14:42
  • @drrcknlsn I mention they may need to do something with the result, and you can put any arbitrary code after the `exec` in the destructor to do other things. (just won't be available to the user since they already got their request serviced) – Ray Feb 19 '14 at 14:43
  • @MichaelBerkowski good point, I do this myself in a User Class object and each new user minds it's own, but if you wanted to have only one action across all user object, you'd need to use some kind of static class semaphore /locking property or something. Even that would only work within the request, since static isn't shared amongst different processes. – Ray Feb 19 '14 at 14:45
  • @Ray I meant that it's not clear to me why one would choose to use this hack over just using e.g. `exec('... > /dev/null');` outside of a destructor. I'd be interested to know if this method works in cases where the other does not, or if it's just a fun quirk. – FtDRbwLXw6 Feb 19 '14 at 14:48
  • @drrcknlsn exec with reidecting output basically spawns off a totally independent process without further interaction with the php. If the `exec` command/scripts results are not needed for processing in the PHP script, then there is no benefit for my destructor hack. The value is when you need to do something in PHP with the results from the command being `exec`, but without halting a users web experience. I use it to send welcome emails to new users via a web service in the destructor of the user object and then update the User record in the DB on the return value from the email API. – Ray Feb 19 '14 at 14:58
  • @Ray Very nice; that's what I was wondering, thanks! – FtDRbwLXw6 Feb 19 '14 at 15:00
2

The top comment on the PHP documentation for exec() by Arno van den Brink gives you your answer:

This will execute $cmd in the background (no cmd window) without PHP waiting for it to finish, on both Windows and Unix.

<?php 
function execInBackground($cmd) { 
    if (substr(php_uname(), 0, 7) == "Windows"){ 
        pclose(popen("start /B ". $cmd, "r"));  
    } 
    else { 
        exec($cmd . " > /dev/null &");   
    } 
} 
?>
FtDRbwLXw6
  • 27,774
  • 13
  • 70
  • 107
1

It sounds like you want to show the results of the du on the web page, but not wait for it. This would require an ajax call.

Load your page, which contains a div like:

<div id="du-div">Calculating filespace...</div>

Then onload, call your du.php via ajax which would run and return your file usage. You then update your div with the content.

Digital Chris
  • 6,177
  • 1
  • 20
  • 29