Grow your CSS skills. Land your dream job.

PHP Include from Root

Published by Chris Coyier

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

<img src="http://cdn.css-tricks.com/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'] ); ?>

Comments

  1. Permalink to comment#

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

  2. Permalink to comment#

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

  3. Permalink to comment#

    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
    Permalink to comment#

    < ? 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. Permalink to comment#

    Holly Crap!

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

  7. Permalink to comment#

    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. Permalink to comment#

    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. Permalink to comment#

    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
    Permalink to comment#

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

  15. alex
    Permalink to comment#

    Chec out this jquery image rotator cris i try to DM you on twitter

    http://malsup.com/jquery/cycle/

  16. Permalink to comment#

    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. Permalink to comment#

    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
    Permalink to comment#

    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. Permalink to comment#

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

  21. Permalink to comment#

    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. Permalink to comment#

    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. Permalink to comment#

    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
    Permalink to comment#

    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
    Permalink to comment#

    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
    Permalink to comment#

    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");
    • penelope
      Permalink to comment#

      i could kiss you for that snippet of code. finally something i can get to work, thanks kyle! :)

  28. So if:

    <img src="http://cdn.css-tricks.com/images/logo.png" alt="logo" /

    Starts at root, what does this do?

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

  29. Davis John
    Permalink to comment#

    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”);

    • Ahhhh, did not know about “set_include_path”, that is clearly the most efficient way to go if doing several includes.

  30. Permalink to comment#

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

    Seems more natural to me.

  31. fivetwentysix
    Permalink to comment#

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

  32. define(‘APPLICATION_PATH’, realpath(‘../’));

    $paths = array(APPLICATION_PATH, get_include_path());
    set_include_path(implode(PATH_SEPARATOR, $paths));

    function __autoload($className)
    {
    $filename = str_replace(‘\’, ‘/’, $className).’.php';
    require_once $filename;
    }

    just include this file into your header it automatically fetch all files and include into the header

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

*May or may not contain any actual "CSS" or "Tricks".