result of php loop not passing to shell script - php

I have a small foreach loop in php but the results will not pass to a shell script. see below:
$contents = file("$target_dir/$user.temp.txt");
foreach($contents as $line) {
echo $line . "<br />";
exec("sh read.sh $line >> tempfile");
}
the echo statement works just fine and displays the data to screen as it should. however the result of $line does not make it to the shell script, but when I replace $line with a random string it does. here is the shell script:
#!/bin/bash
#test script
echo "test output: $1"
when trying to call the shell script with $line in place, the tempfile will get created but is blank. all my permissions are set to 777 and the group calling the script is the same owner as the folder. I've reviewed other posts about php loops but dont seem to find anything that matches exactly what my issue is.
Thanks in advance for any insight.

Needed to add single quotes to $line.
exec("sh read.sh '$line' >> tempfile");

Related

Shell_exec giving different outputs with identical input

I'm trying to return the content of a folder in a Linux enviroment.
To do this I run the code below:
//this line returns folders and files from current folder
$reg = shell_exec ("ls -A");
//in this line I just try to show the info with the desired structure.
$reg = "stat --printf='%n|%s|%s|%F|%y|%a' ".$reg." | numfmt --to=iec-i --field=2 --delimiter='|' --suffix=B";
//This prints the content of $reg
echo $reg;
//I manually input the string returned by $reg and I receive the correct output
echo shell_exec ("stat --printf='%n|%s|%s|%F|%y|%a' .file1 file2 | numfmt --to=iec-i --field=2 --delimiter='|' --suffix=B");
//This just prints the result of "stat --printf='%n|%s|%s|%F|%y|%a' .file1"
echo shell_exec ($reg);
The problem is that the two last "echo" instructions return different outputs given (in theory) identical inputs.
How can I solve this?
When ls detects that it's being piped into another command it writes one file per line, screwing up your command.
You could either replace them with spaces
$reg= str_replace("\n", " ", shell_exec("ls -A"));
or use ls as a substitution
$reg = "stat --printf='%n|%s|%s|%F|%y|%a' $(ls -A) | numfmt --to=iec-i --field=2 --delimiter='|' --suffix=B";

Intercepting standard output / Passing application output (Shell/C/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);

PHP: Backtick failing to work with command

I have a PHP script that retrieves 200 lines from a file by executing a command in Bash using backtick operators. Here's what the code looks like:
$endline = `(shell execution that returns a number here)`;
$line = $endline - "200";
$lines = "sed -n '".$line.", ".$endline." p' log.txt";
echo $lines;
$file = `$lines`;
echo $file;
This code returns $lines as sed -n '1800, 2000 p' log.txt, but $file doesn't return any results. When directly using sed -n '1800, 2000 p' log.txt in a Bash terminal, I get the expected results.
What is done incorrectly here? Do the ' characters have to be escaped?
Edit: The shell script added a space after the number, therefore misreading it.
My guess is that it's $eof or that your path (log.txt) is not appropriate.
I copied and pasted your code, and it works with the following tweaks:
syntax error fixed (add ; to echo $lines)
change $eof to $endline (though you may not need to if $eof is valid
ensure that log.txt was a valid path (this is most likely your error)
otherwise, it ran as expected.
The reason it would work in Bash but not in PHP is that their "working directory" is not necessarily the same.

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.

piping data into command line php?

It is possible to pipe data using unix pipes into a command-line php script? I've tried
$> data | php script.php
But the expected data did not show up in $argv. Is there a way to do this?
PHP can read from standard input, and also provides a nice shortcut for it: STDIN.
With it, you can use things like stream_get_contents and others to do things like:
$data = stream_get_contents(STDIN);
This will just dump all the piped data into $data.
If you want to start processing before all data is read, or the input size is too big to fit into a variable, you can use:
while(!feof(STDIN)){
$line = fgets(STDIN);
}
STDIN is just a shortcut of $fh = fopen("php://stdin", "r");.
The same methods can be applied to reading and writing files, and tcp streams.
As I understand it, $argv will show the arguments of the program, in other words:
php script.php arg1 arg2 arg3
But if you pipe data into PHP, you will have to read it from standard input. I've never tried this, but I think it's something like this:
$fp = readfile("php://stdin");
// read $fp as if it were a file
If your data is on one like, you can also use either the -F or -R flag (-F reads & executes the file following it, -R executes it literally) If you use these flags the string that has been piped in will appear in the (regular) global variable $argn
Simple example:
echo "hello world" | php -R 'echo str_replace("world","stackoverflow", $argn);'
You can pipe data in, yes. But it won't appear in $argv. It'll go to stdin. You can read this several ways, including fopen('php://stdin','r')
There are good examples in the manual
This worked for me:
stream_get_contents(fopen("php://stdin", "r"));
Came upon this post looking to make a script that behaves like a shell script, executing another command for each line of the input... ex:
ls -ln | awk '{print $9}'
If you're looking to make a php script that behaves in a similar way, this worked for me:
#!/usr/bin/php
<?php
$input = stream_get_contents(fopen("php://stdin", "r"));
$lines = explode("\n", $input);
foreach($lines as $line) {
$command = "php next_script.php '" . $line . "'";
$output = shell_exec($command);
echo $output;
}
If you want it to show up in $argv, try this:
echo "Whatever you want" | xargs php script.php
That would covert whatever goes into standard input into command line arguments.
Best option is to use -r option and take the data from the stdin. Ie I use it to easily decode JSON using PHP.
This way you don't have to create physical script file.
It goes like this:
docker inspect $1|php -r '$a=json_decode(stream_get_contents(STDIN),true);echo str_replace(["Array",":"],["Shares"," --> "],print_r($a[0]["HostConfig"]["Binds"],true));'
This piece of code will display shared folders between host & a container.
Please replace $1 by the container name or put it in a bash alias like ie displayshares() { ... }
I needed to take a CSV file and convert it to a TSV file. Sure, I could import the file into Excel and then re-export it, but where's the fun in that when piping the data through a converter means I can stay in the commandline and get the job done easily!
So, my script (called csv2tsv) is
#!/usr/bin/php
<?php
while(!feof(STDIN)){
echo implode("\t", str_getcsv(fgets(STDIN))), PHP_EOL;
}
I chmod +x csv2tsv.
I can then run it cat data.csv | csv2tsv > data.tsv and I now have my data as a TSV!
OK. No error checking (is the data an actual CSV file?), etc. but the principle works well.
And of course, you can chain as many commands as you need.
If you are wanting more to expand on this idea, then how about the ability to include additional options to your command?
Simple!
#!/usr/bin/php
<?php
$separator = $argv[1] ?? "\t";
while(!feof(STDIN)){
echo implode($separator, str_getcsv(fgets(STDIN))), PHP_EOL;
}
Now I can overwrite the default separator from being a tab to something else. A | maybe!
cat data.csv | csv2tsv '|' > data.psv
Hope this helps and allows you to see how much more you can do!

Categories