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)