php CLI mode -f flag - php

I was reading about specifics of PHP in CLI mode and I can't explain for myself what utility has -f flag.
It's possible execute any php script as "php name_of_script.php" or "php -f name_of_script.php"
I guess this option is just kind of syntactic sugar. Also its existence can be perhaps explained by the fact that it's more obvious for user when he sees -f that file is executed. I can't make up any other explanations. Do someone see any other usage of it?

PHP has a very long history with a lot of the design decisions lost in the mists of time; I'm not sure anyone will be able to tell you for certain why there's both a -f option and the ability to run a file without any options at all.
However, it certainly seems designed for user convenience; most command line users would expect an interpreter to interpret a filename provided as a single parameter, and it's the most common use-case, so making it the quickest to type makes sense. My guess would be that the PHP CLI started off with just the -f option, and the option to run a file by providing just the filename was added later to make people's lives easier. The -f was retained for backwards compatibility.
I can think of one case where the -f option is useful: if the filename starts with a hyphen, for example -.php.
When provided as a single parameter, this will be treated as an option, and fail:
$ php -.php
Usage: php [options] [-f] <file> [--] [args...]
php [options] -r <code> [--] [args...]
php [options] [-B <begin_code>] -R <code
...
However, with -f, it'll work:
$ php -f -.php
<script executes successfully>

Related

Why piping output of docker-compose exec to grep, breaks it?

