Does PHP support process substitution? - php

I've trying the following examples such as:
$ php -r 'require_once($argv[1]);' <(echo "hello")
or:
$ php -r 'file_get_contents($argv[1]);' <(echo "hello")
both fails like:
PHP Warning: require_once(/dev/fd/63): failed to open stream: No such file or directory in Command line code on line 1
PHP Warning: file_get_contents(/dev/fd/63): failed to open stream: No such file or directory in Command line code on line 1
or:
$ php -r 'file_get_contents($argv[0]);' < <(echo "hello")
which fails with:
PHP Fatal error: require_once(): Failed opening required '-' (include_path='.:/usr/share/pear:/usr/share/php') in Command line code on line 1
The above attempts were inspired by drush command, for example:
$ drush --early=<(echo print 123';') ""
[warning] require_once(/dev/fd/63): failed to open stream: No such file or directory preflight.inc:58
where I could inject the dynamic PHP code from the file descriptor (without creating a separate file each time) in order to execute the code before bootstrapping the main code.
Other similar command tools works correctly:
$ cat <(echo "hello")
hello
or:
$ python -c "import sys; print sys.stdin.readlines()" < <(echo "hello")
['hello\n']
I've found this PHP bug and this one, but these has been fixed long time ago and I'm using 5.6.22.
Is there any way that I can trick PHP into reading data from the process substitution (to read from file descriptor , e.g. /dev/fd) when called from CLI, by using some simple one-liner?

The error message gives a good hint: PHP cannot find the given file.
But wait, what file? Well, let's remember what process substitution is:
Process substitution is a form of redirection where the input or output of a process (some sequence of commands) appear as a temporary file.
And so you see when you print the argument you are providing this way:
$ php -r 'print $argv[1];' <(echo "a")
To me it returns the following temporary file:
/dev/fd/63
So yes, you can use process substitution with PHP, but not for this.
If what you want is to use the output of the command as an argument, just use $() to expand it:
$ php -r 'print $argv[1];' "$(echo "hello man")"
hello man

Related

How to pass bash script variable value in PHP command (CLI)

I need help in passing the Linux bash-script variable to execute the PHP CLI command.
I am working on the bash-script that executes PHP CLI command that gets input variable from the bash-script like folder-path to include a file for accessing a class of the PHP file.
But what happens while executing the bash-script is that the variable passed to the PHP CLI-command act as a variable for PHP.
Below is the sample-code my script
file="$folderpath"somefile.php
mage_version=$(php -r 'include "$file";print_r(Mage::getVersionInfo());')
Below is the error I am getting
PHP Notice: Undefined variable: file in Command line code on line 1
PHP Warning: include(): Filename cannot be empty in Command line code on line 1
Bash needs double (") quotes to parse variable, otherwise they will stay $var and so php will read them;
file="$folderpath"somefile.php
mage_version=$(php -r "include \"${file}\";print_r(Mage::getVersionInfo());")
More inline bash info
If you need a multi line solution, you can do something like: Run PHP function inside Bash (and keep the return in a bash variable)
php_cwd=`/usr/bin/php << 'EOF'
<?php echo getcwd(); ?>
EOF`
echo "$php_cwd" # Or do something else with it

require_once doesn't work in command line

php /home/test9/public_html/degerlendir/test-4567.php "var1=18&var2=22"
I need to run one page at background with cron job. I tested my code with command at above. But I get this error:
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/extensions/no-debug-non-zts-20100525/imagick.so' - /usr/lib64/extensions/no-debug-non-zts-20100525/imagick.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning: require_once(../config.php): failed to open stream: No such file or directory in /home/test9/public_html/degerlendir/test-4567.php on line 2
PHP Fatal error: require_once(): Failed opening required '../config.php' (include_path='.:/usr/lib64/php') in /home/test9/public_html/degerlendir/test-4567.php on line 2
The problem is page doesn't include config.php in the parent directory. The page working in browser normally. I tried to use different require_once variations like require_once ($_SERVER['DOCUMENT_ROOT']."/config.php"). I could not get it to work.
from the command line there is no $_SERVER['DOCUMENT_ROOT']. That one is only available from the http-server (Apache).
The working directory will not be automatically set. If you prompt is currently at /some/path/ the script will try to find config.php in /some/config.php.
Try cd to the current path by using __DIR__ in the start of your script
<?php chdir(__DIR__); ?>
Cron jobs always take full path of the included file from your root.
/home/test/.../your-file
In your cron job, you need to cd to the correct working directory to allow your PHP file to find it's includes. I do this by creating small shell scripts, and run the shell scripts from cron:
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd ${DIR}
php test-4567.php
exit 0
This also gives you the ability to do some useful things like checking to see if the script is already running to make sure you don't spin up multiple threads if that's something you want to avoid.
#!/bin/bash
FIND_PROC=`ps -ef |grep "php test-4567.php" | awk '{if ($8 !~ /grep/) print $2}'`
# if FIND_PROC is empty, the process has died; restart it
if [ -z "${FIND_PROC}" ]; then
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd ${DIR}
php test-4567.php
fi
exit 0

Shell heredoc inside php heredoc

I have something similar to this in a php script:
<?php
...
function log() {
// saving the log into a file.
exec(<<<BASH
cat >> $logFile <<EOF
$log
EOF
BASH
);
}
...
As you can see the two heredocs (BASH is php and EOF is shell) end as one would think is correct, but when I read the log created the log has something like this:
...
my logged string of an important event
EOF
my logged string of another important event
EOF
...
And I check the apache log and it has the following entries:
sh: line 1: warning: here-document at line 0 delimited by end-of-file (wanted `EOF')
What am I doing wrong?
Please, I am aware that there are many other implementations, such as using php functions or using quotes instead of heredocs. But I am curious about why in this particular case this does not work.
EDIT.
I clarified the code so it is more clear that I am talking about php running shell commands.
Updated answer for PHP case
Suppose we have test.php file with the following contents:
<?php
function mylog() {
$logFile = 'test.log';
$log = 'test';
exec(<<<BASH
cat >> $logFile <<EOF
$log
EOF
BASH
);
}
mylog();
Then php test.php produces the right thing(!):
rm -f test.log
php test.php
cat test.log
Output:
test
Now let's indent the Bash part:
<?php
function mylog() {
$logFile = 'test.log';
$log = 'test';
exec(<<<BASH
cat >> $logFile <<EOF
$log
EOF
BASH
);
}
mylog();
Now php test.php produces exactly what you've written about in your
question:
rm -f test.log
php test.php
cat test.log
Output:
sh: line 2: warning: here-document at line 0 delimited by end-of-file (wanted `EOF')
test
EOF
Apparently, you have your Bash part indented, which is an invalid Bash syntax. So you just need to remove indentation for the Bash part. At least, EOF shouldn't be indented.
Original answer where I thought the OP meant pure Bash
exec executes a command, but you need to evaluate bash expression. So you need eval instead.
To construct the command using eval use the following:
eval "$(
cat <<'EOF'
cat >> test.log <<EOF2
log contents
EOF2
EOF
)"
So we constructed a Bash variable with "$( and )". Within the variable we created a here-doc string with cat <<'EOF' and EOF, where single quotes disable parameter substitution so we can enter literal text.(no evaluation). Then we've written log contents by means of another here-doc string created with <<EOF2 and EOF2.
We might save save the Bash variable, then use it as many times as we like:
cmd="$(
cat <<'EOF'
cat >> test.log <<EOF2
log contents
EOF2
EOF
)"
rm test.log
eval "$cmd"; eval "$cmd"; eval "$cmd"
cat test.log
Output:
log contents
log contents
log contents
See docs for here documents.

