temp file created in different location than requested with systemd - php

I tried creating a trace file with fopen("name","a") and writing to it, but although the fopen succeeds, and returns a handle, and all of the fwrite calls succeed, I cannot find the file at the location specified by the file name parameter to fopen.
$trace = fopen("/var/tmp/billing.log", "a");
if ($trace)
echo "opened /var/tmp/billing.log<br>\n";
else
echo "unable to open /var/tmp/billing.log<br>\n";
...
fwrite($trace, __FILE__ . ': ' . __LINE__ . "ce(" .
"\$aid=$aid, " .
"\$level=$level, " .
"\$id=$id, " .
"\$mode=$mode, " .
"\$nocache=$nocache)\n");
echo __FILE__ . ': ' . __LINE__ . "ce(" .
"\$aid=$aid, " .
"\$level=$level, " .
"\$id=$id, " .
"\$mode=$mode, " .
"\$nocache=$nocache)<br>\n";
The echo indicating the handle has been returned displays, as do the echos immediately after each call to fwrite, but the requested file /var/tmp/billing.log does not exist. As usual /var/tmp is:
drwxrwxrwt. 35 root root 4096 Jul 15 20:06 tmp
so writing to the directory is permitted. I tested this by manually creating a file by:
cat > /var/tmp/test
This appears to be a poorly documented or explained feature of PHP on systems using systemd. Instead of creating the file where I specified PHP instead creates the file a further layer down in a private directory!
$ cd /var/tmp
$ sudo find -name *.log
[sudo] password for jcobban:
./systemd-private-DGOkBT/tmp/recur-billing.log
./systemd-private-DGOkBT/tmp/process-registration.log
./systemd-private-uEF6lO/tmp/recur-billing.log
./systemd-private-uEF6lO/tmp/billing.log
./systemd-private-uEF6lO/tmp/process-registration.log
$ ls systemd-private-uEF6lO/
ls: cannot open directory systemd-private-uEF6lO/: Permission denied
Observe that I have to use sudo to even see the file, because I am not running with the userid of the PHP process. This is a consequence of the decision by PHP to use the private temp directory service of systemd. This action does not appear to be described anywhere in the PHP documentation. If you call the function sys_get_temp_dir it even fibs about the location of the temp files. Note that the decision to use a private temp directory does not affect PHP scripts themselves because the temporary file names are always mapped. From the point of view of scripts the files are at the location specified by the program. That is fopen("/var/tmp/billing.log", "r"); will read the file. The problem is only with the external visibility of temporary files. I haven't checked but I suspect that on Windows PHP maps /tmp and /var/tmp to the Windows temporary directory C:\Windows\Temp\ for portability.
This is a pain because in order to make these trace files visible for external analysis I now have to define and manage my own directory to put trace files in, an action which is complicated because on my site 'DOCUMENT_ROOT' is not a valid path so I have to figure out what the real path to the document root is.
$document_root = substr(__FILE__, 0, -strlen($_SERVER['PHP_SELF']));
$trace = fopen($document_root . "/log/billing.log", "a");

Actually this is a systemd security feature: PrivateTmp
You can disable it for your specific httpd service. On Arch Linux:
juergen#samson:/tmp → grep PrivateTmp /usr/lib/systemd/system/httpd.service
PrivateTmp=true

Related

PHP, system() and inheriting PATH to script

Php pages on /var/www/mypage say system("foo.sh"). foo.sh is located on /one/dir and contains command bar.sh that is in /other/dir. For a user using ssh connection and having /one/dir and /other/dir in PATH everything works.
Now, if I put
<Directory /var/www/mypage>
SetEnv PATH . . . :/one/dir:/other/dir
to Apache config, then print getenv("PATH"); on /var/www/mypage/mytest.php shows that /one/dir and /other/dir are in the path. But system() still does not found foo.sh. What's wrong? And after this also foo.sh should see the same PATH so that it will find bar.sh.
I am setting this on Ubuntu 20.04, PHP 7.4.3.
Most likely because just executing > foo.sh would show command not found: foo.sh.
You should specify full/relative path: system('./foo.sh');

