How to synchronously spawn another PHP script from within a PHP script? - php

I have a terminal application that is currently written in Bash, about 20,000 SLOC. One thing that I like about the way that it's set up is that it is quite modular. Different components are spread across different files, which can be executed at run time. This means that parts of the system can be "hot swapped" or updated during runtime without needing to kill the main program and re-execute it.
The disadvantage is there is a lot of database I/O, which makes it super janky since Bash is really not suited for this. Currently, it interfaces with HTTP APIs which spawn PHP.
I'd like to rewrite it natively in PHP (CLI) to cut out the middleman layer, so the application can communicate directly with the database, making maintenance much easier. One problem I've been pondering though is how to replicate the same modularity with Bash. With Bash, if I call script A, and I make a change to script B, and then I enter script B from script A (assuming it's in a conditional block somewhere, not right at the top of the file), the changes are picked up without needing to re-execute script A, since script B isn't interpreted until it gets executed.
I'm struggling to figure out how to achieve this with PHP. For instance, this will not work:
include('script.php');
The reason is that includes are all executed when the script is interpreted, not when it is executed at run time.
A similar question has been asked already, but it doesn't specifically address this aspect, just how to launch another script in general. I want to basically be able to spawn the script anew at runtime, when the application decides it should be executed. shell_exec and passthru seem to be all that is built into PHP that would be similar, but I'm not sure this is right since that's just spawning another system shell and doing it there, so it's not as "direct" as with Bash.
What would be the proper equivalent in PHP of this in Bash:
if [ "$x" = "3" ]
then
./launchscriptnow.sh
fi
The user should now be executing launchscriptnow.sh. Remember that this is an interactive application, so it's not just doing something and returning a value. The user could be here for 2 seconds, 5 minutes, or an hour.
So that ./launchscriptnow.sh is only interpreted when the code gets to that line, not when the parent script itself is interpreted? Is this kind of thing purely a shell construct or is there an equivalent to this?

I'm don't understand your concern about "when the script is interpreted" vs "when the script is executed"? I have a number of scripts that use a variable name for the script to be included and make that decision right before executing the include statement. $result = include($script_name) will work fine and the decision about which script to include can be made at run time.
The way you describe the problem does not seem to indicate that you want to "launch" another process, but I could be wrong.

Against all recommendations you could:
$script = file_get_contents('module_b.php');
$script = str_replace('<' . '?php', '', $script);
$script = str_replace('?' . '>', '', $script);
eval($script);

Related

Ubuntu (linux in general) How to change name of background process?

When we run the "top" command from command line we can see the processes and under the COMMAND column we see a generic name.
For e,g if I run a php process in the background like
/usr/bin/php /path/to/myscript.php &
I see just php listed under the COMMAND column when I run top.
Is there a way to change the name of the background process when I run it?
*This question is PHP specific.
A process don't really have a name, it has a pid (of type pid_t which is some integer, the result of fork(2) or related system call). Read credentials(7).
And the displayed php name is the right one, it is the one given to execve(2) as the first argument of index 0 and it is the program name. The kernel don't run directly your PHP script, it is running the php interpreter which takes as input your script (so the actual program which is run is php). And your shell command is explicitly giving /usr/bin/php as the program name. You could use strace(1) to check that.
Your shell is displaying (via jobs -l) the background processes. So you could write your own shell to display them differently.
Perhaps you could write in C some wrapper ELF executable which does the appropriate execve(2).
I'm not sure it is worth the trouble. See also proc(5) to understand how applications (like your shell, or ps, or top) are querying the kernel about processes (using /proc/ file-system).
As commented by melopmane, look also into prctl(2) and PR_SET_NAME
(I never used that). I did however use pthread_setname_np(3) which concerns a thread.
(still, I don't think it is worth the trouble in your case; what is wrong with having a PHP process called php?)
See also setproctitle, or write some PHP extension in C to do that...
But you should not care! and I even think that changing that way the name of your process is confusing to the sysadmin. He wants to know that it is some PHP thing. So even if you could abuse your sysadmin, you should not want to.
BTW, you could check (using proc(5)...) with a command like cat /proc/1234/maps (replace 1234 with the actual pid of your process) that the PHP interpreter is an important part of your virtual address space (so there is no reason to "hide" php as you want to), and you could find your specific php process (if you have many of them) using also pgrep(1).

Execute another PHP file without waiting for it to finish its execution

I have StartServer.php file that basically starts a server if it is not already started. Everything works perfect except that the StartServer.php will hang forever waiting for the shell_exec()'d file Server.php to finish its execution that it never does.
Is there a way to execute a PHP file and just forget about it -- and not wait for its execution to finish?
Edit: It has to work on Windows and Linux.
This should help you - Asynchronous shell exec in PHP
Basically, you shell_exec("php Server.php > /dev/null 2>/dev/null &")
You'll need something like the pcntl functions. Only problem is that this is a non-windows extension, and not suitable to run inside a web server. The only other possibility I can think of is to use the exec function and fork the current process manually (as suggested in dekomotes's answer), doing OS detection to figure out the command needed. Note that this approach isn't much different to using the pcntl functions (in Linux, at least) - the ampersand character causes the second script to be run inside different process. Multi-threaded / multi-process programming isn't well supported in PHP, particularly when running inside a web server.
I think it's traditional to let the server detach itself form the parent process, ie to "daemonize" itself, rather than having the script starting the server detach itself. Check the server you're starting to see if it has a daemon-option.
If you've written the server yourself, in PHP, you need to detach it. It looks somehting like this:
posix_setsid(); //Start a new session
if(pcntl_fork()) {exit();} //Fork process and kill the old one
I think this works on Windows too. (Not tested.)

exec function in PHP and passthru?

Hello I have a couple questions about PHP exec() and passthru().
1)
I never used exec() in PHP but I have seen it is sometimes used with imagemagick. I am now curious, what is some other common uses where exec is good in a web application?
2)
About 6 years ago when I first started playing around with PHP I did not really know anything, just very basic stuff and I had a site that got compromised and someone setup there own PHP file that was using the passthru() function to pass a bunch of traffic throught my site to download free music or video and I got hit with a 4,000$ bandwidth charge from my host! 6 years later, I know soo much more about how to use PHP but I still don't know how this ever happened to me before. How can someone beable to add a file to my server through bad code?
1] Exec() is really useful when you:
A) Want to run a program/utility on the server that php doesn't have a command equivalent for. For example ffmpeg is common utility run via an exec call (for all sorts of media conversion).
B) Running another process - which you can block or NOT block on - that's very powerful. Sometimes you qant a pcnt_fork though, or similar, along with the correct CL args for non blocking.
C) Another example is when I have to process XSLT 2.0 - I have to exec() a small java service I have running to handle the transformations. Very handy. PHP doesn't support XSLT 2.0 transformations.
2] Damn that's a shame.
Well, lots of ways. Theres a family of vulnerability called, "remote file include vulns", that basically allow an attacker to include arbitrary source and thus execute it on your server.
Take a look at: http://lwn.net/Articles/203904/
Also, mentioned above, say your doing something like (Much simplified):
exec("someUnixUtility -f $_GET['arg1']");
Well, imagine the attacker does, url.come?arg1="blah;rm -rf /", your code will basically boil down to:
exec("someUnixUtility -f blah; rm -rf /");
Which in unix, you separate commands w/the ; So yeah - that could be a lot of damage.
Same with a file upload, imagine you strip the last four chars (.ext), to find the extension.
Well, what about something like this "exploit.php.gif", then you strip the extension, so you have exploit.php and you move it into your /users/imgs/ folder. Well, all the attacker has to do now is browse to users/imgs/exploit.php and they can run any code they want. You've been owned at that point.
Use exec or when you want to run a different program.
The documentation for passthru says:
Warning
When allowing user-supplied data to be passed to this function, use escapeshellarg() or escapeshellcmd() to ensure that users cannot trick the system into executing arbitrary commands.
Someone had probably found a security hole in your script which allowed them to run arbitrary commands. Use the given functions to sanitise your inputs next time. Remember, nothing sent from the client can ever be trusted.
exec() allows you to use compiled code that is on your server, which would run faster than php, which is interpreted.
So if you have a large amount of processing that needs to be done quickly, exec() could be useful.

