PSD to HTML conversion PSD to HTML conversion PSD2HTML.com with over 300 professionals takes the designs to HTML and beyond

PHP Include from Root

Dec 19 2008

When I reference images, I almost always do something like this:

<img src="/images/logo.png" alt="logo" />

That is a relative file path, but it begins at the root public directory of the site. That way it always references the same location, no matter what directory that code snippet ends up in. If it didn't begin with that "/", it would be a relative file path still but it would the location would depend on what directory you were in at the time. Might work fine when you are at /index.php, but if that moves to /contact/, the file path breaks because the images folder is in the root not in /contact/.

Common sense stuff.

But this gets a little more complicated when dealing with a server side language like PHP. You can also do includes with PHP like this:

<?php include("header.php"); ?>

Because it doesn't begin with a "/", it suffers from the same problem our images example suffered from. If that include code moves to a different directory, the reference can be broken. But with PHP, simply using that beginning "/" will not work, which can be mighty confusing.

The problem is that PHP can see a bit "deeper" into your servers file system than HTML can. For example, the public web directory of CSS-Tricks actually lives at "/var/www/vhosts/css-tricks.com/httpdocs" on my server. So when you do an include with a "/" at the beginning, it looks WAY down deeper than you are intending it to. You actually want it to look in that public web directory. In my case, "httpdocs".

In order to get this functionality back and have relative file paths that do not change, use this bit of PHP smartness:

<?php
   $path = $_SERVER['DOCUMENT_ROOT'];
   $path .= "/common/header.php";
   include_once($path);
?>

Basic stuff for all you programmers but that one had me stumped for ages.

Another Technique

Read Brian Vanderberg writes in:

I have found that in some environments DOCUMENT_ROOT does not seem to be properly set. I have devised a way that is independent of the server, and whether the hosting provider provides the ability to set an include or auto-prepend path as well.

Each directory contains a 'meta' file called '__php__.php' (or whatever one wants to call it). For any files in that directory, they simply include it as <?php include('__php__.php'); ?>. The file itself simply includes the one in the parent directory all the way up to the site root. The file in the site root then can include other files, a simply way of auto-including files even if a service provider does not support it, and also define a variable such as 'SITE_ROOTDIR', which can then be used later. If the document files are moved to another directory, they will still include the __php__.php file in that directory and still get the SITE_ROOTDIR constant from the top __php__.php file.

I also do something similar for a simple navigation bar, where each directory has a __navbar__.php file, and each page simply includes it at the correct location and it can include parent navigation elements and define its own navigation elements.

One advantage of this is that a part of the site can be sectioned in a sub-directory, and still get the root of that part, even if it isn't the actual document root. A disadvantage is that it may slow down while doing all the includes on a site with heavy traffic.

Yet another:

<?php set_include_path( get_include_path() . PATH_SEPARATOR . $_SERVER['DOCUMENT_ROOT'] ); ?>