PHP isn't able to read file

I'm stuck trying to open a file with fopen in php.
$db_ausgaenge = "statuseing.php";
$dout = fopen($db_ausgaenge, "x+");
print $dout;
print(shell_exec('whoami'));
print(shell_exec('pwd'));
print(shell_exec('id'));
fwrite($dout, $out);
fclose($dout);
Warning: fopen(statuseing.php): failed to open stream: File exists in /var/www/html/zufallsgenerator.php on line 33
I checked following items:
chmod for statuseing.php 0777
owner is www-data with groud www-data
script is running as user www-data
groups are uid=33(www-data) gid=33(www-data) groups=33(www-data)
pwd is /var/www/html as expected
the path the scripts want's to open is correct
checked openbase dir in php.ini showed in phpinfo(), added /var/www/html, but php doesn't care about it.
open_basedir = /var/www/html/
After daemon-reload and restarting apache2 via systemctl nothing changed, phpinfo() didn't show the path given in the config. restarting the system via init 6 didn't took effect, too.
statuseing.php already exists.
See the manual (http://php.net/manual/en/function.fopen.php) - opening in x or x+ mode says: Create and open for writing only; place the file pointer at the beginning of the file. If the file already exists, the fopen() call will fail by returning FALSE
Look at the mode you are using.
x+ means that if the file already exists an error will be thrown.
To find the correct mode depending on your scenario check out http://php.net/manual/en/function.fopen.php
Try this:
$db_ausgaenge = __DIR__."/statuseing.php";
$dout = fopen($db_ausgaenge, "a+"); // x+ will throw error cuz it tries to open existing file, thx to: bluegman991 (;
print(shell_exec('whoami'));
print(shell_exec('pwd'));
print(shell_exec('id'));
fwrite($dout, $out);
fclose($dout);
or if You want to truncate file before adding data use w+:
$db_ausgaenge = __DIR__."/statuseing.php";
$dout = fopen($db_ausgaenge, "w+");
print(shell_exec('whoami'));
print(shell_exec('pwd'));
print(shell_exec('id'));
fwrite($dout, $out);
fclose($dout);
also do some checkups:
1) check free space: df -h
2) check if You can edit that file: nano /var/www/html/statuseing.php

session_start() returns "No such file or directory" directly after creating the session file

I'm trying to set the session.save_path on my IIS/PHP via fastcgi server. So I created a new folder called tmp in my php folder, gave IUSR and IIS_IUSRS full permissions to this folder, and set my session.save_path variable in php.ini to "\tmp".
Upon loading my webpage I get the error:
Warning: session_start(): open(tmp\sess_gp13t5fg969iddfq1lrt3e88o1, O_RDWR) failed: No such file or directory (2)
The weird thing is I know it can see the folder because I look in my newly created tmp folder and it actually created the sess_gp13t5fg969iddfq1lrt3e88o1 file right before throwing the error telling me it doesn't exist. So how can it create the file and then not see it? What could I be doing wrong?
Update: If I set session.save_path with an absolute path, it works. When I give it a relative path of just "\tmp" it no longer works. Every example I see uses a relative path for the save_path and I personally need to use a relative path. Why would a relative path cause this issue and how do I fix it?
I found the answer you seek:
Relative Paths in PHP
include($_SERVER["DOCUMENT_ROOT"] . "/relative path here");
Under linux the PrivateTmp config of systemd may be the problem.
The solution would be to copy the corresponding systemd unit file to /etc/systemd and remove there the privatetmp config.
In my case:
cp /usr/lib/systemd/system/httpd.service /etc/systemd/system
systemctl daemon-reload
systemctl restart httpd.service
Change in /etc/systemd/httpd.service then
PrivateTmp=true
to
PrivateTmp=false