Add current date to PHP command line argument

I'm trying to use PHP command line (from cron tab). I know how to add arguments like this:
cd /home/users/public_html/; php -f script.php some_value
I would like (or need) to add current date dinamically:
cd /home/users/public_html/; php -f script.php current_date
With wget I did this:
wget "https://mysitecom/script.php?currentdate=`date +\%s.\%N`"
But I can not find any way to do something similar wih a php command line.
I've tried:
cd /home/users/public_html/; php -f script.php `date+\%s.\%N`
And I get the error "Command not found".
I've tried also the solution proposed in one answer:
cd /home/users/public_html/; php -f script.php date+\%s.\%N
And I get the literal string "date+\%s.\%N"
With the other proposed solution:
cd /home/users/public_html/; php -f script.php "$(date +"%s.%N")"
I get these errors in the email sent by the cron:
/usr/local/cpanel/bin/jailshell: -c: line 0: unexpected EOF while looking for matching `"'
/usr/local/cpanel/bin/jailshell: -c: line 1: syntax error: unexpected end of file
When using PHP from the command line (CLI) they are not called GET variables they are called arguments
There are 2 parameters passed to every script run from the command line called $argv and $argc
One thing to remember the first argv[0] occurance holds the name of the script that is being run. Other than that the arguments appear in $argv[] in the order thay appear on the command line
argc is a count of how many variables have been passed to the script
arcv is an array of all the variables passed
If its any help they are just like the "C" equivalents if you have ever written any "C" code
ADDITIONAL INFO
To call your script with todays date use something like this
cd /home/users/public_html/; php -f script.php "$(date +"%s.%N")"
adjust the format as required.
Although if you want todays date in the script I am not sure why you would not get that from within the PHP script itself.
Finally I've made it work. It was a syntax error:
This:
cd /home/users/public_html/; php -f script.php `date+\%s.\%N`
Need to be:
cd /home/users/public_html/; php -f script.php `date +\%s.\%N`

How to avoid "ls: write error: Broken pipe" with php exec

In PHP I am running this command:
exec ("ls -U ".$folder." |head -1000", $ls_u);
This command is inside a PHP file, run directly by PHP on the console and throws this error:
ls: write error: Broken pipe
What causes this error? Or is using pipes in PHP exec not a good idea?
In Linux with PHP on the terminal, you can reproduce this error with this code:
main.php:
<?php
$process = popen("ls", "r");
pclose($process);
?>
Then running it like this on the terminal:
eric#dev ~ $ php main.php
ls: write error: Broken pipe
The error happens because you are running a command which returns data and you are not catching it, so it complains about a broken pipe.
I was able to fix it like this:
<?php
$handle = popen('ls', 'r');
$read = fread($handle, 2096);
pclose($handle);
echo $read;
?>
Then it works, printing:
eric#dev ~ $ php main.php
main.php
anotherfile.txt
Note, you'll have to stick the fread(...) in a loop if you want to get all the output from ls.
I believe there's a syntax error in the console command, and suggest escaping the arguments with escapeshellarg().
exec('ls -U '.escapeshellarg($folder).' | head -1000', $ls_u);

Categories