open_basedir restriction when running script from command line - php

I'm learning how to use the command line by requirement for a recent project. I have a script that will be run during a cronjob, and am testing it by hitting it from the command line using Putty.
My script runs fine from the browser, but from the command line I get permission errors trying to include files or even check if they exist.
This only happens from the command line. This is what is in the console (I'm sure the correct script is executing, and all it does for now is check if a required file exists):
Here is the line in the terminal that executes the command:
secure:~/www/private/cron$ php -f ./update.php
Here is the output:
Warning: file_exists(): open_basedir restriction in effect.
File(/usr/local/apache/htdocs/example.com/private/modules/real_estate/config/condos.php)
is not within the allowed path(s):
(.:/tmp/:/var/tmp/:/usr/local/apache/htdocs/example.com/images/:/home/example/www/images/)
in /usr/local/apache/htdocs/example.com/private/cron/update.php
on line 43
I do not get this error running the script in a browser, which is confusing to me - but as I mentioned I am new to using the command line. I've tried every way I can think of to reference the file from update.php, and tried changing the include path, but nothing seems to work. Either I get the permission error or it can't find the file.
Does anyone know why there is a difference between executing the script in a browser VS the command line, and what I can do to resolve this error? I'm happy to provide more information as requested.
More information:
This is my CLI output from php --ini:
Configuration File (php.ini) Path: /usr/local/lib
Loaded Configuration File: /usr/local/Zend/etc/php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed: (none)
This is the Loaded Configuration File entry in phpinfo(), from the browser:
/usr/local/Zend/etc/php.ini
So Loaded Configuration File appears to be the same in both environments.

You may want to run two different php.ini files for CLI vs Apache instances.
One way to do that is to copy your current php.ini file to another directory - say into "/usr/local/Zend/etc/php_cli/php.ini" or a more convenient directory. Then, change settings in "/usr/local/Zend/etc/php_cli/php.ini" to better suit a command line environment (expand open_basedir a bit, log file paths, and other CLI-specific settings). Then, when executing CLI scripts, include the -c "/usr/local/Zend/etc/php_cli" switch to have CLI reference that ini file.

There is often a difference between the php.ini for your server and the php.ini for the command line. This means that whatever you're seeing in the browser is almost certainly not what you'll see when you enter php -r 'phpinfo();' on the command line (I mean, the formatting is different and it is less colorful)
You'll want to look for the other php.ini, and then you'll want to commend out open_basedir = <something>

Related

PHP file_get_contents() and curl_exec() fail from website but work from command line

Created .test.php file with one line of code:
<?php
var_dump(file_get_contents('https://checkip.amazonaws.com'));
?>
When I open .test.php from browser, it shows bool(false) but when I run it from command line, it shows my WAN IP as expected.
php -f .test.php
I am using CentOS 9, nginx 1.20.1, and PHP 8.1.3 (Although I've also tried RHEL8 and Apache)
I tried setting /etc/php-fpm.d/www.conf to use my userid and group to make sure it was not a permission problem.
phpinfo() shows allow_url_fopen is set to On and that curl 7.76.1 is enabled and that OpenSSL is enabled with version 3.0.1
I also tried with an http: URL
I also tried using curl() libraries in the .php file and those fail in the same manner.
Calling exec() from .php file works if it calls php -v or another .php file but not if it calls curl
Not sure what else to try, so I will probably nuke the whole server again.
UPDATE: Found this in /var/log/nginx/error.log
FastCGI sent in stderr: "PHP message: PHP Warning: file_get_contents(https://checkip.amazonaws.com): Failed to open stream: Permission denied
Now what?
There might be different settings of your PHP environment used in Command Line Interpreter/Interface CLI vs Common Gateway Interface CGI .
First compare what .ini files are loaded in both environment, ie.
for CLI run php -i
for CGI create a file phpinfo.php with only content <?php echo phpinfo(); and open it in the web browser.
Compare the results and see what modules are loaded and/or what .ini files are loaded.
Once I found the error log, I was able to find my answer. It was a Linux permission setting and running the following command fixed it:
setsebool -P httpd_can_network_connect on

Cannot run a go binary under apache via PHP shell_exec

I am having an issue and I don't understand what is going on. I am basically using this PHP script to try and run a go binary :
<?php
shell_exec('/go/bin/x -arg -arg etc');
If I run this PHP file via command line it works. If I run it directly in browser (it's under www) it does not work. No errors whatsoever.
cli runs as root and apache as www-data. I have set the permissions to 0777 for /go/bin/x and I have also changed the owner / group to www-data. Still nothing.
What can cause this behavior ?
Also note that shell_exec works, but so far I have only ran other php files.
I do not know how I did not think about this before... The issue was that 1 of the input args contained a location to a text file and apache did not have the rights to read the file. The error was in /var/log/apache2/error.log
To Whom It May Concern.
I have same issue that I cannot run shell_exec/exec via website even they were run well in terminal.
See log:
[13-Jul-2020 19:57:23 UTC] PHP Warning: shell_exec() has been disabled for security reasons in /...test_script.php on line 3
Case 1: Check all php.ini where disable_function does not contain "shell_exec" or "exec"
$ sudo find / -name "php.ini"
$ sudo cat <path_to_php.ini> | grep disable_functions
// disable_functions = <<= This is OK
// disable_functions = "shell_exec, exec, system...." <<= They are disabled
Remove function that you want to use. Don't forget restart server.
Case 2: If disable_functions are all empty for all php.ini. Check your PHP-FPM on your hosting via Cpanel. Go to "MultiPHP Manager" from your Cpanel and check PHP-FPM status on your domain. Turn it off and you will be able to run shell_exec();

How Can I use drush.ini file instead of global php.ini file - Drush

I install And run drush as explained in this article:
My server is cloudlinux and cagefs.drupal7
Drush Use global php.ini File instead of drish.ini file and this issue makes some errors for open_basedir and disable_finctions functions.
when I run drush status command.give me following:
> The following restricted PHP modes have non-empty values:
> [error] open_basedir and disable_functions. This configuration is
> incompatible with drush. Please check your configuration settings in
> /opt/cpanel/ea-php56/root/etc/php.ini or in your drush.ini file; see
> examples/example.drush.ini for details. is_dir(): open_basedir
> restriction in effect. [warning]
> File(/usr/share/drush/commands) is not within the allowed path(s):
> (/home/:/usr/lib/php:/usr/local/lib/php:/usr/local/bin:/usr/share/drush:/usr/share/drush/commands:/etc:/tmp)
> preflight.inc:518 PHP configuration :
> /opt/cpanel/ea-php56/root/etc/php.ini
> /home/username/.drush/drush.ini PHP OS : Linux Drush script : /usr/local/bin/drush Drush
> version : 8.1.9 Drush temp directory : /tmp Drush
> configuration : Drush alias files :
So drush for me uses /opt/cpanel/ea-php56/root/etc/php.ini instead of /home/username/.drush/drush.ini
How Can I use drush.ini file instead of server php.ini file ?
I dont want edit global php.ini file for security reasone.
Have you tried adding EXPORT PHP_INI="/home/username/.drush/drush.ini" to your .bashrc file?
This is quite an old question, but I suspect that it is one that many people still puzzle over. Here is a solution that works for me (I'm using Ubuntu linux 18.04, but this should work for any unix system.)
Create a directory, e.g. /home/username/.drushrc
In this directory, create a file named 'php.ini', containing the php settings that you want to override. For example:
disable_functions=
open_basedir=
In your Drupal docroot directory, create a shell script, e.g. named 'mydrush', containing:
#!/bin/sh
PHP_INI_SCAN_DIR=:/home/username/.drushrc ./drush $*
The PHP_INI_SCAN_DIR environment variable specifies additional directories that php will look in to find .ini files when it starts up. The colon at the start of the assignment means that the directory you specify will be appended to the existing list of directories that php scans.
Make your shell script executable:
$ chmod +x mydrush
You can now call drush from your docroot directory using the command ./mydrush, for example:
$ ./mydrush status
Alternatively, you could set the environment variable PHP_INI_SCAN_DIR in your ~/.bashrc file. This would avoid the need for the 'mydrush' file, but it would change the php initialisation settings for every command-line invocation of php - not just when you're running Drush - and that may not be what you want. If you do change ~/.bashrc, then you need to open a new window for the changes to take effect.

Custom php.ini when using #!/usr/bin/php

I have a script in which I am trying to load a custom php.ini file. The script is run on *nix systems via a #!/usr/bin/php -qc /path/to/php.ini header. When doing this, however, PHP reports that the loaded php.ini file does not exist, i.e. none is loaded.
If I execute php -qc /path/to/php.ini /path/to/script in the command line directly, it picks up the php.ini -- is it possible to override the php.ini file using the #! notation?
PHP does not like parsing arguments from the shebang. It only allows one to be present. You can however trick it by omitting the space for the first argument parameter:
#!/usr/bin/php -qc/etc/php5/my.ini
(Obviously this method only works for one such parameter with concatenated argument.)
You can workaround this shebang portability specification fail by wrapping your PHP script in a Shell script:
#!/bin/sh
SCRIPT_PATH="$(dirname $0)"
/usr/bin/env php -qc /path/to/php.ini -f $SCRIPT_PATH/my_original_script.php

Custom php.ini file in when executing 'php' as a shell script

I'm running php as a shell script.
(I am not sure if "shell script" is correct. The file starts with #!/usr/bin/php.)
This works great. But the MongoDB class doesn't get loaded as the correct php.ini file (having extension=mongo.so) is not used.
How do I make it use that php.ini file?
I already tried #!/usr/bin/php -c /usr/local/lib/php.ini
But I still get the same error - Fatal error: Class 'Mongo' not found
What can be done?
Try putting php.ini in the same folder as the php binary. It seems to look there first.
I know this because I used a very powerful and useful command-line program called strace to show me what's really going on behind my back
$ strace -o strace.log php --version
$ grep php.ini strace.log
Strace digs out kernel (system) calls that your program makes and dumps the output into the file specified after -o
It's easy to use grep to search for occurrences of php.ini in this log. It's pretty obvious looking at the following typical response to see what is going on.
open("/usr/bin/php.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/etc/php.ini", O_RDONLY) = 3
lstat("/etc/php.ini", {st_mode=S_IFREG|0644, st_size=69105, ...}) = 0
Edit .bashrc located at your home directory and add this line:
alias php='php -c /path-to-custom/php.ini'
In this particular situation. I would
Check to see if the Mongo module is loaded (using extension_loaded() or class_exists())
If not loaded, try to load the Mongo module using dl()
If loading fails, display an error message so the admin can take care of it (STDERR or trigger_error()
Most distributions already ship different versions of php.ini for Web Servers and CLI. Are there other reasons to add another php.ini configuration for script XYZ (in addition to normal configuration)?
I came across this, because I had the same problem. Problem is there is more than one php.ini file used.
The one used by Apache is located in
/etc/php5/apache2/php.ini
This is the one that is modified to run MongoDB with extension=mongo.so.
However, when running a cron job, or from the terminal, it loads a different ini file. You can find this by using the line
grep php.ini strace.log
It is mentioned by thomas-peter.
The path where it displays '=3' is the php.ini file loaded when running the engine from the terminal, this ini file will need "extension=mongo.so" placed in it as well.
The other option is to use a small sh wrapper, something like this below in a myapp.sh file. Don’t forget to chmod +x on the script to run it.
#!/usr/bin/env sh
SOMEVAR='Yea Baby!'
export SOMEVAR
php -c /path/to/my/custom/php.ini /path/to/my/old_script.php
With the added bonus of being able to set or override environment variables pre-run.
This is a bit of a gotcha with PHP.
php -c /path/to/my/custom/php.ini works from the command line.
But try it in a script like this #!/usr/local/bin/php -c /path/to/my/custom/php.ini and your custom php won't load.
The Solution
Get rid of the space between -c and your path:
#!/usr/local/bin/php -c/path/to/my/custom/php.ini

Categories