I'm running this command to run Drush which is basically a PHP CLI for Drupal, in the running container:
docker-compose -f ../docker-compose.test.yml exec php scripts/bin/vendor/drush.phar -r public_html status-report
The output if this command is fine, it's the list of status information about a specific Drupal instance in the container. I won't be pasting it here as it's long, and irrelevant.
Now let's filter this information by piping it into grep:
docker-compose -f ../docker-compose.test.yml exec php scripts/bin/vendor/drush.phar -r public_html status-report | grep -e Warning -e Error
The result is:
Cro Error L
Gra Warning P
HTT Error F
HTT Warning T
Dru Warning N
XML Error L
Which is wrong, it looks like it has been cut to pieces, and most of it is missing.
Now, if we will disable allocating of pseudo-tty by adding -T flag:
docker-compose -f ../docker-compose.test.yml exec -T php scripts/bin/vendor/drush.phar -r public_html status-report | grep -e Warning -e Error
The output is correct:
Cron maintenance Error Last run 3 weeks 1 day ago
Gravatar Warning Potential issues
HTTP request status Error Fails
HTTPRL - Non Warning This server does not handle hanging
Drupal core update Warning No update data available
XML sitemap Error Last attempted generation on Tue, 04/18/2017
Why is that?
Bonus question, which probably will be answered by the answer to the previous one: Are there any important side effects of using -T?
Docker version 18.06.1-ce, build e68fc7a215
docker-compose version 1.22.0
UPDATE #1:
To simplify things I saved the correct output of the whole scripts/bin/vendor/drush.phar -r public_html status-report into a file test.txt and tried:
docker-compose -f ../docker-compose.test.yml exec php cat test.txt | grep -e Warning -e Error
Interestingly the output is correct now with and witout -T, so it has to have something to do with Drush/php, although I'm still interested what can be a cause of this.
PHP 7.1.12 (cli) (built: Dec 1 2017 04:07:00) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
with Zend OPcache v7.1.12, Copyright (c) 1999-2017, by Zend Technologies
with Xdebug v2.5.5, Copyright (c) 2002-2017, by Derick Rethans
Drush 8.1.17
UPDATE #2:
To isolate problem further I put all content in a PHP file, that is simply printing it, and after:
docker-compose -f ../docker-compose.test.yml exec php php php.php | grep -e Warning -e Error
I'm getting a correct output!
So it has to have something to do with how Drush is printing its messages, but I fail to see what it can be. That could be pretty interesting if we could figure this out.
UPDATE #3:
Ok guys, that's actual magic. The problem happens also with running drush without any commands, to list all available ones. The list of commands is broken when output is being piped, so this can be tested without actual Drupal instance.
Now I want to present you magic.
In drush, output for list of available commands in being generated in commands/core/help.drush.phpin function drush_core_help(). There is this call: drush_help_listing_print($command_categories); I looked into it. Inside is a call drush_print_table($rows, FALSE, array('name' => 20)); that is responsible for generating part of the output that's getting broken.
So inside of it, I decided to intercept the output, just before the last call to drush_print(), by adding simple file_put_contents('/var/www/html/data.txt', $output);
And now it's time for the absolutely magical part for me.
When I execute:
docker-compose -f ../docker-compose.test.yml exec php scripts/bin/vendor/drush/drush -r public_html
The last group of commands can be checked in this file, and in my case it's:
adminrole-update Update the administrator role permissions.
elysia-cron Run all cron tasks in all active modules for specified site using elysia cron system. This replaces the standard "core-cron" drush handler.
generate-redirects Create redirects.
libraries-download Download library files of registered libraries.
(ldl, lib-download)
libraries-list (lls, Show a list of registered libraries.
lib-list)
BUT, if I execute the same command, but the output will be piped or redirected, so for example:
docker-compose -f ../docker-compose.test.yml exec php scripts/bin/vendor/drush/drush -r public_html | cat
SOMETHING DIFFERENT WILL BE SAVED INTO A FILE:
adminrole-update U
p
d
a
t
e
t
h
e
a
d
m
i
n
i
s
t
r
a
t
o
r
r
(and the rest of the broken output)
So the fact of piping/redirecting of the output, influences execution of the command, before the pipe/redirection actually happens.
How is that even possible? O_o
It's not uncommon for a command-line program to change its output presentation based on whether its output is a terminal, or not. For example, ls by itself, with no options, displays files in a columnar format. When piped, the output changes to a list of one-file-per-line. You can see this in the source code for GNU ls:
case LS_LS:
/* This is for the 'ls' program. */
if (isatty (STDOUT_FILENO))
{
format = many_per_line;
set_quoting_style (NULL, shell_escape_quoting_style);
/* See description of qmark_funny_chars, above. */
qmark_funny_chars = true;
}
else
{
format = one_per_line;
qmark_funny_chars = false;
}
break;
You can emulate the behavior of ls | ... with the explicit argument ls -1, and this too is not uncommon: programs that implicitly change their output presentation often provide a way to explicitly engage that alternate presentation.
Support for this isn't just a convention: it's actually a requirement for ls in POSIX:
The default format shall be to list one entry per line to standard output; the exceptions are to terminals or when one of the -C, -m, or -x options is specified. If the output is to a terminal, the format is implementation-defined.
This all may seem magical: how does ls know it's got a pipe following it since it comes before the pipe? The answer is quite simple, really: the shell parses the whole command line, sets up the pipes, and then forks the respective programs with the input/output wired to pipes appropriately.
So, what part of the command is doing the alternate presentation? I suspect it's an interaction between the environment of your exec and the column width calculation in drush. On my local environment, drush help | ... doesn't produce any unusual results. You might try piping to (or through) cat -vet to discover any unusual characters in the output.
That said, regarding docker-compose specifically: based on this thread, you're not the only one who has encountered this or a similar issue. I've not trawled the docker source code, but - generally - not allocating a pseudo-tty will make the other end act like a non-interactive shell, which means things like your .bash_profile won't run and you won't be able to read stdin in the run command. This can give the appearance of things not working.
The thread linked above mentions a work around of this form:
docker exec -i $(docker-compose ...) < input-file
which seems reasonable given the meaning of -i, but it also seems rather convoluted for basic scripting.
The fact that -T makes it work for you suggests to me that you have something in your .bash_profile (or similar login-shell-specific start up file) that's changing certain values (maybe COLUMNS) or altering the values in such a way as to have the observed deleterious effect. You might try removing everything from those files, then adding them back to see if any particular one causes the issue.
I didn't read that very detailed question, but from glancing over it, I'd say the -T option to the exec subcommand is essential if you want to process stdout and stderr in the environment where you execute docker-compose.

How to pipe Program into PHP (-r) in Windows?

