PHP fopen() fails on files even with wide-open permissions

10,810

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-)
Share:
10,810
Gregyski
Author by

Gregyski

Updated on July 19, 2022

Comments

  • Gregyski
    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 included echo exec('whoami'); in the script which confirmed the script was being run by www-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 under www-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
  • Cyclone
    Cyclone over 12 years
    Permission is 0666 as indicated by his strace
  • Adam
    Adam over 12 years
    I'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
    Cyclone over 12 years
    If 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
    Adam over 12 years
    I 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
    Gregyski over 12 years
    Thanks for the suggestion, but even if I chmod 777 writetest.php, the problem remains. It is owned by root:root which is, I believe, typical for a secure Apache setup.
  • Gregyski
    Gregyski over 12 years
    Thank 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
    Adam over 12 years
    Have 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
    Gregyski over 12 years
    Per 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
    Adam over 12 years
    The 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
    Gregyski over 12 years
    Even 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
    Gregyski over 12 years
    That was what I had overlooked. /var/log/apache was missing (r-x) while the rest were correct. Thank you so much.
  • Chris Eberle
    Chris Eberle over 12 years
    Gotta love those gut feelings.