1

I logged into my development server today to find that PHP was failing to include some files with this E_WARNING message:

Warning: include_once(../file2.php) [function.include-once]: failed to open stream: No such file or directory in /var/www/web/some_directory_1/file1.php on line whatever

I did some digging around with our sysadmin and we discovered that PHP only fails when it tries to include file paths with a '../' or './' in the path.

Suppose our file structure looks like this:

/var/www/web/
-- index.php
-- file2.php
-- some_directory_1/
---- file1.php
---- file3.php

If file1.php wants to include file2.php, this will work:

include_once('/var/www/web/file2.php');

But this will not:

include_once('../file2.php');

Now, hold on a second... I know what you're thinking! "Oh, their include_path is just FUBAR." Well, not exactly.

If you do this in index.php, it works:

include_once('some_directory_1/file1.php');

And if you do this in file1.php, it also works:

include_once('file3.php');

Our include_path is set to .:/usr/lib/php. Nothing about the server environment been changed in the last 24 hours (no updates, no new software, no changes to the includes, no changes to the Apache or PHP configurations), myself and the sysadmin were the only people who accessed the server in the last 24 hours, and the includes were working just fine yesterday. We've exhausted our list of possible causes. Any clue what might cause this to happen?

Edit: Forgot the PHP warning message.

John Nicely
  • 148
  • 1
  • 6
  • ... So then why don't you just add `/var/www/web`? – Ignacio Vazquez-Abrams May 23 '12 at 00:09
  • Check the output of `getcwd()`, perhaps something is changing your working directory? Are you using symlinks at all? I have seen them confuse PHP. – Zoredache May 23 '12 at 00:19
  • @Ignacio 1) We use relative paths in hundreds of places throughout the site. 2) It's not actually a solution to our problem, and we want to know why this is happening, not just fix it. 3) We sell our server software too, and customers can change the location of the software. We cannot guarantee the absolute location of the path until after file1.php is loaded (file1.php sets the configuration variables that we use to load every other file elsewhere). – John Nicely May 23 '12 at 00:19
  • @Zoredache getcwd() is the same as it was before and the only changes I made do not affect the cwd. – John Nicely May 23 '12 at 00:20
  • 1
    Do something like this? `include_once(realpath(dirname(__FILE__)."/../file2.php"));` – Zoredache May 23 '12 at 00:22
  • @Zoredache And obviously that works, but only because it's providing a different path value (it resolves the "../"). I'm trying to specifically figure out why using "../" in the path does not work. The same is also true of "./": if I do `include_once('file3.php')` it will work, but `include_once('./file3.php')` will not. – John Nicely May 23 '12 at 00:27
  • Also, we don't have any symlinks in these paths, and the file/directory permissions haven't changed. – John Nicely May 23 '12 at 00:29

1 Answers1

2

The reason you're having trouble is that the relative path in an include/require is always relative to the initial script, and using a relative path causes php to ignore the include_path value. So in your example include_once('../file2.php'); is looking for the file in the parent of index.php, assuming index.php is the initial script.

Not sure why it would suddenly change. But, the solution is to not use relative paths -- either use the include_path or use __DIR__/dirname() as suggested in the comments.

xofer
  • 3,072
  • 12
  • 19
  • See, the problem with that is that we've been using these same relative paths for 4 years without any changes... To repeat: we haven't updated PHP, and we haven't changed the configuration. – John Nicely May 23 '12 at 04:53