Updated: 8 October 2026 · Applies to: PHP 8.3.35 (CLI and built-in web server) and PHP 8.4.26 on Debian 13 (CLI, PHP-FPM and cron); the same constants and functions work in every current PHP 8 release
Use __DIR__. It holds the absolute path of the folder that contains the file it is written in, without a trailing slash, and it does not change with the folder you start the script from. __FILE__ holds the full path including the file name.
<?php echo __DIR__; // /var/www/example.com/public_html echo __FILE__; // /var/www/example.com/public_html/paths.php require __DIR__ . '/config.php'; // always the config.php next to this file
__DIR__ is the same as dirname(__FILE__). Both resolve symlinks, so you get the real path on disk.
Which path function to use
__DIR__: folder of the current file. Use this for includes and for files that sit next to your code.__FILE__: full path and name of the current file.dirname(__DIR__),dirname(__DIR__, 2): one or two folders up (the second argument exists since PHP 7.0).realpath($path): turns a relative path, or one with..or a symlink in it, into a clean absolute path. Returnsfalseif the file does not exist.getcwd(): the current working directory of the PHP process. This is not the script's folder; it depends on how the script was started (see below).$_SERVER['SCRIPT_FILENAME']: the main script that was started, not the included file you are in. On the command line it is exactly what you typed, so it can be relative.$_SERVER['DOCUMENT_ROOT']: the website's document root from the web server configuration. It is empty on the command line.
See the difference with a test script
- Save this as
paths.phpin your site folder:<?php echo "__FILE__ : ", __FILE__, "\n"; echo "__DIR__ : ", __DIR__, "\n"; echo "dirname(__DIR__): ", dirname(__DIR__), "\n"; echo "getcwd() : ", getcwd(), "\n"; echo "SCRIPT_FILENAME : ", $_SERVER['SCRIPT_FILENAME'], "\n"; echo "DOCUMENT_ROOT : ", var_export($_SERVER['DOCUMENT_ROOT'] ?? null, true), "\n";
- Run it from another folder, once with an absolute path and once with a relative one:
$ cd /tmp && php /var/www/example.com/public_html/paths.php __FILE__ : /var/www/example.com/public_html/paths.php __DIR__ : /var/www/example.com/public_html dirname(__DIR__): /var/www/example.com getcwd() : /tmp SCRIPT_FILENAME : /var/www/example.com/public_html/paths.php DOCUMENT_ROOT : '' $ cd /root && php ../var/www/example.com/public_html/paths.php __FILE__ : /var/www/example.com/public_html/paths.php __DIR__ : /var/www/example.com/public_html dirname(__DIR__): /var/www/example.com getcwd() : /root SCRIPT_FILENAME : ../var/www/example.com/public_html/paths.php DOCUMENT_ROOT : ''
__FILE__ and __DIR__ stay the same in both runs. getcwd() follows the shell, and SCRIPT_FILENAME is relative when you typed a relative path.
Inside an included file
__DIR__ and __FILE__ always describe the file they are written in. If paths.php includes inc/helper.php, the same constants inside helper.php point to the inc folder, while SCRIPT_FILENAME still names the main script:
-- inside inc/helper.php -- __FILE__ : /var/www/example.com/public_html/inc/helper.php __DIR__ : /var/www/example.com/public_html/inc SCRIPT_FILENAME : /var/www/example.com/public_html/paths.php
So a library file can always find its own neighbours with __DIR__, whoever includes it.
Why relative paths work in the browser but fail in cron
Relative paths such as 'data.json' or './inc/helper.php' are resolved against getcwd(), and that changes with how PHP runs. In our tests the working directory was:
- PHP-FPM (Nginx or Apache with PHP-FPM) and the built-in web server: the folder of the requested script.
- Command line: the folder you were in when you ran
php. - Cron: the home directory of the crontab owner (
/rootfor root's crontab).
The same script started from /tmp fails like this:
Warning: file_get_contents(data.json): Failed to open stream: No such file or directory in /var/www/example.com/public_html/rel.php on line 3 Fatal error: Uncaught Error: Failed opening required './inc/helper.php' (include_path='.:/usr/local/lib/php') in /var/www/example.com/public_html/rel.php:5
The fix is to build every path from __DIR__:
$json = file_get_contents(__DIR__ . '/data.json'); require __DIR__ . '/inc/helper.php';
One detail: require 'inc/helper.php' without the leading ./ did work from /tmp, because for a bare file name PHP also looks in the calling script's own folder after the include_path. A path that starts with ./ or ../ skips that search, and functions such as file_get_contents() and fopen() never do it. Using __DIR__ avoids guessing.
Go up to a parent folder
Keep configuration outside the web root and reach it from a script inside public_html:
$config = require dirname(__DIR__) . '/config/settings.php'; // /var/www/example.com/config/settings.php echo dirname(__DIR__, 2); // /var/www
dirname() only works on the text of the path. It does not check that the folder exists, and it does not resolve .. inside a path. Use realpath() when you need that.
Turn a relative path or symlink into an absolute path
realpath() resolves symlinks, . and .., and returns false for a file that does not exist. Here /srv/site is a symlink to the real site folder:
$ php -r 'var_dump(realpath("/srv/site/paths.php"), realpath("/srv/site/missing.php"));'
string(42) "/var/www/example.com/public_html/paths.php"
bool(false)
Always check for false before you use the result. According to the PHP manual, realpath() also returns false when PHP lacks execute (search) permission on one of the folders in the path.
Split a path into its parts (pathname, file name, extension)
print_r(pathinfo('/var/www/example.com/public_html/inc/helper.php'));
Array
(
[dirname] => /var/www/example.com/public_html/inc
[basename] => helper.php
[extension] => php
[filename] => helper
)
basename($path, '.php') returns helper, and SplFileInfo gives the same pieces as methods: getPathname() (full path), getPath() (folder) and getFilename().
Other PHP paths people look for
- Path to the PHP binary: the
PHP_BINARYconstant, orwhich phpin a shell. On Debian 13 it is/usr/bin/php, a link to/usr/bin/php8.4. - Loaded php.ini:
php --iniorphp_ini_loaded_file(). On Debian 13 the command line uses/etc/php/8.4/cli/php.ini; PHP-FPM has its own file under/etc/php/8.4/fpm/. - Include path:
get_include_path()(.:/usr/share/phpon Debian 13). - Your site's web root on shared hosting: see What is the path to public html in PHP.
Common problems
- "Failed to open stream: No such file or directory" with a relative path: build the path from
__DIR__, as above. - "open_basedir restriction in effect": the path is correct but outside the folders PHP may read. See open_basedir restriction in effect.
- A script works in the browser but not from cron: cron starts in the home directory, so relative paths point somewhere else. Use
__DIR__, orcdto the folder in the cron line first.
Setting up PHP on your own server? See How to install PHP on Ubuntu 26.04 and 24.04.
Official documentation: PHP magic constants, realpath(), include.