How do I resolve a PHP error "Failed opening required" in a symlink context?
I am running Apache/PHP on MacOS X Lion 10.7.4. My directory structure is set up as so:
/Users/achan/Sites/
lrwxrwx--- 1 achan staff 23B Apr 27 16:21 epwbst@ -> /Users/achan/dev/epwbst`
where epwbst/
is a symlink inside of ~/Sites
.
If I put test.php
inside of the Sites/
directory, Apache serves up the file correctly; it spews out phpinfo()
like it is supposed to. If I put the same file under the symlink, I get this error:
[Mon May 28 14:47:13 2012] [error] [client ::1] PHP Warning: Unknown: failed to open stream: No such file or directory in Unknown on line 0
[Mon May 28 14:47:13 2012] [error] [client ::1] PHP Fatal error: Unknown: Failed opening required '/Users/achan/Sites/epwbst/test.php' (include_path='.:/usr/lib/php/pear') in Unknown on line 0
Just to be sure that Apache was working, I created a test html file under ~/Sites/epwbst/
and Apache served it up as expected.
Why can't Apache run php under my symlinked directory?
I've pasted my php config here: http://pastebin.com/gg27JyVZ
Okay, this drove me nuts for hours. It is a permissions issue, but not how one might think. The problem rests with the permissions of the symbolic link itself:
/Users/achan/Sites/
lrwxrwx--- 1 achan staff23B Apr 27 16:21 epwbst@ -> /Users/achan/dev/epwbst`
Here's the rub: chmod
won't normally change the permissions on symbolic links, because (with the apparent exception of php5_module
and some other cases beyond the scope of this answer) those permissions are largely irrelevant as they are ignored in nearly all contexts. Here's the fix:
chmod -h 755 /Users/achan/Sites/epwbst
Note the -h
. From the man page:
...
-h If the file is a symbolic link, change the mode of the link itself
rather than the file that the link points to.
...
For some reason, php5_module
actually pays attention to the permissions on the symbolic link. If they are too restrictive, php5_module
will refuse to see the target, even if the httpd
user could otherwise read and run that very same target using /usr/bin/php
.
Consider the following:
% umask 027
% cd ~/Sites
% mkdir bar
% chmod 755 bar
% ln -sv bar foo
foo -> bar
% ls -al ~/Sites/foo
lrwxr-x--- 1 xyz xyz 3 Apr 22 13:17 foo -> bar
% ls -adl ~/Sites/foo/.
drwxr-xr-x 2 xyz xyz 68 Apr 22 13:17 /Users/xyz/Sites/foo/.
% echo 'Hello!' >bar/hello.txt
% chmod 644 bar/hello.txt
% curl http://localhost/~xyz/bar/hello.txt
Hello!
% curl http://localhost/~xyz/foo/hello.txt
Hello!
So far, so good. Now consider:
% echo '<?php phpinfo(); ?>' >bar/info.php
% chmod 644 bar/info.php
% curl http://localhost/~xyz/bar/info.php
<html xmlns="http://www.w3.org/1999/xhtml"><head>
...
</div></body></html>
% curl http://localhost/~xyz/foo/info.php
<br />
<b>Warning</b>: Unknown: failed to open stream: No such file or directory in <b>Unknown</b> on line <b>0</b><br />
<br />
<b>Fatal error</b>: Unknown: Failed opening required '/Users/xyz/Sites/foo/info.php' (include_path='.:') in <b>Unknown</b> on line <b>0</b><br />
Hmmm. My httpd
runs as user _www
, so let's check to see if that user can read .../foo/info.php
:
% sudo sudo -u _www cat ~/Sites/foo/info.php
Password:
<?php phpinfo(); ?>
Yup. Now let's see if that user can run .../foo/info.php
:
% sudo sudo -u _www /usr/bin/php ~/Sites/foo/info.php
Password:
phpinfo()
PHP Version => 5.4.24
...
If you did not receive a copy of the PHP license, or have any
questions about PHP licensing, please contact [email protected].
Yes?! WTF?! Grrr! Now repair it:
% chmod -h 755 foo
% curl http://localhost/~xyz/foo/info.php
<html xmlns="http://www.w3.org/1999/xhtml"><head>
...
</div></body></html>
Bang. Done.
So, yes. It appears that php5_module
does something paranoid and nonstandard. This may have gone overlooked as umask
often defaults to 022
, which will at least create symbolic links with 755
. Also, many filesystems (not HFS+) impose at the kernel level permissions of 777 during symbolic link creation, irrespective of umask
.
You and I appear to be the two people in the solar system running Apache+PHP on HFS+ while setting our umask to something more restrictive than the default. I'll bet you even use case-sensitive HFS+, too. ;o)