tomorrows web, here today

Resolving PHP Relative Path Problem

php-cover

Using relative paths in PHP may prove to be a little tricky for beginners. Especially if you are coming from another language. The way the paths are resolved in PHP is different enough from other languages that I decided to write this short article to explain how it works.

Problem:

When a PHP file includes another PHP file which itself includes yet another file — all being in separate directories — using relative paths to include them may raise a problem. PHP will often report that it is unable to find the third file, but why? Well the answer lies in the fact that when including files in PHP the interpreter tries to find the file in the current working directory. In other words, if you run the script in a directory called A and you include a script that is found in directory B, then the relative path will be resolved relative to A when executing a script found in directory B. So, if the script inside directory B includes another file that is in a different directory, the path will still be calculated relative to A not relative to B as you might expect. This is a very important point to understand about the difference between PHP and other languages like C/C++.
To further clarify this point, lets consider the following example taken from a post by “œvvo at geocities dot com” at http://bugs.php.net/bug.php?id=9673:

Running ‘test.php’ fails with:

This is because the code looks for ‘../b.inc’ relative to ‘./’ not relative to ‘./include/a/’.

Solution:

In general, there are 2 solutions to this problem:

  1. Use $_SERVER["DOCUMENT_ROOT"] – We can use this variable to make all our includes relative to the server root directory, instead of the current working directory(script’s directory). Then we would use something like this for all our includes:
  2. Use dirname(__FILE__) – The __FILE__ constant contains the full path and filename of the script that it is used in. The function dirname() removes the file name from the path, giving us the absolute path of the directory the file is in regardless of which script included it. Using this gives us the option of using relative paths just as we would with any other language, like C/C++. We would prefix all our relative path like this:
    You may also use basename() together with dirname() to find the included scripts name and not just the name of the currently executing script, like this:

I personally prefer the second method over the first one, as it gives me more freedom and a better way to create a modular web application.

Note:  Remember that there is a difference between using a backslash “\” and a forward (normal) slash “/” under Unix based systems. If you are testing your application on a windows machine and you use these interchangeably, it will work fine. But once you try to move your script to a Unix server it will cause some problems. Backslashes (“\”) are also used in PHP as in Unix, to indicate that the character that follows is a special character. Therefore, be careful not to use these in your path names.

This concludes this tutorial, I hope you enjoyed it and learned something useful. Thank you for reading, and if you have any feedback please post here or contact me directly.

  • Ramires

    I know this is old, but as they say: ‘Old is gold!’
    Thanks, brother!
    Help me a lot.
    Cheers!

    • yagudaev

      Thanks Ramires :). I am glad you found this to be useful.

  • Scott Richardson

    Method 2 didn’t work for me, however method 1 worked fine!

    • yagudaev

      Method 2 is different, you have to reference your included scripts relative to the location of the script you are writing the include in.

  • http://www.facebook.com/angela.poire Angela Poire

    Very helpful. Thank you!

    • yagudaev

      Glad you found it helpful :).

  • Homer Flagg

    Dude, you were the first who could provide this solution in a way that actually worked. And it’s not even complicated. Thanks!

    • yagudaev

      Glad you were able to solve your problem :).

  • Davex

    Thank you, it was very helpful.

    • yagudaev

      I am happy to see you found this helpful.

  • Shervin

    After reading a lot about this problem in another websites, this was very helpful . thank you

    • yagudaev

      Your welcome :). I am glad you found this helpful.

  • jithin

    You got a typo there, in the second method. You are saying in the explanation to use dir(), but actually its dirname() which is shown in the example correctly.

    • yagudaev

      thanks for pointing it out, corrected :).

      • Anon

        There is another dir() in second method

        • yagudaev

          Thanks :). Corrected now.

  • P. Silva

    Thanks. This solved a problem for a PHP newbie (me).

  • http://twitter.com/skierpage S Page

    If you don’t need backwards compatibility you can use the magic constant__DIR__ in PHP 5.3. It’s the same as dirname(‘__FILE__’), giving the directory of the current script.

  • http://www.facebook.com/kaleazy Kyle Anthony Hill

    Thank you, this is perfect!

  • Alvaro

    Thank you was very helpful!!!

  • Pingback: PHP – Changing from Relative to Absolute Paths | I'm a Human Inbox Programming Journal

  • Hiranmoy Chatterjee

    Dear friend……..you have solved my everything…..I love you dear…

  • isaacewing

    aweome, thank you for sharing… my solution was the second one… i have a dev environment and i need it to programmatically decide which to use ../includes/ vs includes/

  • neo

    How to make this work on local system

  • http://w3development.co.uk/ Andrew Pendlebury

    Or, 3. If you are including files from a handful of known locations then you can modify the include_path in your config.php script (a file that is included on every page, possibly in the document root). By including these locations in the include_path means that you don’t need to specify any path at all in your includes.

  • Julian

    Thank you very much!!! :)

  • Chris

    I just tried out some things and found that there is inconsitent behaviour.
    I have files:

    a.php
    b/b.php
    b/c/c.php
    d.php

    a.php includes b/b.php. So far everything is OK.

    Then b.php includes c.php. *Two paths work*
    include c/c.php AND
    include b/c/c.php
    That was unexpected.

    c.php includes now d.php
    However the third time only one path works. The one from the original directory:
    include d.php

    • http://w3development.co.uk/ Andrew Pendlebury

      I’m not sure that I follow your last example, but note that if you are specifying relative paths then the include_path will be searched.

  • http://polycademy.com/ Roger Qiu

    How would you get the front controller’s path? That is the path to index.php? This is the opposite of what you’re showing.

    • yagudaev

      If you want to get the name of the currently executing script use: $_SERVER['PHP_SELF']. So it will give you index.php. If you want the URL, $_SERVER["REQUEST_URI"]. But since you used the word controller, I would assume you are using an MVC framework, in which case you should use the abstraction it gives you to access URLs.

  • none

    Remember there is always ../../ ect. so you can always reverse traverse the ghetto way.

  • Quaki G

    thanks for that great tutorial. it brought me one step closer to the solution but all is not well with me. I am still getting the error: include(C:xampphtdocsssprotectedviewsgenerate/html/codobar.php): failed to open stream: No such file or directory.

    if i change the forward slash to backslash, the path is correct but it still fails to include the file.. any suggestions would be appreciated

  • J. Alexander Curtis

    Thanks, this is exactly what i have been trying to figure out. My current solution was creating manual variables before the include statements to the filepath to root from that file, and then referencing them in the included files.

    I knew there was a better way and this is it.

  • Sorin

    Thanks a lot, great explanation…method 1 works perfect on different servers

  • Isaac

    very simple solution::
    1) relocate all publicly executable files to the base reference directory of your choice, using c

    chdir(../);
    2) refer all includes and requires in reference to your chosen base directory

  • Richard

    What about using set_include_path()?: http://php.net/manual/en/function.set-include-path.php

    Also in C/C++ programming the usual solution was to make sure that any directories containing library files was present in the include path settings of a project.

    • yagudaev

      You are right. You could do that. There is only one draw back to it, which is that you can accidentally have something you didn’t expect included. However, most of my time now is spent programming in Ruby on Rails. So I love the implicit nature of includes personally and find it cleans the code base.

      Maybe you can write a blog post about it. I would recommend digging into major PHP open source projects to see how they do things. I will link to your blog post from here. I have not done PHP in many years, so it is best for someone who uses it on a daily basis to weigh in on this method.