How to achieve single-processing mode running php scripts?

I have cron job - php script which is called one time in 5 minutes. I need to be sure that previously called php script has finished execution - do not want to mix data that's being processed.
There are three approaches I used to apply:
Creation of auxiliary text file which contains running-state flag. Executed script analyzes the contents of the file and breaks if flag is set to true. It's the simplest solution, but every time I create such script, I feel that I invented a bike one more time. Is there any well-known patterns or best-practices which would satisfy most of the needs?
Adding UNIX service. This approach is the best for the cron jobs. But it's more time consuming to develop and test UNIX service: good bash scripting knowledge is required.
Tracking processes using database. Good solution, but sometimes database usage is not encouraged and again - do not want to invent a bike, hope there is a good flexible solution already.
Maybe you have other suggestions how to manage single-processing of php scripts? Would be glad to hear your thoughts about this.
I'd recommend using the file locking mechanism. You create a text file, and you make your process lock it exclusively (see php flock function: http://us3.php.net/flock). If it fails to lock, then you exit because there is another instance running.
The advantage of using file locking is that if your PHP scripts dies unexpectedly or gets killed, it will automatically release the lock. This will not happen if you use plain text files for the status (if the script is set to update this file at the end of execution and it terminates unexpectedly, you will be left with untrue data).
http://php.net/flock with LOCK_EX should be enough in your case.
You could check wether or not your script is currently running using the ps command, helped by the grep command. "man ps" and "man grep" will tell you all about these unix/linux commands if you need informations about these.
Let's assume your script is called 'my_script.php'. This unix command :
ps aux | grep my_script.php
...will tell you if your script is running. You can run this command with shell_exec() at the start of your script, and exit() if it's already running.
The main advantage of this method is that it can't be wrong, where the script could have crashed, leaving your flag file in a state that would let you think it's still running.
I'd stick to version number 1. It's simple and works out. As long as you only wan't to check whether the script has finished or not it should be sufficent. If more complex data is to be remembered I'd go for version 3 in order to be able to 'memorize' the relevant data...
hth
K

