5

I'd use the following code:

$SERVER_PATH = dirname(__FILE__);
shell_exec($PHP_LOCATION.' '.$SERVER_PATH."/script.php?k1=v1&k2=v2 > /dev/null 2>/dev/null &");

Where:

  • $PHP_LOCATION should contain the path to PHP,

  • $SERVER_PATH - is current working directory (fortunately the script to run is in the same directory),

  • > /dev/null 2>/dev/null & added to make this call asynchronous (taken from Asynchronous shell exec in PHP question)

This code has two problems:

  1. As far as I remember ?k1=v1&k2=v2 will work for web-call only, so in this particular case parameters will not be passed to the script.

  2. I don't really know how to init the $PHP_LOCATION variable to be flexible and to work on the most hosts.

I conducted some research regarding both problems:

To solve 1 suggested to use -- 'parameters_string' but it is also recommended to modify the script to parse parameters string which looks a bit clumsy. Is there a better solution?

To solve 2 I found a solution to use PHP_BINARY but this is a PHP 5.4+ case (I'm using 5.3). But the original question was about to run PHP of the same version as the original script version. So for me (as I use PHP 5.3 only) is there probably a solution?

EDIT 0

Let me do some explanation why I stuck to this weird (for PHP) approach:

Those PHP scripts should be separate from each other:

  • one of those will analyze the data and

  • the second will generate PNG graphs as a final result.

Those scripts aren't intended to run simultaneously, this means that the second can run at it's own schedule it is only needed that the run should be upon its data will be ready (which done by the first script). So no data should be passed back from second script (child) to the first (parent).

EDIT 1

As seeing from most of the comments the main discussion goes to forking direction. However I'd like to make stress on the point 1 and 2 asked in the original questions. I have some reasons to solve the task in the way I pointed out and I tried to point all that reason. If some of my points looks weird, please post a comment - I will make it more clear or I will change the main question.

Thank you in advance!

Community
  • 1
  • 1
Vlada Katlinskaya
  • 991
  • 1
  • 10
  • 26
  • 1
    why don't you use `include_once('file path')` ? – Abdo Adel Jul 22 '15 at 09:01
  • @AbdoAdel I need it to be asyncronous. So this is why I'd like to run a separate process. In case on `include` the main script will not get the control until the child process finish – Vlada Katlinskaya Jul 22 '15 at 09:04
  • 2
    Sounds like PHP isn’t the best choice for the problem you’re trying to solve then, and a threaded language is. – Martin Bean Jul 22 '15 at 09:07
  • I agree, @MartinBean, but now I can write on PHP and JS only :( – Vlada Katlinskaya Jul 22 '15 at 09:08
  • @MartinBean given the fact one can use threads with PHP, where does that leave us at? – N.B. Jul 22 '15 at 09:11
  • seems like PHP supports Threads now [here](http://stackoverflow.com/questions/209774/does-php-have-threading) – Abdo Adel Jul 22 '15 at 09:15
  • @AbdoAdel “Summary: **experimental** implementation of threads” Emphasis mine. It’s not a core language feature. – Martin Bean Jul 22 '15 at 09:21
  • You can use PCNTL and pcntl_fork specifically. Only available in CLI api. – Matiss Jul 22 '15 at 12:40
  • A job queue is a better idea than what you're doing, it should be an obvious indicator this isn't a good design that you're calling a php process from a php process via a shell. However, the main reason it's not a good idea is **what you're doing won't work** without more fiddling. You'll find that when the php process that calls `shell_exec` ends/dies - so does the exec'ed process. – AD7six Jul 23 '15 at 08:11
  • @AD7six thank you for the input! Could you examine my **EDIT 0** for clarification? – Vlada Katlinskaya Jul 23 '15 at 08:22
  • @VladaKatlinskaya still sounds like a good idea to use a job queue. [Here's laravels docs on job queues](http://laravel.com/docs/5.1/queues) (which I just googled and don't use btw, but the description is clear) which may be a useful reference to see how you could apply that to your workflow. If not now, in the future. – AD7six Jul 23 '15 at 08:28
  • Thanks, @AD7six! Looks interesting. – Vlada Katlinskaya Jul 23 '15 at 08:50

1 Answers1

2

How to get executable

Assuming you're using Linux, you can use:

function getBinaryRunner($binary)
{
    return trim(shell_exec('which '.$binary));
}

For instance, same may be used for checking if needed stuff is installed:

function checkIfCommandExists($command)
{
    $result = shell_exec('which '.$command);
    return !empty($result);
}

Some points:

  • Yes, it will work only for Linux
  • You should be careful with user input if it is allowed to be passed to shell commands: escapeshellarg() and company
  • Indeed, normally PHP should not be used for stuff like this as if it is about asynchronous requests, better to either implement forking or run commands from external workers.

How to pass parameters

With doing shell_exec() via file system path you're accessing the file and, obviously, all "GET" parameters are becoming just part of file name, it is no longer "URI" as there is no web-server to process that. So you have two options:

  • Invoke call via accessing your web-server. So it will be like:

    //Yes, you will use wget or, better, curl to make web-request from CLI
    shell_exec('wget http://your.web-server.domain/script.php?foo=bar');
    

    Downside here: if you'll access your web-server via public DNS, it will cause network gap and all processing overheads. Benefit - obviously, you will not have to expect anything else in your script and make no distinction between CLI and non-CLI calls

  • Use $_SERVER array in your script and pass parameters as it should be with CLI:

    shell_exec('/usr/bin/php /path/to/script.php foo bar');
    
    //inside your script.php you will see:
    //$_SERVER['argv'][0] is "script.php"
    //$_SERVER['argv'][1] is "foo"
    //$_SERVER['argv'][2] is "bar"
    

    Yes, it will require modification in the script, and, probably, some logic of how to map "regular" web-requests and CLI ones. I would suggest even to think of separating CLI-related stuff to different scripts bundle so not to mess that logic.

More about "asynchronous run"

When you do php script.php & you just run it in background mode. That, however, still keeps parent-child relation for your process. That means - if parent process dies, it's childs will also be removed. To be precise, SIGHUP will be triggered and to avoid this situation you should use nohup command. It will allow to emulate "detaching" of a process and therefore making it's run reliable and independent of circumstances happening to parent process.

Alma Do
  • 37,009
  • 9
  • 76
  • 105
  • I feel you're just propagating a bad design with this answer. And neither example will be asynchronous, which is apparently the reason for doing this in the first place. `better to [..] run commands from external worker` - _this_ should be the direction to guide IMO as I commented on the question. – AD7six Jul 23 '15 at 08:14
  • I'm not propagating anything as I do not suggest this way as a preferred one. Still OP asked the question - and depending on circumstances, he might or might not need implementation of forking his script processes. Either way, it is possible to achieve the thing that OP needs with only "pure CLI control" and therefore for some cases this might be valuable info – Alma Do Jul 23 '15 at 08:19
  • @AlmaDo thank you for such detailed answer! I've added **EDIT 0** to originl question for some additional clarification. – Vlada Katlinskaya Jul 23 '15 at 08:23
  • The thing is, the answer to the question as asked is `shell_exec('nohup php /whatever.php args &')` which is only implied by the answer; by that I mean it doesn't _directly_ answer the question anyway. I don't deny the info in the question is useful - _but_ it'll be read in most cases as "has code - copy - paste - it doesn't work" – AD7six Jul 23 '15 at 08:25
  • Well, you have the point in that, but then again, why write detailed answers with explanations :) I'm not a copy-pasta fun and thus I hope that the answer will be read carefully as I tried to provide detailed info. If solve the original problem with parallel processing from the beginning, we can reach the point when it will be - the language itself isn't so good and we need to choose `go lang` for instance. – Alma Do Jul 23 '15 at 08:28