Relative and absolute paths, in the file system and on the web server.
- Intro
- The difference between absolute and relative paths
- Absolute paths
- Relative paths
- Document root
- Web server paths
- Current working directory
- Console scripts. Single entry point
- Helpful PHP commands and constants
- Comments (13)
Intro
Your site exists in two realms at once: the real and the virtual one.
For the site visitors it's entirely a virtual server, which in many ways is different from a real one. There are no files for starter. I know, it's hard to believe at first, but it's a fact. In the address like http://example.com/file.html
, file.html
is not a file. It's a part of URI, a virtual resource. There could be or could be not a real file with such a name, but it doesn't matter. Your browser cannot know that, and don't need to. All it needs to know is an address.
For the site developer, on the other hand, their site is a certain program running on a particular server, on the very real computer with HDD, files and directories. And your PHP script, while reading data files or including other scripts, is working with such real files that exist on the physical medium.
So this dualism is the root of many problems.
PHP users confuse these matters badly at first, doing things like being unable to locate an existing file, confusing hyperlinks with files, including local files via HTTP and such.
However, to sort these things out all you need is to grasp just two simple concepts:
- The difference between absolute and relative paths.
- The difference between the root of the web server and the filesystem root.
The difference between absolute and relative paths
It's fairly simple.
- If the path is built starting from the system root, it is called absolute.
- If the path is built starting from the current location, it is called relative (which makes sense, as it is relative to our present position)
It's exactly the same as with the real life directions. Given the absolute address, a postal one, like "7119 W Sunset Blvd West Hollywood, CA 90046" you can find the location from anywhere. However, given the relative directions, like "keep three blocks this way and then and turn to the right" would work from the current location only, otherwise sending you astray.
So it goes for the paths in the computer world: given the absolute address, you can always get to the place, no matter from where you started. Whereas relative path is tricky, and should be used with caution, only when you positively know where you are at the moment.
Absolute paths
So again: an absolute path is one starting from the system root
Some absolute path examples:
/var/www/html/forum/index.php
/img/frame.gif
C:\windows\command.com
Note that in Unix-like systems (and web-servers) the root is defined as a slash - /
. And this is very important to know. It is not just a marker, but already a full qualified address, a path. Type cd /
in your unix console and you will get to the root directory. Exactly the same is true for all web servers. So you can tell that in the http://example.com/
address the trailing slash is not for the decoration but a regular address itself - the address of the home page.
On Windows, the filesystem doesn't have the common root for the whole system but split between disks, so an absolute paths starts from the drive letter. Whereas each disk has its own root, which is a backslash - \
. So you can type cd \
and get to the root of the current disk.
So you can tell that windows is rather confusing, but for the simplicity we would pretend that we have only one disk, and within its boundaries the rules are pretty much the same as in Unix.
So now you can tell an absolute path from a relative one - it is starting from the root, which is:
- on a Unix file system it's
/
- on a web serer it's again
/
- on Windows it's either
\
(for the current disk) orD:\
(system-wide)
Relative paths
If you don't supply the root, it means that your path is relative.
The simplest example of relative path is just a file name, like index.html
. So one should be careful with relative paths. If your current directory is /about/
then index.html
would be one, but if you switch it to /contacts/
then it will be another.
Other relative path examples:
./file.php
(the file is in the current folder. The same as justfile.php
)images/picture.jpg
(the file is in the images folder that is in the current directory)../file.php
(file is in the folder that is one level higher than the current directory)../../file.php
(file is in the folder that is two levels higher than the current directory)
What you ought to know is that the system, when encountered a relative path, always builds it up to the absolute one. Both web-server and file system are doing that but different ways. So, let's learn them.
Document root
This is the most interesting part. There is a point where the real world meets the virtual one.
Imagine there is a file like /var/www/site/forum/index.php
.
While on the web-server its address is http://www.site.ru/forum/index.php
And here the point can be clearly seen: there is a part, common for both addresses: /forum/index.php
, which is the very source of confusion.
For the browser, this path is perfectly absolute, starting from the root of the web-server.
Whereas for the script it's only a part of the full path - the filesystem path. And if you try to use it in PHP it will result in a failure: there is no /forum/
catalog on the HDD!
To get the working path to this file, we have to add the missing part. In our example it's /var/www/site
, which is called DOCUMENT_ROOT
and is the most important configuration option for the file system interactions. In PHP you can access it via $_SERVER['DOCUMENT_ROOT']
.
So now you can tell that to make any file system path work, it should be absolute and built using DOCUMENT_ROOT
. So a correct PHP code to access /forum/index.php
from PHP would be
$path = $_SERVER['DOCUMENT_ROOT'] . "/forum/index.php";
here we are using web-server part of the path, prepending it with the document root. Voila!
Web server paths
are much simpler.
Like it was said before, for the browser, there are no files on the server. A site user never has an access to the server's file system. For the browser, there is a site root only. Which is constant and always simply a slash.
Therefore, to make an HTML link absolute, just build it from the site root - and you will never see a 404 error for the existing file again!
Imagine your site has two sections,
http://www.example.com/about/info.php
and
http://www.example.com/job/vacancy.php
and in the info.php
you want to link to vacancy.php
. If you make it as is, <a href=vacancy.php>
, then browser won't find it! Remember, it always tries to build up the link to the full one, using the current location, which is /about/
and so the resulting path is /about/vacancy.php
which is wrong. To make it right, we have to make this link absolute, starting from the site root: /job/vacancy.php
So it goes for all the internal links on the site - images, js and css files, hyperlinks or any other resource that can be clicked on or loaded on the page.
For the local resources it's better to make it path only, without protocol and domain - like /job/vacancy.php
. Whereas for the external resources these attributes are obligatory, and so it should be a fully qualified URL like http://www.example.com/job/vacancy.php
.
Current working directory
The current working directory (also current directory, working directory, CWD) is the key element in relative paths. It's the directory, from which relative paths being built up.
On a web-server, it's a directory, where the requested php file stays. So if you are requesting an URL like http://example.com/about/index.php
, the current working directory would be:
/about
for the browser/var/www/html/about
for PHP/filesystem (given the document root is/var/www/html/
)
therefore, all relative paths in the HTML on that page will be interpreted by browser as starting from /about
:
- a link
<a href=history.php>
will be requested as /about/history.php - an image
<img src=logo.png>
will be requested as /about/logo.png
And likewise, for PHP all relative paths are starting from /var/www/html/about
.
In a console, the PHP's current working directory is equal to the shell's current directory. It means that while in /home/user
and calling php folder/file.php
command, the CWD will be still /home/user
.
You can get the current working directory using getcwd()
function or change it using chdir()
.
Console scripts. Single entry point
It's a pity, but for the console scripts our useful $_SERVER['DOCUMENT_ROOT']
variable is unavailable. So we are bound to use paths relative to the calling script, derived from the current script's location.
For example, if your application is hosted in /var/www/app
and there are two subfolders, /var/www/app/bin
and /var/www/app/config
, and you want to access the latter from the former, you can write the following code:
$config_path = __DIR__.'/../config/settings.php';
require $config_path;
Although technically absolute (starting from a slash), this path is essentially relative to the calling script, because if the calling script will be moved into another directory, it won't find the configuration file anymore.
This is why it is recommended to use a single entry point for your application. Or - as in our case - two entry points, one for web requests and one for console commands.
So for our fictional application we would have three files - an entry point for the web front, an entry point for console applications and a bootstrap file:
- /var/www/app/html/index.php
- /var/www/app/bin/console.php
- /var/www/app/config/bootstrap.php
Then we could write the following code (among other things) in bootstrap.php
:
define('ROOT_DIR', realpath(__DIR__.'/..'));
to define the ROOT_DIR
constant that contains the path to our application's root directory (which is directly above the config
dir).
And then in both index.php
and console.php
the
require __DIR__.'/../config/bootstrap.php';
to make all the bootstrap stuff available, including the ROOT_DIR constant. From now on we can use it to build absolute paths starting from the root directory (as long as our scripts are called through the entry point either web or console one):
include ROOT_DIR.'/config/settings.php';
Example implementations can be found in Laravel's Artisan or Symfony Console.
Of course, both entry points should implement a sort of resolver to call all other pages and console scripts but that's slightly out of scope of this article.
Helpful PHP commands and constants
There are may hepful commands and constants in PHP to ease the path interpolation. Some of them are:
__FILE__
a constant that contains the full absolute path to the file which is currently executing.__DIR__
a constant that contains the path to a directory where lies the file which is currently executing (effectively it's just__FILE__
without the filename and the ending slash)realpath()
command will convert a relative path to an absolute onegetcwd()
will give you the current directory
Related articles:
- PHP error reporting
- Do you really need to check for both isset() and empty() at the same time?
- What's wrong with popular articles telling you that foo is faster than bar?
- MVC in simpler terms or the structure of a modern web-application
- How to get a single player's rank based on the score
- Articles
- Do you abuse the null coalescing operator (and isset/empty as well)?
- Operator precedence or how does 'or die()' work.
- Why should I use prepared statements if escaping is safe?
- Numerical strings comparison
- Do generators really reduce the memory usage?
- How to make Stack Overflow a nice place
- Iterating over array getting look-ahead items along
- How to debug small PHP programs
Add a comment
Please refrain from sending spam or advertising of any sort.
Messages with hyperlinks will be pending for moderator's review.
Markdown is now supported:
>
before and an empty line after for a quote