I have a PHP file that runs a node script using exec() to gather the output, like so:
$test = exec("/usr/local/bin/node /home/user/www/bin/start.js --url=https://www.example.com/");
echo $test;
It outputs a JSON string of data tied to the website in the --url paramater. It works great, but sometimes the output string is cut short.
When I run the command in the exec() script directly, I get the full output, as expected.
Why would this be? I've also tried running shell_exec() instead, but the same things happens with the output being cut short.
Is there a setting in php.ini or somewhere else to increase the size of output strings?
It appears the only way to get this working is by passing exec() to a temp file, like this:
exec("/usr/local/bin/node /home/user/www/bin/start.js --url=https://www.example.com/ > /home/user/www/uploads/json.txt");
$json = file_get_contents('/home/user/www/uploads/json.txt');
echo $json;
I would prefer to have the direct output and tried increasing output_buffering in php.ini with no change (output still gets cut off).
Definitely open to other ideas to avoid the temp file, but could also live with this and just unlink() the file on each run.
exec() only returns the last line of the output of the command you pass to it. Per the section marked Return Value of the following documentation:
The last line from the result of the command. If you need to execute a command and have all the data from the command passed directly back without any interference, use the passthru() function.
To get the output of the executed command, be sure to set and use the output parameter.
https://www.php.net/manual/en/function.exec.php
To do what you are trying to do, you need to pass the function an array to store the output, like so:
exec("/usr/local/bin/node /home/user/www/bin/start.js --url=https://www.example.com/", $output);
echo implode("\n", $output);
Related
I just cannot fathom how to get the PHP exec() or shell_exec() functions to treat a '*' character as a wildcard. Is there some way to properly encode / escape this character so it makes it through to the shell?
This is on windows (via CLI shell script if that matters, Terminal or a git-bash yields the same results).
Take the following scenario:
C:\temp\ contains a bunch of png images.
echo exec('ls C:\temp\*');
// output: ls: cannot access 'C:\temp\*': No such file or directory
Permissions is not the problem:
echo exec('ls C:\temp\exmaple.png');
// output: C:\temp\example.png
Therefore the * character is the problem and is being treated as a literal filename rather than a wildcard. The file named * does not exist, so from that point of view, it's not wrong...
It also does not matter if I use double quotes to encase the command:
echo exec("ls C:\temp\*");
// output: ls: cannot access 'C:\temp\*': No such file or directory
I have also tried other things like:
exec(escapeshellcmd('ls C:\temp\*'));
exec('ls C:\temp\\\*');
exec('ls "C:\temp\*"');
exec('ls "C:\temp\"*');
And nothing works...
I'm pretty confused that I cannot find any other posts discussing this but maybe I'm just missing it. At this point I have already worked around the issue by manually programming a glob loop and using the internal copy() function on each file individually, but it's really bugging me that I do not understand how to make the wildcard work via shell command.
EDIT:
Thanks to #0stone0 - The answer provided did not particularly answer my initial question but I had not tried using forward slashes in the path and when I do:
exec('ls C:/temp/*')
It works correctly, and as 0stone0 said, it only returns the last line of the output, which is fine since this was just for proof of concept as I was not actually attempting to parse the output.
Also, on a side note, since posting this question my system had been updated to Win11 22H2 and now for some reason the original test code (with the backslashes) no longer returns the "Cannot access / no file" error message. Instead it just returns an empty string and has no output set to the &$output parameter either. That being said, I'm not sure if the forward slashes would have worked on my system prior to the 22H2 update.
exec() only returns the last output line by default.
The wildcard probably works, but the output is just truncated.
Pass an variable by ref to exec() and log that:
<?php
$output = [];
exec('ls -lta /tmp/*', $output);
var_dump($output);
Without any additional changes, this returns the same as when I run ls -lta /tmp/* in my Bash terminal
That said, glob() is still the preferred way of getting data like this especcially since
You shouldn't parse the output of ls
I have a C code that I have to execute through PHP,
I have used exec('./sys'), sys is my executable file.
I have also tried system(), passthrough(), shell_exec() and they are not giving output.
When I executed exec('who'); it gives the output.
What can I do to execute sys?
Each of those methods you reference will execute your sys file, but you need to make sure you are executing the correct path. Your working path is determined by what script is actually executing PHP. For example, if you're executing your code through apache or the command line your working directory may be different. Lets assume this file structure:
+ src/
| + script.php
| + sys
I would recommend using PHP's __DIR__ magic variable in your script.php to always reference the current file's directory, and then work from there:
// script.php
exec(__DIR__ . "/sys");
Retrieving output can be done a couple different ways. If you want to store the output of the script in a variable, I would recommend using exec according the the manual:
Parameters ΒΆ
command
The command that will be executed.
output
If the output argument is present, then the specified array will be filled with every line of output from the command. Trailing whitespace, such as \n, is not included in this array. Note that if the array already contains some elements, exec() will append to the end of the array. If you do not want the function to append elements, call unset() on the array before passing it to exec().
return_var
If the return_var argument is present along with the output argument, then the return status of the executed command will be written to this variable.
exec will return the first line of output, but if you want more than that you need to pass a variable by reference:
// script.php
$output = array();
exec(__DIR__ . "/sys", $output);
$output will then contain an array of each line of output from the command. However if you want to run your sys script and directly pass through the output then use passthru(__DIR__ . "/sys"); For example, if you wanted to execute a command that required input on the command line, passthru would be the best option.
I used php shell_exec to run BLAST command (biologcal sequence alignment tool) and outputs the result in browser. However, I am not able to format the result same like it displayed when I run the same command in terminal . I tried using methods like passthru() and exec(). Both of it doesnt work! In my case, output formatting is important as a small space can make the error (a portion is give below). Can anyone tell me how to display the result in browser as exactly which in command terminal.
$cmd = "$blast -query /var/www/html/kim/blast/testing.txt -db /var/www/html/kim/blast/$db";
$result =shell_exec($cmd);
print_r ($result);
Part of my output looks like,
Query 707 TCAGACTTGAA 766
|||||||||||
Sbjct 3632 TCAGACTTGAA 3691
In order to keep formatting identical, including spaces etc., you should use the <pre> html element. An example:
echo '<pre>';
echo $result;
echo '</pre>';
Just echo the raw result. Using print_r or var_dump would lead to formatting by PHP. The above example is the most raw formatting you can achieve, given you leave result untouched.
With CSS you can then style the <pre>. But make sure to use a MONOSPACE font so that shell formatting is kept.
So I need to found out if an upload from a user is images/ video and what type. I currently use
"filetype"=>system("file -i -b ".$_FILES['file']['tmp_name'])
which is inserted into my MongoDB collection via this
$s3file='http://'.$bucket.'.s3.amazonaws.com/'.$actual_image_name;
$collection = static::db()->media;
$datetime = time();
$mediaupload = array("owner"=>$_SESSION['user_information'][0]['_id'],"filelink"=>$s3file,"filetype"=>system("file -i -b ".$_FILES['file']['tmp_name']),"filesize"=>$size,"uploadtime"=>$datetime,"ownerid"=>$_SESSION["user_information"][0]['_id']);
$collection->insert($mediaupload);
$media = $collection->findOne($mediaupload);
However what I am noticing is it echos the result out to the PHP page - which is not what I need it to do. i know it is the system function because when I remove that function it does not echo the uploaded file type to the php code.
I am wondering therefor how can i still run that system file -i -b function and get it to include into the MongoDB database but not echo the result into the public php page return.
Try something like (for multi-line output)
exec("file -i -b ".$_FILES['file']['tmp_name'], $output);
array("filetype"=>$output);
It may look a little unorthodox, but exec uses its second input parameter as a way to pass the output information back to you - the output of file will be stored as an array into $output.
From the docs:
If the output argument is present, then the specified array will be
filled with every line of output from the command. Trailing
whitespace, such as \n, is not included in this array. Note that if
the array already contains some elements, exec() will append to the
end of the array. If you do not want the function to append elements,
call unset() on the array before passing it to exec().
If you simply want the first line from the output, use the simpler version:
array("filetype"=>exec("file -i -b ".$_FILES['file']['tmp_name']));
I have switched the system to exec() and that seems to of fixed my issue
I currently have a php page that my webserver serves. In order to display all the information I need to display on the page I need output from an external python script. So I have been using the exec() command of php to execute the python script and capture the output in an array of strings as follows:
$somequery = $_GET['query'];
$result = exec("python /var/www/html/query/myscript.py ".somequery."");
//some for loop to loop through entries in result and echo them.
However there are never any entries to be printed, yet when I run the command directly on the console of the server it will output correctly. I've tried echoing out the command on the webpage that I am executing and it's the correct command. The only thing I think it can be is that exec() doesn't stop the rest of the php program from executing before it finishes, leading to the loop i have printing out entries finding that $result is empty.
How can I ensure that exec() finishes executing before the rest of my php script? Are there maybe settings in php.ini that I would need to change? I'm not entirely sure.
EDIT: I've tried running and storing the output of shell_exec("echo hello"); and printing that output, it now prints. However, when running my command that takes a few seconds longer, the program never finishes executing it before going to the next line.
EDIT 2: I found my solution in the following post https://stackoverflow.com/a/6769624 My issue was with with the numpy python package I was using and I simply needed to comment out the line in /usr/lib64/python2.7/ctypes/init.py like the poster did and my script output correctly.
The correct way to get your shell output is like this:
exec("python /var/www/html/query/myscript.py ".somequery."", $result);
var_dump($result); //output should be in here
Give it a try.