talideon.com

There’s a fine line between genius and insanity... that’s where I live, baby!

Entries for November 2007

November 5, 2007 at 2:38PM I am now the proud owner of

keithgaughan.ie! Now to figure out what to do with it...

November 9, 2007 at 10:22AM URL path parsing

Over the years I’ve built up a fairly substantial library of code I call AFK, which includes a tiny framework (we’re talking in the region of 20-30 lines here) that’s built on top of the libraries. I wrote it mostly because I wanted to try out stuff that no other PHP framework appeared to do or do well, and partly out of inevitable developer vanity. It’s served me well over the years and has morphed an awful lot since I started it.

One of the things it includes is a class called AFK_Routes, which, as you might expect, does URL routing. The route format is more-or-less the same as Joe Gregorio’s URI templates, so you’d specify a path like this:

/weblog/{year}/{month}/{entry}

Simple enough (and that’s relative to the root of the application, BTW). When specifying a template, you can also give a list of arbitrary data to be combined with the values extracted from the template variables, and a list of patterns that the various variables must adhere to. For example, if I was giving the routing specification for a weblog, the code might be:

function routes() {
    $patterns = array('year' => '\d{4}', 'month => '[1-9]|1[012]');
    $r = new AFK_Routes();
    $r->route('/', array('_view' => 'frontpage'));
    $r->route('/{year}/, array('_view' => 'year'), $patterns);
    $r->route('/{year}/{month}/', array('_view' => 'month'), $patterns);
    $r->route('/{year}/{month}/{entry}', array('_view' => 'entry'), $patterns);
    return $r;
}

This has problems. Firstly, it means there’s no effective way to cache compiled templates until they’re updated again. Secondly, the PHP code is mostly noise and obscures the routing information. Thirdly, it doesn’t play well with version control systems.

My solution to these is to move the routing information out to a configuration file. No XML crap mind you, just a simple plaintext list of templates. While I was thinking about this, it struck me that I could improved the actual templates themselves by allowing the patterns to be inlined.

In this new world order, the template variable syntax would be extended by giving the option of adding the pattern after the variable name, with the two separated with =:

/
_view = frontpage

/{year=\d{4}}/
_view = year

/{year=\d{4}}/{month=[1-9]|1[012]}/
_view = month

/{year=\d{4}}/{month=[1-9]|1[012]}/{entry}

[Lines starting with ‘/’, ‘#’, and ‘@’ are special, marking the start of a template specification, a comment, and a metadata specification respectively.]

Here’s the code for compiling a template to a regular expression:

function compile($template) {
    preg_match_all(
        '/{([_a-z][_a-z0-9]*)(?:=((?:[^{}]+(?:{\d*,?\d*})?)+))?}/i',
        $template, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);

    $start = 0;
    $pattern = '`^';
    foreach ($matches as $m) {
        $patt_len = strlen($m[0][0])
        $pos = $m[0][1];
        $name = $m[1][0];
        $pattern .=
            preg_quote(substr($template, $start, $pos - $start), '`') .
            "(?P<$name>";
        $start = $pos + $patt_len;
        if (isset($m[2])) {
            $pattern .= $m[2][0];
        } elseif ($start < strlen($template)) {
            // If there's no pattern specified, it delimits this pattern by
            // the next character following it. This is usually what you want
            // in all but 1% of cases.
            $delim = substr($template, $start, 1);
            if ($delim == '{') {
                throw new AFK_RouteParsingException(
                    'If you put two placeholders next to one another, ' .
                    'the first of the two must have a pattern.');
            }
            $pattern .= '[^' . preg_quote($delim, '`') . ']*';
        } else {
            $pattern .= '.*';
        }
        $pattern .= ')';
    }
    $pattern .= preg_quote(substr($template, $start), '`') . '$`';

    return $pattern;
}

function parse($pattern, $path) {
    return preg_match($pattern, $path, $matches) != 0 ? $matches : false;
}

Mind, I hacked this together during Prison Break last night, so there’s probably plenty of opportunities to improve it.

And here’s a demonstration it in use:

$t  = '/adfafsf{foo}fds/{bar=fds|af?ds}/{baz}/';
$re = compile($t)
print_r(parse($re, '/adfafsf---fds/ads/4444/'));

Which gives us:

Array (
    [foo] => ---
    [bar] => ads
    [baz] => 4444
)

This system give you most of the power of regular expressions, with the simplicity of Rails-style route specifications.

November 12, 2007 at 9:58AM Random Updates

I decided to resurrect the Irish Weblog Ping Proxy (and BlogPing) on some shared hosting I have with my employers, and I finally fixed the stupid contact form by removing the broken spam protection. Grr!

I might monetise the ping proxy, not garishly mind you, but I’ll give it a while first to see if it gets any traffic. I think the days of its like are well gone, mind you.

Compiz is just way too much fun. I end up spending inordinate amounts of time flicking between windows and dragging them around just for the eye candy. It’s sweet!

November 16, 2007 at 7:29PM A big pat on the back to Damien

...for his shiny new Netvisionary award. If anybody deserves one, it’s him.

Now, I’m heading off to a gig. Night all!

November 17, 2007 at 12:26PM 2moro2our Waterford

My sister Niamh, Ian, and I went to the 2fm 2moro 2our show in Electric Avenue in Waterford yesterday. No photos, I’m afraid; Niamh had meant to bring a camera, but when we got there, she realised she’d left it behind. Ah, well.

First up were the local band who were playing, The Siam Collective, were weren’t bad, but weren’t quite my cup of tea. The sound was rather muddy too, which didn’t help. I discovered that Niamh was friends with, and went to college with, John Leech, one of the guys in the band.

Next up were Ham Sandwich, who had a great set, and we’d the craic with Podge afterwards. Sound man.

After that were Concerto for Constantine. Sigh. I can’t believe I subjected my eardrums to that shite. Think Muse with a better drummer trying to play Tool’s backcatalogue. Yup, that bad. The world doesn’t need another Muse. The crowd they pulled consisted almost solely of groupies there to fawn over Mark Greaney.

Because of how bad Concerto for Constantine were, we didn’t bother hanging around for David Geraghty, which may, in hindsight, have been a bad idea.

Tonight, Ian and myself are heading to see Director in The Forum, which ought to be a good gig.

November 19, 2007 at 11:21AM Note to self on PHP autoloaders

It appears that if you’re in an autoloader, you can’t depend on the autoloader to work, that is, autoloaders don’t work within the context of an autoloader executing.

This is a little frustrating at times but makes sense as you could end up with accidental infinite recursion if you try to load a class--say an exception class--directly or indirectly. If the load fails, and your autoloader tries to load the very same class, it’ll fail and PHP might call the autoloader again. So PHP wisely makes them non-reentrant. Reentrancy is something you normally want, but in this case, due to the quasimagical nature of autoloaders, reentrancy would make problems with them hard to debug.

The solution? If your autoloaders need anything, make sure they’re explicitly loaded beforehand.

[For anybody who’s wondering, I ran into this when adding diagnostic exceptions to an autoloader and was depending on the autoloader to load said exceptions.]

November 20, 2007 at 12:30PM New books!

I ordered ‘Release It!’ and ‘Programming Erlang’ from Amazon on Thursday and they arrive today. Now, I’m quite aware that Amazon has a warehouse in Cork, but I’m still surprised at how quickly the books arrived.

I’m finishing up reading ‘Beautiful Code’. Overall, it’s a great book, but the individual chapters are something of a mixed bag qualitywise.

The worst chapters, in my opinion, are chapters 20 (”A Highly Reliable Enterprise System for NASA’s Mars Rover Mission”) and 27 (”Integrating Business Partners the RESTful Way”). The former was weighed down with buzzwords and enterprisey crap and the system it described neither impressed me nor evoked any sense of beauty within me. The latter was just plain disappointing and the author seemed to misunderstand what RESTful use of HTTP is really about, though it was a weakish chapter as a whole, it’s real problem was that it was mistitled. Had it been called “Integrating Business Partners with POX over HTTP” or something similar, I don’t think I’d’ve minded as much.

On the plus side, you’ve chapters like “Top Down Operator Precedence” (Chapter 7), “A Regular Expression Matcher” (Chapter 1), and “Beautiful Concurrency” (Chapter 24), which were all quite stunning. In the case of that last chapter, though I’m one of these people who thinks that shared nothing is usually a better approach to distributed computing, I still see the value and potential usefulness of software transactional memory, and, as a bonus, it demonstrated the value of lazy evaluation and a well-designed type system, especially when combined with type inference.

I haven’t read from chapter 29 (”Treating Code as an Essay”) onwards yet, but I expect to get through them tonight.

November 20, 2007 at 4:14PM Getting “Fatal error: Class ‘Net_DNS_RR’ not found” with Net_DNS 1.0.0?

Here’s what you do. Open up the file containing Net_DNS_RR, which on my Ubuntu system at work is at /usr/share/php/Net/DNS/RR.php but this will vary from OS-to-OS and distro-to-distro, and move the require_once directives in the fold block marked “Include files” after the fold block marked “Net_DNS_RR object definition”.

The error is occurring because the classes in the included files are attempting to extend a class which has yet to be defined, so PHP dies horribly.

The lesson here for everybody is that you should define your base classes before you subclass them. Bad Net_DNS developers!

Update: Grr! Niall tells me that this bug has been around for about four months and still nobody submitted a bug report. FFS! Does nobody have the common sense to take five minutes to submit a blasted bug report?! Gah! I’ve submitted one, which’ll hopefully be more successful than the last one I submitted to the PHP devs...

Update: It’s November 30th, and still no progress on that bug. I’ve tried giving the devs a poke because the fix is quite simple and I did provide a patch after all...

14:35: Just got some feedback on the bug. It’s been marked as closed. While I’m not entirely happy with the resolution, I think I’ll let this stand. :-/

November 22, 2007 at 4:03PM Pop culture can bugger off

This kind of crap [via] is what will eventually turn me into a bitter misanthrope. Sure, popular culture’ll eat itself, but it’ll then shit itself out, and the cycle will begin again.

Why should we care about these people? That’s what I don’t get. What have they ever really done of worth? Not enough people are willing to admit it, but “celebrity” gossip is just a modern freak show that lets us gawp without feeling bad about ourselves. It’s a cruel and voyeuristic form of entertainment that devalues us all because when somebody is a famous for being famous and nothing more, their “worth” comes from the degree to which they manage to screw up their lives and the lives of those around them, not from actually achieving something or pushing themselves to be better than they are. They’re no longer human in the eyes of the masses that buy this junk, just another soap opera character to follow.

Please, let’s just let it die. Is it really so much to ask that people be celebrated on their merits rather than how entertaining their self-destruction is?

November 30, 2007 at 11:41AM Firefox, Opera, and possibly others treat 301 and 302 redirects incorrectly.

In HTTP 1.1 (and HTTP 1.0, it seems), 301 (Permanent Redirect) and 302 (Temporary Redirect) redirects specify that the page you’re requesting has moved either permanently or temporarily. If you’re POSTing and you get such a redirect, you’re meant to send the POST request to the page given in the provided Location header instead.

However, both Firefox and Opera (and possibly other browsers) incorrectly treat the redirect the same way as a 303 (See Other) redirect. A 303 redirect informs the user agent that the request has been processed successfully, and the result is to be found at the URL given in the Location header.

Now, there are fairly good reasons for the broken behaviour in response to the 302 redirect; older code used 302 redirects as 303 redirects are used today. However, the behaviour with 301 redirects is completely broken.

I’ve submitted bug reports for Firefox and Opera, though Opera don’t provide URLs for them. The Opera bug report code is 300955.

I’ve put a demonstration of the bug online. The destination page should state that the request method for 301 and 302 redirects is POST in a conformant user agent. A non-conformant one will state that it’s GET.

Update: Konqueror (and by implication, Safari, I’d guess) exhibits the very same bug. Anybody want to try it in IE?

Update: Thanks to Phil Ringnalda for getting back to me on the bug. I’d missed an older report on the same topic, so it turned out mine was a duplicate. It’s something of a pity that this’ll never be fixed, at least for permanent redirects, but I guess that’s one form of brokenness we’re just going to have to put up with.