Subscribe to The Thread

  1. Mike says:

    This won’t fly on non-apache servers such as IIS as $_SERVER['DOCUMENT_ROOT'] is not set.

  2. jason says:

    I’ve always done that and I’m glad to see that I’ve been doing it right!

  3. Lisandro says:

    THANK YOU SO MUCH!…

    I’ve been complaining about this issue for a while now and thinked it was me that couldn’t configure WAMP to behave properly.

    Thank God you care about PHP Newbies!!! :P

    But (of course) i’ve got a newbie question:

    This snippet must go instead of <?php include (header.php) ?> in every part we have somthing to include right?

    I think it is that way but just to confirm…

    Thanks Again…love your post and screencasts….

  4. Webling says:

    < ? php require_once $_SERVER['DOCUMENT_ROOT'] . ” /common/header.php ” ; ? >

  5. A better option would be something like this:

    $path = dirname(__FILE__) . DIRECTORY_SEPARATOR;

    This will not make any assumptions about any files being inside the document root.

  6. Lisandro says:

    Holly Crap!

    It’s not working in my WAMP instalation. Is there anything else to have in mind to implement this?

  7. Mike says:

    It’s important to remember that your DOCUMENT_ROOT should work in most cases, but that it may not be a valid file system path. Often, in shared hosting enviroments, doing a dirname(__FILE__) returns the true file system path to the current php script, but those two paths may be different. This especially comes into play when determining the absolute URL of a file.

  8. Mike says:

    Also, be aware that Windows file paths use the backslash “\”, and *nix-based systems use the forward slash “/”.

  9. This is MUCH better:

    <?php
    // index.php
    $path = realpath(dirname(__FILE__)) . “/”;
    include_once $path . “/common/header.php”;
    ?>

    Enjoy! ;D

  10. bogardus says:

    My Mistake: It should say MAMP instead of WAMP (I’m on Mac right now) but couldn’t edit my comments.

    I read about that backslash in Windows, but it’s not my case right now.

    I can’t figure out what i’m doing wrong.

    • Honestly I’ve never tried/tested this running PHP on a local machine like you are doing. I wouldn’t be surprised it it behaves a little different than a regular server would.

  11. Hi Chris and everyone,
    really useful tip.

    We would like to recommend a more efficient solution using one line of PHP:

    ini_set('include_path', './' . PATH_SEPARATOR . "./common/". PATH_SEPARATOR . ini_get('include_path'));

    Simply include this line of code in file like config.php once and forget about the paths to the includes, just use include_once("header.php");

    Advantage of this technique is that it does not create additional variable utilizing native PHP “include_path” setting. This solution also protects from the situation when $_SERVER['DOCUMENT_ROOT']; variable differs from the real path to your script.

  12. Thanks — been looking for this for a while. Passed it along to my programmer this morning. He’ll be a loyal fan in no time.

  13. Wow! This came JUST in time. I was about to figure out how I could handle the php includes. Your posts always seem to be relevant to something I’m currently working on.

  14. joe says:

    it would be simpler to just do it like this yoursite.com/images/sample.png

  15. alex says:

    Chec out this jquery image rotator cris i try to DM you on twitter
    http://malsup.com/jquery/cycle/

  16. Jeffrey says:

    Better yet you could add your document root to the include path list so that you don’t need to create the path:

    set_include_path( implode( PATH_SEPARATOR, array(
    $_SERVER['DOCUMENT_ROOT'],
    get_include_path()
    ) ) );

    then you can just do:

    include 'common/header.php';

    and it will look in your doc root first.

    But even better would be to NOT place your php files in the doc root and place them elsewhere instead so that you can’t access header.php directly from the web.

    • That’s smart… header.php is likely to be completely useless if loaded from the web, so keeping them out of the public directory would be smart.

  17. Brad Bice says:

    Very nice. And keep these simple hints and tricks coming. I appreciate them!

  18. php has been a great learning experience for me lately but definitely difficult to understand for a designer, or at least this designer :) php include is awesome though, great tip here!

  19. Isaac says:

    I’ve been using this:

    print("<?php include($_SERVER['DOCUMENT_ROOT']."/header.php"); ?>");

    I think it does the same thing, or at least close to it and is more compact.

  20. Nathan C says:

    Heh… I’ve been working with PHP for about 6 months now and I never thought of this. Nice work!

  21. geeks says:

    Yes, I did it before too ( as jason ) but i thought it’s not correct , i’m happy to see it here .

    Now i see i was correct .

  22. Paul says:

    PHP actually has a configuration variable that contains all the paths it goes to in order to look for a file you are trying to include: include_path
    So, using ini_set(), you could easily overwrite or rather append something to this variable at runtime.

  23. PoNx says:

    I’ve written this one:

    function root_path() {
        if(!preg_match("/^(http:\/\/)/", $_SERVER['HTTP_HOST'])) {
            $server = "http://" . $_SERVER['HTTP_HOST'];
        } else {
            $server = $_SERVER['HTTP_HOST'];
        }
        if(!preg_match("/(\/)$/", $server)) $server = $server . '/';
        $path = explode('/', dirname(htmlentities($_SERVER['PHP_SELF'])));
        $path = $path[1];
        if(!preg_match("/(\/)$/", $path)) $path = $path . '/';
        return $server . $path;
    }
  24. AD says:

    wait, putting a forward slash at the beginning of “/images/logo.png” should go to the root, without using a bunch of “../../etc”? I so something I’ve somehow overlooked all these years?

    When I test it out on my remote host, it works, but doing that locally with the default Apache install in OS X, as well as a MAMP filepath, neither works. How do you develop locally and make this work?

    • Correct.

      Working locally is just weird like that … I don’t have a good answer for you. I avoid doing it just for this reason. Why bother if when you take it live it’s all screwed up?

  25. AD says:

    Thanks for the reply, Chris.

    If that’s the case, what did you mean by “When I reference images, I almost always do something like this:”?

    Thanks for the site. Always a great read.

  26. I’ve found a way to use a single publicly viewed file (index.php), that then uses a slightly modified version of Till Quack’s method of URL parsing, then just set a meta tag in the header of my html to keep all my relative links functioning, like so:

    <base href="http://yoursite.com/" />

    That eliminates most of the headache of relative URLs, and it’s also pretty portable. After I implemented it once, I’ve been able to port the code to every new project without any trouble.

    Your method looks like it’s probably great for dealing with multiple directories, but it seems like it might be tough to maintain if your directories are modified.

    Good to see some PHP on here!

    -Jason

  27. kyle says:

    The code Chris posted works fine for me in MAMP. You could check your php error logs in MAMP (in Terminal type:

    tail -f /Applications/MAMP/logs/php_error.log

    ) to see why it is failing to work. There’s also no real reason to set the path variable in the code if you’re only using it once. This should work just as well:

    php_include($_SERVER['DOCUMENT_ROOT'] . "/common/header.php");
  28. So if:

    <img src="/images/logo.png" alt="logo" /

    Starts at root, what does this do?

    <img src="./images/logo.png" alt="logo" />

  29. Davis John says:

    Nice little tip, Chris!

    Here’s my 2 cents; if you find yourself making a lot of php includes relative to the document root, the following snippet can save a few keystrokes:

    set_include_path($_SERVER['DOCUMENT_ROOT']);

    Now all includes made would be relative to the document root. So you can just use:

    include_once(“common/header.php”);

  30. matt says:

    Hey Chris, loving your work. Just a quickie – why not just do this instead?:

    Seems more natural to me.

  31. fivetwentysix says:

    you can also do require(‘filename.ext’) which will stop performing anything beyond that line if no file is found.

This comment thread is closed. If you have important information to share, you can always contact me.