There are fundamental differences between PHP scripts that are run by a web request, and those that are run from the command line. One of the main ones is that the environment settings will be completely different, including the path. Every few years I forget this and it comes back to bite me.
Generally I use relative paths for require_once()
and similar functions. This is because it makes the code more portable when moving to a different storage location or a different server (e.g. working with development and live servers). The downside is that the relative paths are likely to point to completely the wrong location for scripts that are called via the command line. There are various reasons for wanting to run PHP scripts on the command line, one of the most common being for cron jobs. Of course they can be run using wget
or curl
or suchlike, but that causes extra overhead with the web server, not to mention potential problems with timeouts and so on.
To avoid this kind of problem, when writing a script that will be run as a cron job, I now always put the following code at the top:
chdir( __DIR__ );
This changes the current working directory to the path of the script, which means that require_once()
will work as expected. In addition, I strongly recommend writing cron scripts that do not produce any output unless there is an error, and making sure that your cron settings will notify you by email of any output produced. This follows standard best practice guidelines for cron jobs. It always surprises me how many cron jobs I see where the author couldn’t be bothered to differentiate between correct behaviour and errors, and then redirects all output to /dev/null
because they are sick of being bombarded with emails.
Comments
Folders outside of working directory
Can understand switching to current directory to run scripts / includes within one folder ... but what about when you need to access folders OUTSIDE of the current directory? Let's say I am in "/cgi-bin/sales/sales_cron.php", and now wish to access a file in "/cgi-bin/track/data/this,dat"
Offline testing, I used "getCWD", and then broke it apart / reconstructed to get back to cgi-bin (/home/domain/cgi-bin/). I then append that to the other file ("/home/domain/cgi-bin/"."track/data/this.dat") ... but not sure if "getCWD" will work like this on CRON
Or should I use some other method?
Re: Folders outside of working directory
Hi Christopher,
This depends a bit on how your code is structured, and particularly how the different folders are related. One option would be to use a configuration variable to specify where the file(s) are located. Another one would be something like this:
$dir = realpath(__DIR__ . '/../track/data/this.dat');
My preference is to use a configuration variable when the data is from a separate source, and the __DIR__
method when it's part of the same source tree, because in that case you can be fairly sure that the relative structure will remain the same between deployments.
Hope that helps!
Works for scripts that run a PHP file, too
I sometimes have cron jobs that start a bash shell script, which then runs a PHP file. In that case, the method mentioned here works great because it changes the current directory for the PHP file, but not for the shell script that ran it. So when the PHP file exits, the shell script is still running in the same directory it was in before. Thanks for this!
Never stop learning even after 20 years, this one is pretty helpfull and simple solution. Thanks a lot :)