Don't wait for the process to exit

I have a PHP script that is called from a cron job every minute. This script takes some info from the database and then calls another PHP script using the System function (passing it some parameters).
That means that I can start up to 10 scripts from this "main" one. And what I would like to do is that I would call the script and continue the execution of the main script, that is, not wait for the System call to complete and then call the next one.
How can this be done?
You may be able to use proc_open(), stream_select() and stream_set_blocking() in concert to achieve this kind of thing.
If that sounds vague, I was going to paste a big chunk of code in here that I used in a recent project that did something similar, but then felt it may hinder rather than help! In summary though, the code worked like this:
cronjob calls cronjob_wrapper.php
cronjob_wrapper.php creates a new Manager class and then calls start on it.
Manager class start method check to see how many instances are running (looking for pid files in a particular location). If it's less than a given max number of instances it writes out it's own process id to a pid file and then carries on
Manage class creates an instance of an appropriate Encoder class and calls exec on it.
The exec method uses proc_open, stream_select and stream_set_blocking to run a system command in a non-blocking fashion (running ffmpeg in this case - and could take quite a while!)
When it has finally run it cleans up its PID file and bails out.
Now the reason I'm being vague and handwavy is that our multiple instances here are being handled by the cronjob not by PHP. I was trying to do very much the kind of thing you are talking about, and got something working pretty well with pcntl_fork() and friends, but in the end I encountered a couple of problems (if I recall at least one was a bug in PHP) and decided that this approach was a much more rock-solid way to achieve the same thing. YMMV.
Well worth a look at those functions though, you can achieve a lot with them. Though somehow I don't think PHP will ever become the sockets programming language of choice... :)
If your OS supports it, you can use the pcntl_fork() function to spin off child processes that the parent doesn't wait for. Be careful though, it is easy to accidentally create too many child processes, especially if they take longer than expected to run!
I think the answer would be very similar to those already provided for Asynchronous PHP calls.
http://php.net/pcntl_fork
It's *NIX only but you can fork your script using the PCNTL extension.
I'm not sure that PHP supports threading. Check here.
You could run them in the background:
system('php yourscript.php &');
You just have to make sure that you check on the total number of processes running. All in all, not a super elegant solution. Instead cron you could let one script run for forever, I am thinking something like this:
<?php
while(true) {
// do whatever needs to be done.
}
?>
Careful though. PHP is not exactly known to be used as a daemon.
use php's version of fork or threads.

Categories