Scope? Nope. Dope!

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:

// 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?

// 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.

Customizing Subversion Permissions

I spent the better part of the morning this morning learning how to set up Subversion to allow anonymous checkouts of repositories while maintaining authentication requirements for checking in. It was quite a learning lesson, but the Subversion book and several Google searches actually get things working the way I want them.

Anyway, what I had to do was modify my httpd.conf (this could potentially be done in the subversion.conf, but I have virtual hosted my svn repos so I made these changes in my httpd.conf) to change the way permissions were being served. Keep in mind that I am not usering svnserve to serve up my repos but am using Apache instead. The changes that I made to httpd.conf were inside the <Location> block set up for the virtual host for my subversion repos and look like:

<Location /repo-url-path>
  DAV svn
  SVNParentPath /path/to/repos

  # Taken from the sample on path based auth
  AuthzSVNAccessFile /path/to/repos/auth/authz
  # Try anonymous access first, resort to real
  # authentication if necessary.
  Satisfy Any
  Require valid-user
  # How to authenticate users
  AuthType Basic
  AuthName "Everah Projects Code Repositories"
  AuthUserFile /path/to/svn-auth-file

As you can see, I created an AuthzSVNAccessFile named authz and put it in a directory called /auth/ that was off of my repos directory root. I then added the SVN instruction to use that file in my httpd.conf.

The next step was to add the Satisfy Any and Require valid-user lines after that but before the AuthType information. This tells SVN to look for permissions in the permissions file and apply those as described in the file. Then SVN is allowed to open up access to those that have it and require validation where it is required.

After I created the authz file I made it look something like this:
# Make groups for easier addition later on of permissions to contributors
devs_all = robert
devs_padlock = robert

# NOTE: The repository name in the section header is the directory
# name off of /path/to/svn-repos/
# The path portion is the section of that repo. In this case, / means
# the entire friggin thing.
@devs_all = rw
* = r

@devs_padlock = rw
* = r

@devs_all = rw
* =

Once this was done, I restarted Apache and the changes were in effect.
[root@myserver /]# apachectl -k graceful

And now I have a Subversion install that allows for anonymous access to some of my repos while others still require authentication. And the repos that allow anonymous access still require authentication for checking in.

Sweet. I like being a nerd.

Resources to help you along the way
Using HTTPd (Apache) as your SVN Server
Authorization Options
Per Directory Authorization
Path-Based Authorization

Essential tools for any PHP developer

The following list was written by Chris Neale, of fame, and reproduced with permission from the PHP Developers Network Forums

I’m sort of writing a new article listing all the things I use, or should use, to write awesome websites. If you fancy adding to the list then please do, it’d help.

The Obvious
PHP – I think we all know what this is.
MySQL – And this.
Apache – My personal choice of web server mainly because I understand htaccess.

Swiftmailer – The best PHP mail sending library available bar none.
ADODB Lite – The best database abstraction layer around.
Template Lite – The best template engine.
FPDF – Awesome PDF library.
SHA256 – Hashing replacement for MD5/SHA1.
HTMLPurifier – Stop XSS attacks before they happen.
SimpleTest – Unit Testing library that’ll improve your code no end.
JQuery – Javascript AJAX/effects/make stuff easier type of thing.
JPGraph – Delightful library for charts and graphs in PHP.
ExCanvas – Get < canvas > working seamlessly in IE.

Firefox – Best browser around.
Internet Explorer – Needed for testing because there’s still people who suffer it.
Opera – Again, needed for testing.
Safari – And again.

Extensions and Plugins
Web Developer – Absolutely critical for finding out information about the clientside things.
Firebug – Brilliant javascript console that makes AJAX so much less of a headache to debug.
YSlow – Site speed profiling plugin (needs Firebug).
NoScript – The easy way to test a site with JS and more switched off.
SearchStatus – Site search profiler, find out keyword information, page rank, Alexa rank etc.
XDebug – An awesome PHP debugger/profiler.

I’m not really interested in what editor/IDE you use, that’s a very personal choice. I’m interested in things that are absolutely top of their class couldn’t live without them essentials.

Any new developer would do well to glean something from this information.