In Windows 7, running php.exe from C:\wamp64\bin\php\php5.6.25\php.exe,
I find that the following prints the PHP usage instructions.
echo 4;|php -r <-- prints php usage instructions
C:\wamp64\bin\php\php5.6.25>echo 4;|php -r
Usage: php [options] [-f] <file> [--] [args...]
php [options] -r <code> [--] [args...]
However, a friend claims that the same command echo 4;|php -r (or perhaps he means echo '4;'|php -r works for him using Linux.
How can I get this behaviour in windows?
Note I'm aware of php -r used to run some code passed as a parameter following it, i'm asking about it running a file or accepting stdin.
There's a few points of confusion here, so I'll do my best to itemize what's wrong.
First, the original command can't work on Linux/POSIX shell because it's not valid:
echo 4; | php -r
Where ; has significant meaning, it's a command separator, and a command can't begin with |.
Fixing this, you get:
echo '4;' | php -r
Where that is at least valid as far as the shell is concerned, but it's still not enough for PHP to deal with. The -r argument requires a second term, code, which is the code to be evaluated. This needs to be supplied inline, not externally as you usually would.
Specifically the -r flag does not mean "run the input file as if it has <?php ... ?> surrounding it" but instead it means "run this bit of code in PHP mode".
For example:
echo '4;' | php
Technically works, but it's not evaluated as PHP code, so it's pointless.
The version that does work in POSIX shell is this:
php -r `echo '4;'`
Where that inlines the output of echo '4;' into the command-line argument itself. I'm not sure Windows can do that without PowerShell involved.
The -r flag is intended for quick little snippets like:
php -r 'echo 5 * 9;'
Where that prints 45 as expected.
Try
echo 4 | php -r
instead of terminating echo 4 and piping nothing into php.
Not that it should matter, "-r" means nothing to php. Nor does 4 (apart from rhyming).

shell_exec throws: sudo: no tty present and no askpass program specified

I have been trying to execute a script using shell_exec() function in php:
I've written the following lines of code:
$command = "bash /path/to/my/script/ funciton_name() 2>&1";
echo shell_exec($command);
Inside the shell script I'm doing:
sudo rsync -avvc /source/path /destination/path
On executing this on the browser, I get the following error message:
sudo: no tty present and no askpass program specified
When I execute the same shell script on my server, it executes fine.
When I went through similar questions posted on this forum, I realised that I had to add the NOPASSWD line on my server which I found out has already been added in the following format:
User_Alias NOBODY=nobody,apache
NOBODY ALL=(ALL) NOPASSWD : /path/to/my/script
Also when I do:
echo shell_exec("whois");
I get the output as:
apache
Any assistance in overcoming this problem would be of great help.
sudo will require a TTY, even if you have set up it up to be passwordless, unless you explicitly do not require it. But as #Cfreak pointed out, it would be much better (simpler and safer) to avoid sudo by setting correct access rights (read it before continuing) in the first place.
rsync itself will not require root permissions on a sanely configured *nix install. To verify this, you can check that type -a rsync doesn't print anything weird like rsync is aliased to `sudo rsync' and that ls -l $(which rsync) prints sensible permissions (at least rx for everyone).

Difference between sentences of cronjobs

What is the difference between these two cron commands:
/usr/local/bin/php -f /home/username/public_html/...
/usr/local/bin/php -q /home/username/public_html/...
the first one is "-f" and the second one "-q"
Cronjob works fine with both of them. I just don't know what is the difference between them.
Thanks.
From the PHP manual:
f:
-f --file
Parse and execute the specified file. The -f is optional and may be omitted - providing just the filename to execute is sufficient.
q:
-q --no-header
Quiet-mode. Suppress HTTP header output (CGI only).
Since -f is optional and -q only applies to the CGI-version of PHP (you are running the regular command line interpreter, however), this leaves you with the same command twice:
/usr/local/bin/php /home/username/public_html/...
To explicitly answer your question: In this case, there is no difference between those two commands!
The two options are of PHP command.
--no-header
-q Quiet-mode. Suppress HTTP header output (CGI only).
and
--file file
-f file Parse and execute file
are shown in the help doc of PHP, you can check them with man php in your terminal.
Also the synopsis contains
php [options] [ -f ] file [[--] args...]
where the -f seems not to be necessary.

Running php script (php function) in linux bash

How we run php script using Linux bash?
php file test.php
test.php contains:
<?php echo "hello\n" ?>
From the command line, enter this:
php -f filename.php
Make sure that filename.php both includes and executes the function you want to test. Anything you echo out will appear in the console, including errors.
Be wary that often the php.ini for Apache PHP is different from CLI PHP (command line interface).
Reference: https://secure.php.net/manual/en/features.commandline.usage.php
First of all check to see if your PHP installation supports CLI. Type: php -v. You can execute PHP from the command line in 2 ways:
php yourfile.php
php -r 'print("Hello world");'
There are two ways you can do this. One is the one already mentioned, i.e.:
php -f filename.php
The second option is making the script executable (chmod +x filename.php) and adding the following line to the top of your .php file:
#!/path/to/php
I'm not sure though if a webserver likes this, so if you also want to use the .php file in a website, that might not be the best idea. Still, if you're just writing some kind of script, it is easier to type ./path/to/phpfile.php than having to type php -f /path/to/phpfile.php every time.
Simply this should do:
php test.php
just run in linux terminal to get phpinfo .
php -r 'phpinfo();'
and to run file like index.php
php -f index.php
php -f test.php
See the manual for full details of running PHP from the command line
php test.php
should do it, or
php -f test.php
to be explicit.
I was in need to decode URL in a Bash script. So I decide to use PHP in this way:
$ cat url-decode.sh
#!/bin/bash
URL='url=https%3a%2f%2f1%2fecp%2f'
/usr/bin/php -r '$arg1 = $argv[1];echo rawurldecode($arg1);' "$URL"
Sample output:
$ ./url-decode.sh
url=https://1/ecp/

Categories