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

101,023

Solution 1

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

@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:

Difference Between getcwd() and dirname(__FILE__) ? Which should I use?

Why you should use dirname(__FILE__)

Solution 3

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 4

  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 5

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().

Share:
101,023

Related videos on Youtube

Yarin
Author by

Yarin

Products PDF Buddy - Popular online PDF editor Gems Snappconfig - Smarter Rails app configuration

Updated on July 08, 2022

Comments

  • Yarin
    Yarin almost 2 years

    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?

  • Yarin
    Yarin over 12 years
    @Pekka- awesome- just what I was looking for. For further info, see stackoverflow.com/questions/2184810/…
  • Yarin
    Yarin over 12 years
    @Olli- you're missing the point of the question- I was asking about how relative paths are determined when includes are chained.
  • Johnny Wong
    Johnny Wong almost 10 years
    To conclude, A.php's path is first searched for C.php, then B.php's path is searched if no prefix './' or '../' in the include. (Assume default PHP's setting)
  • Nick Bedford
    Nick Bedford over 9 years
    You can also use __DIR__ for that exact purpose.
  • Pacerier
    Pacerier over 9 years
    So if you start the string with ./, does it check the calling script's directory first or the current working directory first?
  • Johnny Wong
    Johnny Wong about 9 years
    This answer is somewhat overkill: NO NEED include(dirname(__FILE__)."/C.PHP");, because include("C.PHP"); is enough (Yes! C.PHP can be in same directory as B.PHP) It may fail only when there are two C.PHP files in your project.
  • Johnny Wong
    Johnny Wong about 9 years
    To make it more clear: It is relative to both B.php and A.php if without "./" or "../" prefix in the include path. See my answer below.
  • HartleySan
    HartleySan almost 8 years
    Thanks for cluing me in to using chdir(__DIR__) to fix the problem.
  • Johnny Wong
    Johnny Wong over 7 years
    @Denis Howe No, you are already depending on the current working directory if your include path start with ./. i.e. chdir("/app/other") will make include("./inc.php") fail. Thus, use include("inc.php") to be safe in this case.
  • Johnny Wong
    Johnny Wong over 7 years
    @Pacerier if the string start the with ./ or ../, it only check current working directory. (include_path and directory of calling script (B.php) are both ignored). See my answer for more detail.
  • Miguel Vieira
    Miguel Vieira almost 7 years
    I'd like to add something, I had a file called csb.php, included a functions file from a folder, and the functions file included a file named t.php from the same folder as the functions file, When I tried including a file named csb.php from the folder t.php was, it started including the same csb.php that called the functions file, but when I changed the second csb.php to csbe.php it started working right away. So, it looks like it priorizes the first folder, then the second include folder!
  • herzbube
    herzbube about 6 years
    [...] getcwd(), which defaults to the path of the entry .php file [...] - not necessarily true. If I run PHP on the command line then getcwd() refers to the current working directory of the shell, regardless of which .php file I invoke. I can imagine, though, that if PHP is run in a web server environment that the environment initializes the current working directory to the entry .php file. Tested on macOS with PHP 7.2.2 installed via Homebrew.
  • Sz.
    Sz. about 6 years
    "if this fails, it will search in the calling script's own directory dirname(__FILE__) (__DIR__) with php >= 5.3.)" Are you sure? Where is it documented? I hope you are wrong, and PHP does not use __FILE__ and __DIR__ for this purpose, as that would promptly break including "sibling" scripts from symlinked ones! :-o (Which, fortunately, appears to work fine here, on my 7.1 setup.)
  • Kevin Y
    Kevin Y almost 2 years
    @JohnnyWong It can fail in many ways. PHP can have its include_path misconfigured if . doesn't appear in it and thus it won't look in current working directory. Also the working directory can change, either by the entry point or by changing it with chdir (as shown in your post). When going through relative includes, it needs to go through the full list of include_paths and it could potentially find the "wrong" file depending on configuration. It's a lot less error prone to use absolute paths: e.g. __DIR__, dirname(__FILE__) etc. But feel free to use relative paths if you know the risks.
  • G M
    G M almost 2 years
    Note that the dirname function has an optional second parameter (type integer) that enables you to traverse 'n' number of parent directories relative to the current script. You can find more details here: php.net/manual/en/function.dirname.php