124

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
  • 173,523
  • 149
  • 402
  • 512
  • More accurate than accepted answer in my opinion : https://stackoverflow.com/a/23902890/1636522. –  Oct 27 '17 at 16:57

6 Answers6

141

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");
Muhammad bin Yusrat
  • 1,433
  • 1
  • 14
  • 19
Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • @Pekka- awesome- just what I was looking for. For further info, see http://stackoverflow.com/questions/2184810/difference-between-getcwd-and-dirname-file-which-should-i-use – Yarin Sep 11 '11 at 14:35
  • 8
    You can also use `__DIR__` for that exact purpose. – Nick Bedford Dec 08 '14 at 23:27
  • 1
    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 Mar 26 '15 at 03:28
  • 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. – Johnny Wong Mar 26 '15 at 03:28
  • @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. – Kevin Y Jun 17 '22 at 01:10
  • 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: https://www.php.net/manual/en/function.dirname.php – G M Jun 18 '22 at 21:11
26

@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__)

Pete
  • 1,305
  • 1
  • 12
  • 36
Yarin
  • 173,523
  • 149
  • 402
  • 512
  • 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! – Miguel Vieira Aug 03 '17 at 17:21
19
  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().)

Johnny Wong
  • 945
  • 9
  • 16
  • 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) – Johnny Wong May 28 '14 at 10:02
  • Thanks for cluing me in to using `chdir(__DIR__)` to fix the problem. – HartleySan May 27 '16 at 16:26
  • _[...] `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. – herzbube Feb 25 '18 at 13:26
19

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.

  • *"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.) – Sz. Mar 31 '18 at 18:29
6

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

Denis Howe
  • 2,092
  • 1
  • 23
  • 25
  • So if you start the string with `./`, does it check the calling script's directory first or the current working directory first? – Pacerier Jan 29 '15 at 04:44
  • 2
    @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 Dec 19 '16 at 04:05
  • @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. – Johnny Wong Dec 19 '16 at 04:07
-2
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");

Olli
  • 752
  • 6
  • 20
  • 5
    @Olli- you're missing the point of the question- I was asking about how relative paths are determined when includes are chained. – Yarin Sep 11 '11 at 14:38