Today I made a classic blunder in PHP programming. It is one that many make and certainly one I have made before. But the frustrating thing about this issue is it probably would have been caught by a simple unit test or, in lieu of that, something as simple as trying to capture output of my script from the go.
I was working on the command line (something I have been spending a lot more time doing) building a background processing application that will be triggered by the web. The process is expected to take between 45 minutes and an hour each time it is ran and will be ran one time a month at the discretion of an administrator (hence the reason it is not set as a cron job).
One of the very first lines of the CLI script looks like this:
<?php // Define our path for all includes and file writes define('APPPATH', realpath('.')); ?>
It would seem simple enough, right? Basically that little line of code defines a constant called APPPATH that would essentially describe the path to the location of the file that is setting the constant. At least that is what I thought. And every test I ran led me to believe that I had indeed made the right choice to set the path the way I did.
I ran the script, and even other scripts that derived code from the script, from the command line on my local Ubuntu machine, from the command line on our Fedora dev machine and from the command line on our Ubuntu production server. I have similar snippets that are working on all of our machines, and these snippets work interactively, through cron and through the web.
But today something happened that I did not intend. As I attempted to run my last process test of this long running script through the web I found myself in a place where my script would not run. It was being triggered properly. It was just not actually doing anything.
After an hour of trying to figure out what I was doing wrong I solicited the wisdom and advice of two of my colleagues who are seasoned Unix professionals and after a couple of minutes I was able to begin to see what was wrong. Can you guess what it was?
That’s right… PHP, on the web, was applying its scope to the CLI script that it was calling. The reason it had worked in all cases prior to triggering it by the web was that I was logged in as me and calling the script as a CLI script interactively, through the prompt. That means that the setting of the APPPATH constant was happening as expected and to what I expected.
However, from the web, when PHP runs as an apache module, it calls the CLI script from the scope of the web server. That means that the use of realpath() on the location ‘.’ (current working directory) was assuming the working directory was the web server root, not the location of where the script actually resided.
That’s right folks, I lost track of the scope in which I was working. Like a dope.
The simple solution to this problem was to change where the script looks to set its own directory. Can you think of what I could have used, instead of ‘.’ as the location to pass to realpath() so that it knows, without a doubt, what its own path is?
<?php // Get the real path to the current directory location OF THIS FILE define('APPPATH', realpath(dirname(__FILE__)));/ ?>
I hate it when something this simple causes such deep pain and suffering, needlessly.