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. Returns false if 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

  1. Save this as paths.php in 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";
  2. 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 (/root for 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_BINARY constant, or which php in a shell. On Debian 13 it is /usr/bin/php, a link to /usr/bin/php8.4.
  • Loaded php.ini: php --ini or php_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/php on 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__, or cd to 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.

Related services

KVM VPS hosting

NVMe SSD and full root access, with Free Basic Managed Support.

Unmanaged dedicated servers

full root access and free IPMI KVM, with Free Basic Managed Support.

Managed dedicated servers

our engineers look after the server for you, from $135 a month.

Was this answer helpful?

Still stuck? Open a ticket