php file not included despite setting include_path

I have an apache2 server running on my Linux machine. I edited the file /etc/php5/apache2/php.ini by setting include_path to
include_path = ".:/usr/share/php:/var/www/subdir"
To make sure I did not change the wrong file, I also edited all other php.ini files (there was one more) I found on my computer and checked the output of phpinfo() which printed the correct include_path from above. (I also restarted apache2.)
However, when I use lines like
use some\name\space;
require_once('./subsubdir/file.php');
in a file start.php (which lies in another directory /var/www/subdir/anothersubdir/), the require_once command does not work, as I get the following error in the apache log file
[error] [client 127.0.0.1] PHP Fatal error: require_once(): Failed opening required './subsubdir/file.php' (include_path='.:/usr/share/php:/var/www/subdir') in /var/www/subdir/anothersubdir/start.php on line x
I also tried
require_once('/subsubdir/file.php');
but it did not work. How do I have to inlcude file.php when I have set the include_path as shown above ?
Thanks a lot in advance !
The first questions I would be asking myself are:
is the webserver running in a chroot environment?
what are the permissions on the target file?
And a simple way to answer both of these would be:
print getcwd() . "<hr />\n";
$t='/var/www/subdir/anothersubdir/subsubdir/file.php';
function show_permissions($path)
{
if (strlen($path)>1) {
show_permissions(dirname($path));
}
if (is_readable($path)) {
print "Permissions for $path: " . var_export(stat($path)) . "<br />";
} else {
print "can't read $path <br /> \n";
}
}
(my money would be on a permissions problem - not a path issue)
Try rebooting Apache, to clear the internal cache.

PHP cli command line safe_mode restriction

I'm using the Kohana framework (3.0.9), which generates daily logs. I want to mail the log file if one was made the day before CRON runs the script, but after days trying I can't figure out how to put off safe_mode in PHP CLI modus.
When I'm running my script on the web, there is no problem. But I want to run the script as a CRON task on my Plesk 9.5.2 server (or on the command line as root user) I'm getting the following error:
ErrorException [ 2 ]: dir(): SAFE MODE Restriction in effect. The script whose uid is 10001 is not allowed to access /var/www/vhosts/mydomain.com/subdomains/mysubdomain/httpdocs/application/logs/2011/01 owned by uid 48 ~ APPPATH/classes/controller/ajax.php [ 181 ]
I've allready put SAFE MODE off in my Plesk control panel, which works fine for the web request, but not in on the command line or as an CRON task.
I'm using the following code to test if its working:
$d = dir(APPPATH.'logs/2011/01/');
echo "Handle: " . $d->handle . "\n";
echo "Path: " . $d->path . "\n";
while (false !== ($entry = $d->read())) {
echo $entry."\n";
}
$d->close();
I can read the directory APPPATH.'logs/', and also the directory APPPATH.'logs/2011', but the directory's representing each month with the daily log files always give an error.
At nowadays you can schedule php script execution from UI like this:
In case you still need execute script via command line pay attention that Plesk's PHP binaries are placed in:
# 7.0
/opt/plesk/php/7.0/bin/php
# 5.6
/opt/plesk/php/5.6/bin/php
# 5.5
/opt/plesk/php/5.5/bin/php
# and so on
Original answer:
I know this is a few months old, but for the next person that comes across a problem while using Plesk and cron and PHP, here's the answer.
While Plesk does run cron as ROOT, it also runs PHP by default with safe mode ON, which means that when you setup a cron in Plesk that needs PHP, it's going to have restrictions that you do not experience from the shell or from the web.
So what you do is use the CLI /etc/php.ini option override, like so:
/usr/bin/php -q -d safe_mode=Off /var/www/vhosts/path-to-your-php-file.php
Have you disabled safe_mode in the php.ini for CLI?
You can find the location of this file by running the following command php --ini. Search for safe_mode in this file and change the line to safe_mode = Off.

Categories