PHP - Alternative to shell_exec - php

I am using a PHP script on a local machine connected to an offline server. That server has a webpage on it that processes some homebrewed scripts. This all works fine. However, my setup currently looks something like this
<?php
echo shell_exec(./script1)
echo('Script 1 Done!' .PHP_EOL);
echo shell_exec(./script2)
echo('Script 2 Done!' .PHP_EOL);
echo shell_exec(./script3)
echo('Script 3 Done!' .PHP_EOL);
echo('All Done! .PHP_EOL);
?>
This is fine and works. However, each of these scripts have a ton of output. At seemingly random, arbitrary points in my code, the webpage refreshes and shows that output on a white background. I'm fine with this, except for the random, arbitrary points.
Is it possible to get this to do that in real time? I'm not even sure what to Google for this issue as nothing I've tried has seemed related.

Just capture the output in an array and then you can control when you want to output if you decide to at all.
<?php
$shellOutput = [];
$shellOutput[] = shell_exec('./script1');
$shellOutput[] = shell_exec('./script2');
$shellOutput[] = shell_exec('./script3');
//then when you want to output a simple foreach will do the trick.
foreach($shellOutput as $output){
echo $output;
}
?>

Related

Running A PHP File In Console And Clearing Echoed Results In A Loop?

I have a PHP file that currently runs via my console on my Mac. It's a private piece of software that interacts with an API via a loop that runs every x seconds.
At the minute Im am echoing out all information during each loop but the problem is within console it just repeats the content and appends it on to the previous. Is there a way of clearing all previous echoed results after each loop?
I thought I could use \r to replace the line but that doesn't seem to be working. I have also tried a few other examples after searching on here without any luck.
while(1){
echo "Some info goes here";
sleep(5);
}
For example if I try the following in a while loop
while(1){
echo "==============\r\n";
echo "==============\r\n";
sleep(5);
}
I end up with after a hand full of loops
Thanks
Two ways that I can think of off the top of my head:
Use the ANSI escape sequence to clear the screen:
print chr(27) . "[2J" . chr(27) . "[;H";
Run the command that clears the screen for your platform:
system("cls"); for windows
system("clear"); for unix-like systems
echo "\033[2J\033[;H";
Should clear your terminal.
If you just want to overwrite the same line again, this is working for me:
<?php
while(1) {
echo "test\r";
sleep(1);
}
?>

Does ajax have to wait for a PHP script to finish before displaying the output

I'm using ajax to run a simple PHP script which echos numbers. To test if ajax would display each echo as it happens or if it waits for the whole script to finish before displaying anything.
<?php
echo '1';
sleep(5);
echo '2';
sleep(5);
echo '3';
sleep(5);
echo '4';
sleep(5);
echo '5';
?>
This has shown me that it does wait for the whole script to finish before displaying the numbers.
I would like to know if it is possible to output each echo as it happens, similar to how you would see it in shell?
No that's impossible as the PHP script must run and return it's output before it is supplied to the AJAX request.
No it is not possible to wait for fractial result. But you can use websockets to achieve this behaviour.
For example you can use php library Ratchet or use javascript (or other language) as server.
There are many different ways, techniques and software on how to implement what you need.
Here is a basic and easy example for you: https://github.com/panique/php-long-polling
It is based on a long polling technique.
But I would suggest you to use a centrifu-go with sockJs library for a large projects.

the proper way to run a binary in a separate process without a return value

How can I execute an external binary from within my php code, without the page waiting for a return value before it is sent?
Let me clarify. I have a web application that needs to do some fairly cpu intensive tasks, like a lot of file IO amongst other things. I want my user to be able to initiate their task from the GUI in their browser, but I then want my program to hand the task over to a separate file on my server so my user does not have to sit and wait for all the work to be done and risking timing out his/her connection etc.
Let me show you a simple example of what I have tried:
index.php
<?php
echo "This is a test run for an eternal program: <br><br>";
echo shell_exec("hello");
//ok so we can run executables from php script YAY .. but what about if they are long programs?
//If my script is waiting for a return value surely the connection will time out?
echo "<br><br>";
echo shell_exec("long_run"); //Waits for return value as expected. Further more it
//just does not do the file IO
?>
hello
#!/usr/bin/php5
<?php
echo "hello";
?>
long_run
#!/usr/bin/php5
<?php
$f = fopen("time.txt","a");
$i = 1;
while ($i < 10) {
sleep(2);
echo $i . "<br>";
fwrite($f, $i . " ");
$i++;
}
fclose($f);
?>
Note: I wrote the long_run example in PHP for consistency in reality my program is a binary and needs to interface with the PHP that my actual website is written with.
I have contemplated solving my problem by simply having the PHP save instructions to a file which my binary can scan on a regular basis and act upon. I think this kind of interface would be easy enough to implement it, but as someone with limited experience in PHP and indeed in web projects of this nature generally I would really like to get a better idea of the 'correct' approach to this problem. I'm sure there must be a standard way?
You can achieve it by running your command in background just append & to the command you wich to run.
It will run the binary in a seperate process without a return value
<?php
shell_exec("yourcommand &"); // It will run the 'yourcommand' in backgournd
.... // All further operations will be executed right after the shell exec without waiting for it return value

Open Linux terminal command in PHP

I have a server running on Linux that execute commands to 12 nodes (12 computers with Linux running in them). I recently downloaded PHP on the server to create web pages that can execute commands by opening a specific PHP file.
I used exec(), passthru(), shell_​exec(), and system(). system() is the only one that returns a part of my code. I would like PHP to act like open termainal command in linux and I cannot figure out how to do it!
Here is an example of what is happening now (Linux directly vs PHP):
When using linux open terminal command directly:
user#wizard:/home/hyperwall/Desktop> /usr/local/bin/chbg -mt
I get an output:
The following settings will be used:
option = mtsu COLOR = IMAGE = imagehereyouknow!
NODES = LOCAL
and additional code to send it to 12 nodes.
Now with PHP:
switch($_REQUEST['do'])
{ case 'test':
echo system('/usr/local/bin/chbg -mt');
break;
}
Output:
The following settings will be used:
option = mtsu COLOR = IMAGE = imagehereyouknow!
NODES = LOCAL
And stops! Anyone has an explanation of what is happening? And how to fix it? Only system displays part of the code the other functions display nothing!
My First thought is it can be something about std and output error. Some softwares dump some informations on std out and some in std error. When you are not redirecting std error to std out, most of the system calls only returns the stdout part. It sounds thats why you see the whole output in terminal and can't in the system calls.
So try with
/usr/local/bin/chbg -mt 2>&1
Edit:
Also for a temporary work through, you can try some other things. For example redirect the output to file next to the script and read its contents after executing the command, This way you can use the exec:
exec("usr/local/bin/chbg -mt 2>&1 > chbg_out");
//Then start reading chbg_out and see is it work
Edit2
Also it does not make sense why others not working for you.
For example this piece of code written in c, dumps a string in stderr and there is other in stdout.
#include <stdio.h>
#include<stdlib.h>
int main()
{
fputs("\nerr\nrro\nrrr\n",stderr);
fputs("\nou\nuu\nuttt\n",stdout);
return 0;
}
and this php script, tries to run that via exec:
<?php
exec("/tmp/ctest",&$result);
foreach ( $result as $v )
{
echo $v;
}
#output ouuuuttt
?>
See it still dumps out the stdout. But it did not receive the stderr.
Now consider this:
<?php
exec("/tmp/ctest 2>&1",&$result);
foreach ( $result as $v )
{
echo $v;
}
//output: errrrorrrouuuuttt
?>
See, this time we got the whole outputs.
This time the system:
<?php
echo system("/tmp/ctest 2>&1");
//output: err rro rrr ou uu uttt uttt
?>
and so on ...
Maybe your chbg -mt writes additional code to stderr instead of stdout? Try to execute your script inside php like this:
/usr/local/bin/chbg -mt 2>&1
The other responses are good for generic advice. But in this specific case, it appears you are trying to change your background on your desktop. This requires many special considerations because of 'user context':
First, your web server is probably running as a different user, and therefore would not have permissions to change your desktop.
Second, the program probably requires some environmental variables from your user context. For example, X programs need a DISPLAY variable, ssh-agent needs SSH_AGENT_PID and SSH_AUTH_SOCK, etc. I don't know much about changing backgrounds, but I'm guessing it involves D-Bus, which probably requires things like DBUS_SESSION_BUS_ADDRESS, KONSOLE_DBUS_SERVICE, KONSOLE_DBUS_SESSION, and KONSOLE_DBUS_WINDOW. There may be many others. Note that some of these vars change every time you log in, so you can't hard-code them on the PHP side.
For testing, it might be simpler to start your own webserver right from your user session. (i.e. Don't use the system one, it has to run as you. You will need to run it on an alternate port, like 8080). The web server you start manually will have all the 'context' it needs. I'll mention websocketd because it just came out and looks neat.
For "production", you may need to run a daemon in your user context all the time, and have the web server talk to that daemon to 'get stuff done' inside your user context.
PHP's system only returns the last line of execution:
Return Value: Returns the last line of the command output on success, and FALSE on failure.
You will most likely want to use either exec or passthru. exec has an optional parameter to put the output into an array. You could implode the output and use that to echo it.
switch($_REQUEST['do'])
{ case 'test':
exec('/usr/local/bin/chbg -mt', $output);
echo implode('\n', $output); // Could use <br /> if HTML output is desired
break;
}
I think that the result of execution, can changes between users.
First, try to run your PHP script directly into your terminal php yourScript.php
If it runs as expected, go to your Apache service and update it to run with your own credentials
You are trying to change the backgrounds for currently logged in users... While they are using the desktop. Like while I'm typing this message. I minimize my browser and 'ooh my desktop background is different'. Hopefully this is for something important like it turns red when the reactor or overheating.
Anyway to my answer:
Instead of trying to remotely connect and run items as the individual users. Setup each user to run a bash script (in their own account, in their own shell) on a repeating timer. Say every 10 minutes. Have it select the SAME file.. from a network location
/somenetworkshare/backgrounds/images/current.png
Then you can update ALL nodes (1 to a million) just by changing the image itself in /somenetworkshare/backgrounds/images/current.png
I wrote something a while ago that does just this -- you can run a command interpreter (/bin/sh), send it commands, read back responses, send more commands, etc. It uses proc_open() to open a child process and talk to it.
It's at http://github.com/andrasq/quicklib, Quick/Proc/Process.php
Using it would look something like (easier if you have a flexible autoloader; I wrote one of those too in Quicklib):
include 'lib/Quick/Proc/Exception.php';
include 'lib/Quick/Proc/Exists.php';
include 'lib/Quick/Proc/Process.php';
$proc = new Quick_Proc_Process("/bin/sh");
$proc->putInput("pwd\n");
$lines = $proc->getOutputLines($nlines = 10, $timeoutSec = 0.2);
echo $lines[0];
$proc->putInput("date\n");
$lines = $proc->getOutputLines(1, 0.2);
echo $lines[0];
Outputs
/home/andras/quicklib
Sat Feb 21 01:50:39 EST 2015
The unit of communication between php and the process is newline terminated lines. All commands must be newline terminated, and all responses are retrieved in units of lines. Don't forget the newlines, they're hard to identify afterward.
I am working on a project that uses Terminal A on machine A to output to Terminal B on Machine B, both using linux for now. I didnt see it mentioned, but perhaps you can use redirection, something like this in your webserver:
switch($_REQUEST['do'])
{ case 'test':
#process ID on the target (12345, 12346 etc)
echo system('/usr/local/bin/chbg -mt > /proc/<processID>/fd/1');
#OR
#device file on the target (pts/0,tty0, etc)
echo system('/usr/local/bin/chbg -mt > /dev/<TTY-TYPE>/<TTYNUM>');
break;
}
Definitely the permissions need to be set correctly for this to work. The command "mesg y" in a terminal may also assist...Hope that helps.

Printing / Echoing To Console from PHP Script

I'm debugging a PHP script that runs a couple SQL queries and emails a set of users. I'm sure this is a very basic thing, but every time I try to echo, print, or print_r it doesn't appear while running the script.
So say I have this in the script:
print("This should print");
echo "on the command line";
When I run the script via command line php script.php it doesn't actually print anything to the command line while running the script.
Is there a way of having PHP print to console? I feel like I'm missing something extremely basic here.
Thats the method of doing it.
Things to check for are output buffering
http://php.net/manual/en/function.ob-flush.php
Is that code actually being run ? Make sure it doesnt branch before it gets there
A good approach could be:
function log($message)
{
$message = date("H:i:s") . " - $message - ".PHP_EOL;
print($message);
flush();
ob_flush();
}
It will output to your terminal each line you call. Just use :
log("Something");
log("Another line");
The following code working fine for me.
<?php
print("This should print");
echo "on the command line";
?>
with tags.
I know it is old, but I am going post my own solution to this just in case if someone would run into similar situation. I had a problem that a legacy command line PHP script wouldn't print or echo anything to the terminal when DSN is incorrectly configured and the script got stuck for very long time (not sure how long, never waited for it to terminate by itself). After putting ob_end_flush() in the entry line of the script, the output came back to the terminal. So it turned out that all output was buffered and since the script stuck at some point, the output stayed buffered and so never went to the terminal.

Categories