Are PHP include paths relative to the file or the calling code?

PhpIncludeRelative Path

Php Problem Overview


I'm having trouble understanding the ruleset regarding PHP relative include paths. If I run file A.PHP- and file A.PHP includes file B.PHP which includes file C.PHP, should the relative path to C.PHP be in relation to the location of B.PHP, or to the location of A.PHP? That is, does it matter which file the include is called from, or only what the current working directory is- and what determines the current working directory?

Php Solutions


Solution 1 - Php

It's relative to the main script, in this case A.php. Remember that include() just inserts code into the currently running script.

> That is, does it matter which file the include is called from

No.

If you want to make it matter, and do an include relative to B.php, use the __FILE__ constant (or __DIR__ since PHP 5.2 IIRC) which will always point to the literal current file that the line of code is located in.

include(dirname(__FILE__)."/C.PHP");

Solution 2 - Php

@Pekka got me there, but just want to share what I learned:

getcwd() returns the directory where the file you started executing resides.

dirname(__FILE__) returns the directory of the file containing the currently executing code.

Using these two functions, you can always build an include path relative to what you need.

e.g., if b.php and c.php share a directory, b.php can include c.php like:

include(dirname(__FILE__).'/c.php');

no matter where b.php was called from.

In fact, this is the preferred way of establishing relative paths, as the extra code frees PHP from having to iterate through the include_path in the attempt to locate the target file.

Sources:

https://stackoverflow.com/questions/2184810/difference-between-getcwd-and-dirname-file-which-should-i-use

Why you should use dirname(_FILE_)

Solution 3 - Php

  1. If include path doesn't start with ./ or ../, e.g.:

     include 'C.php'; // precedence: include_path (which include '.' at first),
                      // then path of current `.php` file (i.e. `B.php`), then `.`.
    
  2. If include path starts with ./ or ../, e.g.:

     include './C.php';	// relative to '.'
    
     include '../C.php';	// also relative to '.'
    

The . or .. above is relative to getcwd(), which defaults to the path of the entry .php file (i.e. A.php).

Tested on PHP 5.4.3 (Build Date : May 8 2012 00:47:34).

(Also note that chdir() can change the output of getcwd().)

Solution 4 - Php

The accepted answer of Pekka is incomplete and, in a general context, misleading. If the file is provided as a relative path, the called language construct include will search for it in the following way.

First, it will go through the paths of the environment variable include_path, which can be set with ini_set. If this fails, it will search in the calling script's own directory dirname(__FILE__) (__DIR__ with php >= 5.3.) If this also fails, only then it will search in the working directory ! It just turns out that, by default, the environment variable include_path begins with ., which is the current working directory. That is the only reason why it searches first in the current working directory. See http://php.net/manual/en/function.include.php.

> Files are included based on the file path given or, if none is given, > the include_path specified. If the file isn't found in the > include_path, include will finally check in the calling script's own > directory and the current working directory before failing.

So, the correct answer to the first part of the question is that it does matter where is located the included calling script. The answer to the last part of the question is that the initial working directory, in a web server context, is the directory of the called script, the script that includes all the others while being handled by PHP. In a command line context, the initial working directory is whatever it is when php is invoked at the prompt, not necessarily the directory where the called script is located. The current working directory, however, can be changed at run time with the PHP function chdir. See http://php.net/manual/en/function.chdir.php.

This paragraph is added to comment on other answers. Some have mentioned that relying on include_path is less robust and thus it is preferable to use full paths such as ./path or __DIR__ . /path. Some went as far as saying that relying on the working directory . itself is not safe, because it can be changed. However, some times, you need to rely on environment values. For example, you might want set include_path empty, so that the directory of the calling script is the first place that it will search, even before the current working directory. The code might be already written and updated regularly from external sources and you do not want to reinsert the prefix __DIR__ each time the code is updated.

Solution 5 - Php

Short answer: it's relative to the including script.

TFM explains it correctly:

> If the file isn't found in the include_path, include will check in the calling script's directory and the current working directory

So, if /app/main.php says include("./inc.php") that will find /app/inc.php.

The ./ is not strictly necessary but removes any dependency on include_path.

I would not rely on finding include files in the current working directory in case someone changes it with chdir().

Solution 6 - Php

dir
-> a.php
-> c.php

- dir2 
-> b.php

To include a in b you need to include("../a.php");

To include b in c you need to include("dir2/b.php");

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionYarinView Question on Stackoverflow
Solution 1 - PhpPekkaView Answer on Stackoverflow
Solution 2 - PhpYarinView Answer on Stackoverflow
Solution 3 - PhpJohnny WongView Answer on Stackoverflow
Solution 4 - Phpuser2066805View Answer on Stackoverflow
Solution 5 - PhpDenis HoweView Answer on Stackoverflow
Solution 6 - PhpOlliView Answer on Stackoverflow