Intercepting standard output / Passing application output (Shell/C/PHP) - php

I am running a hybrid of shell script and a C application to allow execution as root. I am using it to do some conversions with FontForge from the website that is written in PHP. My problem is that when FontForge encounters some problems its spewing error information out to standard output. I am currently capturing that output and parsing it for keywords to generate some error messages.
Q: I am wondering if I can somehow redirect that output to some variable and pass it back to PHP for processing - as long as current solution works fine under browser, unfortunately when I run unit tests I get pages of failed glyph mapping information that does nothing but obscures the results. I would like to bypass std_out entirely.
I am not very very familiar with either C or shell scripting so please do not laugh :). Here is what I have:
PHP:
[...]
$new_path = exec("./convert_font " . $file . " " . $file2);
if (strpos($new_path, 'Save Failed') !== false) {
// throw exception or something
}
[...]
Script (convert_font):
#!/bin/bash
PATH=/usr/local/bin:$PATH
FONTFORGE_LANGUAGE=ff
export PATH FONTFORGE_LANGUAGE
if (test -f $1);
then
a=$(./pfb2otf $1 $2 2>&1)
fi
echo $a
C (pfb2otf):
#!/usr/bin/fontforge
//Opens file
Open($1);
Reencode("unicode");
//Makes conversion to otf
Generate($2+".otf");
//Prints the resulting name (if conversion is successful) to STD_OUT so I can capture it with my bash script to send back to PHP and consider operation successful to
Print($2+".otf");
Quit(0);

http://php.net/manual/en/function.exec.php
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().
You can use the additional output parameter in your PHP Code to catch all stdout messages to an array. You can also redirect stderr to stdout in both perl and C
http://www.masaokitamura.com/2009/08/how-to-redirect-stderr-to-stdout-in-perl/
Hope this helps.

There are 3 things to note :
1) Your program writes probably errors on error output, to get them too you need to add 2>&1
$new_path = exec("./convert_font " . $file . " " . $file2 . ' 2>&1');
2) exec() returns only the last line of the command execution, the safest way to get your return values is to pass a second argument to your exec().
$return = array();
exec("./convert_font " . $file . " " . $file2 . ' 2>&1', $return);
You may note that $return is a multidimentional array with 1 line / entry. So to be sure you get your error into this array, you may do :
$new_path = implode("", $return);
3) do not forget to use escapeshellarg in case where one of your file has spaces (at least) or back quotes/parenthesis/dollar (...everything a shell can interpret).
$return = array();
exec("./convert_font " . escapeshellarg($file) . " " . escapeshellarg($file2) . ' 2>&1', $return);

Related

Does PHP shell_exec add parentheses to the command?

I'm trying to run a cat command using the shell_exec function, to be more precise something like this:
cat <(echo "foo") bar.xml > foo-bar.xml
But I'm getting a syntax error like the following one:
sh: 1: Syntax error: "(" unexpected
I'm completely lost since this works fine locally and when the command is executed manually in the server, but when running the php script it returns the syntax error. Any clues?
Original code being used:
$shell_cmd = "cat <(echo \"{$this->xmlHeader}\") ";
$shell_cmd .= '\'' . $path . $filename . '\'' . " ";
$shell_cmd .= " > " . '\'' . $path . "hfb/" . strtolower(str_replace($this->replace_values, '', $hfbName)) . ".xml" . '\'';
shell_exec($shell_cmd);
The problem here is likely to be which shell is used. It's not really documented, but I believe shell_exec will use /bin/sh, which will often be a minimal Posix-compliant shell (or a more complex shell emulating that compliance). That's very useful, because it means system scripts will always work the same way, regardless of what other shells are installed or configured for particular users.
When you log in directly, however, you're probably using bash, which has extra features such as the <(...) syntax for getting a named file descriptor from a command.
The best approach in this case is to make your command use only standardised facilities, which will be available in /bin/sh.
In particular, you are using cat to glue together a literal string from echo and a file:
cat <(echo "foo") bar.xml
That can be expressed instead by first echoing the string, and then outputting the file:
echo "foo"; cat bar.xml
To gather both into one output, place them in braces:
{ echo "foo"; cat bar.xml; } > foo-bar.xml
Alternatively, you can give cat an argument of - to concatenate standard input with one or more other files, so you could pipe the value from echo into it:
echo "foo" | cat - bar.xml > foo-bar.xml

How to check bash shell finished in php

I am having difficulty processing bash shell in php.
My problem is as below.
I have 3 tasks corresponding to 3 files bash shell (task1.sh, task2.sh, task3.sh). When task1.sh finishes processing, task2.sh will automatically execute, when task2.sh finishes processing, task3.sh will automatically execute.
Initially, I wrote a file called task.sh and embedded task1.sh, task2.sh, task3.sh into it. But I want to embed these 3 tasks into a php file.
For example: I create task.php and do the following:
If task1.sh fails, it will display popout (alert) error message.
If task1.sh processing is complete then task2.sh will continue to be automatically done.
The processing of task2.sh and task3.sh is similar to the above.
All 3 tasks I want to run backgroud. The problem is that when I run the background bash shell, I will not be able to check the failed error statement (the result always returns to 0).
I have learned a lot and consulted many documents but it did not help me.
I hope you can support me.
Sorry, my english very poor.
You may use the $retval argument of exec().
<?php
exec('task1.sh', $output, $retval);
if ($retval !== 0) {
// task 1 failed
exit('Error running task1: ' . implode("<br/>\n", $output));
}
exec('task2.sh', $output, $retval);
if ($retval !== 0) {
// task 2 failed
exit('Error running task1: ' . implode("<br/>\n", $output));
}
exec('task3.sh', $output, $retval);
if ($retval !== 0) {
// task 3 failed
exit('Error running task1: ' . implode("<br/>\n", $output));
}
You can simply use the function:
exec ( string $command [, array &$output [, int &$return_var ]] ) : string
With:
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.
Thus you could use $output and $result_var to check the execution errors of your shells.
Regards

