54

If a PHP script is run as a cron script, the includes often fail if relative paths are used. For example, if you have

require_once('foo.php');

the file foo.php will be found when run on the command line, but not when run from a cron script.

A typical workaround for this is to first chdir to the working directory, or use absolute paths. I would like to know, however, what is different between cron and shell that causes this behavior. Why does it fail when using relative paths in a cron script?

2
  • This is a great resource as well: stackoverflow.com/questions/2857712/… Commented May 18, 2010 at 14:03
  • 1
    Don't change your PHP files just to make them work from a cron job, instead change the current directory on the cron job line. Check my answer here. Commented Apr 9, 2019 at 20:32

8 Answers 8

112

Change the working directory to the running file path. Just use

chdir(dirname(__FILE__));
include_once '../your_file_name.php'; //we can use relative path after changing directory

in the running file. Then you won't need to change all the relative paths to absolute paths in every page.

Sign up to request clarification or add additional context in comments.

4 Comments

This was driving me mad. This sorted it out perfectly
You can also use chdir(__DIR__); which is a bit more concise.
this only works if you can execute chdir() in your environement. include/require dirname( __FILE__ ) is much more reliable.
I don't like to change the PHP code, instead change the directory at the cron tab, check my answer
14

The working directory of the script may be different when run from a cron. Additionaly, there was some confusion about PHPs require() and include(), which caused confusion about the working directory really being the problem:

include('foo.php') // searches for foo.php in the same directory as the current script
include('./foo.php') // searches for foo.php in the current working directory
include('foo/bar.php') // searches for foo/bar.php, relative to the directory of the current script
include('../bar.php') // searches for bar.php, in the parent directory of the current working directory

Comments

7

The only chance I got "require_once" to work with cron and apache at the same time was

require_once(dirname(__FILE__) . '/../setup.php');

Comments

6

Because the "current working directory" for cron jobs will be the directory where your crontab file exists -- so any relative paths with be relative to THAT directory.

The simplest way to handle that is with dirname() function and PHP __FILE__ constant. Otherwise, you will need to edit the file with new absolute paths whenever you move the file to a different directory or a server with a different file structure.

dirname( __FILE__ )

__FILE__ is a constant defined by PHP as the full path to the file from which it is called. Even if the file is included, __FILE__ will ALWAYS refer to the full path of the file itself -- not the file doing the including.

So dirname( __FILE__ ) returns the full directory path to the directory containing the file -- no matter where it is included from and basename( __FILE__ ) returns the file name itself.

example: Let's pretend "/home/user/public_html/index.php" includes "/home/user/public_html/your_directory/your_php_file.php".

If you call dirname( __FILE__ ) in "your_php_file.php" you would get "/home/user/public_html/your_directory" returned even though the active script is in "/home/user/public_html" (note the absence of the trailing slash).

If you need the directory of the INCLUDING file use: dirname( $_SERVER['PHP_SELF'] ) which will return "/home/user/public_html" and is the same as calling dirname( __FILE__ ) in the "index.php" file since the relative paths are the same.

example usages:

@include dirname( __FILE__ ) . '/your_include_directory/your_include_file.php';

@require dirname( __FILE__ ) . '/../your_include_directory/your_include_file.php';

Comments

3

Another possibility is that the CLI version is using a different php.ini file. (By default, it'll use php-cli.ini and fallback to the standard php.ini)

Also, if you're using .htaccess files to set your library path, etc. this obviously won't work via the cli.

Comments

3

In addition to the accepted answer above, you can also use:

chdir(__DIR__);

3 Comments

only if you are allowed to execute chdir() in the environment you're in
is that common? I've never worked in any environment where that function wasn't allowed.
i have experienced it related to PHP safe_mode. php.net/manual/en/features.safe-mode.functions.php, but this has been deprecated php.net/manual/en/features.safe-mode.php. -- that's deprecated not removed... meaning, it could still be encountered.
2

When executed trough a cron job your PHP script probably runs in different context than if you start it manually from the shell. So your relative paths are not pointing to the right path.

2 Comments

that's right. In fact, the script's working directory is the working directory of the shell. Should use absolute pathnames.
absolute path names are a nightmare to manage as you move files around... just use dirname( __FILE__ )
0

The DIR works although it will not work on my localhost as it has a different path than my live site server. I used this to fix it.

    if(__DIR__ != '/home/absolute/path/to/current/directory'){ // path for your live server
        require_once '/relative/path/to/file';
    }else{
        require_once '/absolute/path/to/file';
    }

1 Comment

still using a conditional statement that can be replaced by dirname( __FILE__ )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.