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 theSITE_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'] ); ?>
This won’t fly on non-apache servers such as IIS as $_SERVER[‘DOCUMENT_ROOT’] is not set.
I’ve always done that and I’m glad to see that I’ve been doing it right!
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….
It dosen’t have to, it is just a bit more intelligent to do so
< ? php require_once $_SERVER[‘DOCUMENT_ROOT’] . ” /common/header.php ” ; ? >
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.
Holly Crap!
It’s not working in my WAMP instalation. Is there anything else to have in mind to implement this?
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.
Also, be aware that Windows file paths use the backslash “\”, and *nix-based systems use the forward slash “/”.
This is MUCH better:
<?php
// index.php
$path = realpath(dirname(__FILE__)) . “/”;
include_once $path . “/common/header.php”;
?>
Enjoy! ;D
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.
Hi Chris and everyone,
really useful tip.
We would like to recommend a more efficient solution using one line of PHP:
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.
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.
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.
it would be simpler to just do it like this yoursite.com/images/sample.png
Chec out this jquery image rotator cris i try to DM you on twitter
http://malsup.com/jquery/cycle/
Better yet you could add your document root to the include path list so that you don’t need to create the path:
then you can just do:
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.
Very nice. And keep these simple hints and tricks coming. I appreciate them!
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!
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.
Heh… I’ve been working with PHP for about 6 months now and I never thought of this. Nice work!
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 .
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.
I’ve written this one:
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?
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.
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
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:
i could kiss you for that snippet of code. finally something i can get to work, thanks kyle! :)
So if:
<img src="/images/logo.png" alt="logo" /
Starts at root, what does this do?
<img src="./images/logo.png" alt="logo" />
The bit of
<img src="./images/logo.png" alt="logo" />
would basically reference the file logo.png in the folder images relative to the page’s location.
If you keep all your images in say http://somedomain.com/images/ but your file is in http://somedomain.com/docs/, the url it would use for logo.png would be http://somedomain.com/docs/images/logo.png.
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:
Now all includes made would be relative to the document root. So you can just use:
Ahhhh, did not know about “set_include_path”, that is clearly the most efficient way to go if doing several includes.
Hey Chris, loving your work. Just a quickie – why not just do this instead?:
Seems more natural to me.
I think the comment engine chewed up your code example. Feel free to email it to me at [email protected] and I’ll update the comment. Thanks Matt!
you can also do require(‘filename.ext’) which will stop performing anything beyond that line if no file is found.
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