PHP fopen() fails on files even with wide-open permissions
Remember that in order to reach a file, ALL parent directories must be readable by www-data. You strace output seems to indicate that even accessing /var/log/apache2/writetest
is failing. Make sure that www-data has permissions on the following directories:
/ (r-x)
/var (r-x)
/var/log (r-x)
/var/log/apache2 (r-x)
/var/log/apache2/writetest (rwx)
/var/log/apache2/writetest/writetest.log (rw-)
Gregyski
Updated on July 19, 2022Comments
-
Gregyski almost 2 years
I'm currently migrating my LAMP from my Windows Server to a VPS running Debian 6. Most everything is working, however, one of the PHP scripts was failing to write to its configured log file. I could not determine why, so I wrote a new, simple, contrived PHP script to test the problem.
<?php ini_set('display_errors', 1); error_reporting(E_ALL); echo exec('whoami'); $log = fopen('/var/log/apache2/writetest/writetest.log', 'a'); if ($log != NULL) { fflush($log); fclose($log); $log = NULL; } ?>
However, it fails with the result:
www-data Warning: fopen(/var/log/apache2/writetest/writetest.log): failed to open stream: Permission denied in /var/www/_admin/phpwritetest.php on line 5
- While I would never do it normally, to help diagnose, I set
/var/log/apache2/writetest/writetest.log
to chmod 777. - Both the directory and the file are owned by
www-data:www-data
. - The file was created with
touch
.
I ran
strace
to verify which process was performing the open:[pid 21931] lstat("/var/log/apache2/writetest/writetest.log", 0x7fff81677d30) = -1 EACCES (Permission denied) [pid 21931] lstat("/var/log/apache2/writetest", 0x7fff81677b90) = -1 EACCES (Permission denied) [pid 21931] open("/var/log/apache2/writetest/writetest.log", O_RDWR|O_CREAT|O_TRUNC, 0666) = -1 EACCES (Permission denied)
I checked and pid 21931 was indeed one of the apache2 child processes running under
www-data
. As you can see, I also includedecho exec('whoami');
in the script which confirmed the script was being run bywww-data
.Other notes:
- PHP is not running in safe mode
- PHP
open_basedir
is not set - Version info:
Apache/2.2.16 (Debian) PHP/5.3.3-7+squeeze3 with Suhosin-Patch mod_ssl/2.2.16 OpenSSL/0.9.8o
- uname -a:
2.6.32-238.19.1.el5.028stab092.2 #1 SMP Thu Jul 21 19:23:22 MSD 2011 x86_64 GNU/Linux
- This is on a VPS running under OpenVZ
- ls -l (file):
-rwxrwxrwx 1 www-data www-data 0 Sep 8 18:13 writetest.log
- ls -l (directory):
drwxr-xr-x 2 www-data www-data 4096 Sep 8 18:13 writetest
- Apache2's parent process runs under
root
, and the child processes underwww-data
- selinux is not installed (thanks to Fabio for reminding me to mention this)
- I have restarted apache many times and rebooted the server as well
- While I would never do it normally, to help diagnose, I set
-
Cyclone over 12 yearsPermission is
0666
as indicated by his strace -
Adam over 12 yearsI'm not seeing that in the post? I see that the .log files are 0666 and the containing folder but not the permissions to the .php file doing the writing.
-
Cyclone over 12 yearsIf the php file can run, shouldn't it be able to write to the file then if the other file's permissions are accurate?
-
Adam over 12 yearsI just tested a php file with file_put_contents( 'test.txt', 'data' ); when I run it from the command line as root it makes the file no issues. When I call it from the browser it does nothing. When I changed the files permissions for the .php file it worked from being called by the browser (apache).
-
Gregyski over 12 yearsThanks for the suggestion, but even if I
chmod 777 writetest.php
, the problem remains. It is owned byroot:root
which is, I believe, typical for a secure Apache setup. -
Gregyski over 12 yearsThank you for the suggestion and the excellent explanation for how to check it, but selinux is definitely not installed. I had checked before but had forgotten to mention it in my question. But I have seen others for whom that was the cause so hopefully your answer will help others in the future.
-
Adam over 12 yearsHave you tried other ways to read the file? file_get_contents, file, or ( I don't know if this is do-able ) Curl it? Or if you give the .php execute permissions can you read the contents with a shell_exec command into a variable? These would just be a work-around though.
-
Gregyski over 12 yearsPer your suggestion, I added text to the file and tried the following:
$lines = file('/var/log/apache2/writetest/writetest.log'); echo $lines;
,$str = file_get_contents('/var/log/apache2/writetest/writetest.log'); echo $str;
, and$log = fopen('/var/log/apache2/writetest/writetest.log', 'r');
. All three cause the same error indicated in my question. -
Adam over 12 yearsThe last thing I can think of to get that information would be $file_contents = shell_exec( 'cat /path/to/file' ); with the .php file having execute permissions. Sorry I couldn't help more. Good luck.
-
Gregyski over 12 yearsEven though I really do need to get it working with the existing functions (and I'm writing, not reading anyways), I couldn't resist trying the shell_exec. It produced no error, it just returned an empty string. Anyways, thanks for your suggestions.
-
Gregyski over 12 yearsThat was what I had overlooked.
/var/log/apache
was missing (r-x) while the rest were correct. Thank you so much. -
Chris Eberle over 12 yearsGotta love those gut feelings.