Executing a Python script to return a value in PHP

I've read a lot of answers on here regarding this but I still haven't been able to figure it out. I have some PHP code that is trying to execute a Python script while the PHP also passes the Python some arguments, and then I want the Python to do something and return a value to the PHP.
I've tried it this way:
$url = "URL given";
$retailer = "other string";
$price = system("/usr/local/bin/python3 /full/path/script.py '" . $url . "' '" . $retailer . "'", $retval);
sleep(5);
print "Price: " . $price;
With the Python code (where the function being called prints the value):
def main():
getPrice(sys.argv[1], sys.argv[2])
main()
And the $price variable doesn't return anything even though if I run the command thats inside system() in Terminal it prints the value out fine.
I've also tried:
exec("/usr/local/bin/python3 /full/path/script.py", $output, $ret_code);
sleep(5);
print "Price: " . $output[0];
But in this case I've tried it the way above where the Python simply prints "hi" instead of passing the arguments through and I still get nothing, as well as trying it the way with passing the args in from earlier.
I can't tell if maybe the Python isn't being called, or perhaps it is and it returns nothing for some unknown reason but if anyone may know the issue here I would love to hear your thoughts

PHP exec doesn't return output of external program

I've the following program:
function execute_query($ip, $username, $password, $query){
$runCMD ="python run_query.py " . escapeshellarg($ip). " ". escapeshellarg($username) . " " . escapeshellarg($password)
. ' ' . escapeshellarg($query);
$output = [];
exec ($runCMD, $output);
print_r ($output);
//return (implode("\n", $output));
}
However the array $output is always empty, the program is returning the result correctly, when executed manually from CMD. I've no idea what to do. I tried so many things that I even don't recall all of them. Here are a few:
1.I disable UAC
2.I tried using shell_exec
3.I tried appending powershell in front of the command 'powershell' . $runCmd
4.I tried appending '2>&1' at the end of the command
5.I tried using proc_open, to manually open cmd.exe and execute the command
Any other ideas what I may do, or at least how to continue troubleshooting. Using Linux is not an option
It seems like stderr is working. Also i tried printing 'asd' from the python script and it's working.
The output from the python script is WMI query, it may contain \n, \r and \t
Here is the python script:
from subprocess import check_output
import sys
def run_query(ip, username, password, query):
runCMD = "query.exe " + username + " " + password + ' "' + query + '" ' + ip + ''
results = check_output(runCMD).decode("utf-8")
results = results.split("\n")
for result in results:
if not result.startswith("__"):
print(result)
if __name__ == "__main__":
run_query(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])
UPDATE 1
query.exe is a program, which returns filtered result from WMI query, passed as argument. No idea what's inside but it's working as expected. I also tried running query.exe from the php script, the same thing no output. UPDATE 2 I'm using php 7.1, tried php 5.6 without luck.
UPDATE 3
When I try to change the string into byte array in python I get this output when the script is manually runned:
bytearray(b'The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)\r')
bytearray(b'')
, but the php script returns this:
Array
(
[0] => bytearray(b'')
)
UPDATE 4
f*** it I'm switching the whole project to python

PHP Put list from Powershell into Array

Code:
$exchangesnapin = "Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010";
$output = shell_exec('powershell '.$exchangesnapin.';"get-mailboxdatabase" 2>&1');
echo( '<pre>' );
echo( $output );
echo( '</pre>' );
Result:
Name Server Recovery ReplicationType
---- ------ -------- ---------------
Mailbox Database 0651932265 EGCVMADTEST False None
Mailbox Database 0651932266 EGCVMADTEST False None
I tried with
echo( $output[1] );
The result was only a letter 'N'. I believe its taking the Name column but one character at a time.
$output[1] is 'N', $output[2] is 'a'.
Is there any way I can get the mailbox list into array?
you are trying to execute an external program (powershell) from PHP and have the output as an array.
In order to execute an external program in PHP, you could use:
exec() function
shell_exec() function
system() function
backtick operator
process control extensions
using process control extensions (PCNTL, popen) gives you more control, but takes more code and time. using the execution functions are simpler.
In this situation, using exec() could help you to have the output of powershell in an array whose each index is a line from the powershell output.
<?php
$output = array(); // this would hold the powershell output lines
$return_code = 0; // this would hold the return code from powershell, might be used to detect execution errors
$last_line = exec("powershell {$exchangesnapin} get-mailboxdatabase 2>&1", $output, $return_code);
echo "<pre>";
// print_r($output); view the whole array for debugging
// or iterate over array indexes
foreach($output as $line) {
echo $line . PHP_EOL;
}
echo "</pre>";
?>
Please note that (as the documentation says) if you only want to echo the output of powershell, you could use the passthru() function. using exec() uses memory to store the output of the external program, but using passthru would not use this storage, resulting in less memory usage. But the output could not be used for further processing, and is sent to the PHP standard output right a way.
In the end, please note that external program execution requires careful data validation to reduce the risk of unwanted system effects. Make sure you use escapeshellarg() on the data that constructs the execution command.

Categories