Daniel Rench

Web application development : Servers : Networks : E-Mail : DNS : Databases : Programming for hire

previous : contact : linkedin : code : links : pictures : facebook : twitter : next

Excitement Has A New Name: Tmetic::Feed::Manager

For a while I've been using the RSS reader built into the Thunderbird mail client. I thought it was kind of cool how it made blog posts look like e-mail messages. But why settle for kind of like e-mail when you can have the real thing?

So I wrote a Perl module: Tmetic::Feed::Manager. Just download it, untar it, then do the usual perl Makefile.PL && make && make test && make install. You may need to install some prerequisite modules like DBD::SQLite, Text::Template, and XML::RSS::Parser; the build process will let you know what you're missing. Except sendmail. If you don't have a working sendmail in your $PATH (whether it's actually qmail or postfix or the real thing) you will run into trouble.

This is an initial release and has some limitations, the biggest being it can only deal with RSS 2.0 feeds; no RSS 0.9x or Atom yet. Enjoy if possible and applicable, and send your thoughts (all of them) to me.

Because nobody has ever put the phrase "print to STDERR in PHP" on a web page

I needed to know how to do this, and this particular phrase (quoted) returns zero documents on well-known search engines. See, PHP does define STDERR (and STDOUT and STDIN) for use in print() statements, but (this is funny) not when running under a web server. So in order to print debugging information to your server's error log, you have to open it yourself and use fwrite():

	$STDERR = fopen('php://stderr', 'w+');
	fwrite($STDERR, "some debug info\n");

Printing to standard error is the #1 most common debug aid in the universe of all time (almost 6000 years). Yet PHP goes out of its way to take it away from you. It may be there for PHP scripts not run under a web server, but that's almost the same as saying it's not there at all.

It also sounds like maybe at one time STDERR, etc. worked as programmers would expect but the last word on that was "Not PHP problem -> bogus."

Dec 11, 2006 update: Thanks to reader Andy Bakun I now know about PHP's error_log() function. When called with one argument (a message string), it sends the string to the web server's error log (when running under a web server), or to STDERR (when running from the command line). So I think it's safe to say error_log() is PHP's do-what-I-mean equivalent of writing to STDERR in any other language. And now it's documented somewhere.

Excitement Has a New Name: Excessively Strong Typing in Perl

I haven't used this in "serious" code but that's only because I'm not a freak about strong typing. Don't you worry, it works fine.

package Typed;

sub TIESCALAR {
    my $class = shift;
    my $test_function = shift;
    bless [ undef, $test_function ], $class;
}

sub FETCH {
    my $self = shift;
    $self->[0];
}

sub STORE {
    my $self = shift;
    my $v = shift;
    if ($self->[1]->($v)) {
        $self->[0] = $v;
    } else {
        die "'$v' is an illegal value for " . ref($self) . "\n";
    }
}

package Typed::Integer;

our @ISA = 'Typed';

sub TIESCALAR {
    my $class = shift;
    Typed::TIESCALAR($class, sub { my $n = shift; $n =~ /^[\+-]?\d+$/ });
}

package Typed::Number::Natural;

our @ISA = 'Typed'; # could say 'Typed::Integer' but it makes no difference here

sub TIESCALAR {
    my $class = shift;
    Typed::TIESCALAR(
            $class,
            sub {
                my $n = shift;
                ($n !~ /\D/) && ($n > 0);
            }
        );
}

package Typed::VarChar;

our @ISA = 'Typed';

sub TIESCALAR {
    my $class = shift;
    tie my $n, 'Typed::Number::Natural';
    $n = shift;
    my $r = Typed::TIESCALAR(
            $class,
            sub {
                my $s = shift;
                defined($s) && (length($s) <= $n);
            }
        );
}

package main; # "where the action is"

tie my $x, 'Typed::Integer';
$x = 100; # OK
$x = -12; # OK
$x = 1.1; # dies, uh I mean "throws an exception"
$x = 'stuff'; # dies

tie my $z, 'Typed::VarChar', 5;
$z = 'chars'; # OK
$z = ''; # OK
$z = 'Fairly long string'; # dies

Since the Knockoff Project seems dead

Starship album cover

[ref: The Knockoff Project]

Agitating for green shopping bags

a picture of angry Macy's protesters The shirts are cute and I suppose it's sad to see a "beloved institution" go, but what sort of person gets emotional over corporate name changes I ask rhetorically? I thought it was lame when International Harvester changed its name and clever logo but I got over it. It's not like when Lounge Ax closed or anything. Actually even that event was probably less culturally significant than the Kots and Derogatises made it out to be. By the time Lounge Ax closed in 2000, the Empty Bottle had held the Cool Underground Chicago Rock Saloon torch at least 4 years and still does for all I know.

arguments.callee: A dren.ch Endorsement

I mostly agree with Mr. JSON's ECMAScript recommendations but not this:

The following features should be depreciated.

[...]

arguments.callee.

It might have a goofy name but arguments.callee is way too useful (inside a Javascript function, this is a reference to the function itself). I don't mean anonymous recursive functions, though that's still kind of cool. Say you wanted a "sequence" function. With arguments.callee:

function sequence () {
	var me = arguments.callee;
	if (! me.n) me.n = 0;
	return me.n++;
}

Without:

var sequence = (function () {
		var n = 0;
		return function () { return n++ };
	})();

You can argue that the "without" version is better but I'm not going to agree with you.

9/12/2006 update: This works and is probably clearer than either of the above:

var sequence = function () { return sequence.n++ };
sequence.n = 0;

It manages to avoid arguments.callee and function-within-a-function closure. It also fixes the (for me) biggest problem with the arguments.callee version: the test for undefined n on every call. But there are a couple minor downsides: the function needs to know its name, and it's not self-contained. Maybe you don't care.

8/15/2007 update: A Canadian named Peter discusses similar problems though he's into using the term "pattern".

Transmutable (?) Objects in Perl and Ruby

I have no idea if "transmutable" is the right word to describe this concept but I'm using it anyway.

In Perl, I sometimes find it useful to "transmute" objects. For example:

sub Grape::new {
	my $class = shift;
	bless {}, $class;
}

sub Grape::dehydrate {
	my $self = shift;
	bless $self, 'Raisin';
}

sub Raisin::new {
	my $class = shift;
	bless {}, $class;
}

my $x = Grape->new();
print ref($x), "\n"; # prints "Grape"
$x->dehydrate();     # it's not a Grape anymore
print ref($x), "\n"; # prints "Raisin"
$x->dehydrate();     # Raisin doesn't have a dehydrate() method, so it dies

To do this in Ruby, I first tried something like this:

class Grape
	def dehydrate
		self = Raisin.new
	end
end

But Ruby complains "Can't change the value of self". I ended up trying something with Ruby's version of AUTOLOAD, method_missing:

class Grape
	def initialize
		@me = Hidden::Grape.new
	end
	def method_missing(method, *args)
		r = @me.method(method).call(*args)
		@me = r if /^Hidden::/.match(r.class.to_s)
		return r
	end
	def class
		@me.class.to_s.sub(/^Hidden::/, '')
	end
	def methods
		@me.methods
	end
end

module Hidden
	class Grape
		def dehydrate
			Raisin.new
		end
	end
	class Raisin
	end
end

x = Grape.new
puts(x.class) # prints "Grape"
x.dehydrate
puts(x.class) # prints "Raisin"
x.dehydrate   # NameError: undefined method `dehydrate' for class `Hidden::Raisin'

Various things seem wrong about it (especially overriding class() and methods()), but it pretty much does what I want.

11/15/2006 update: I no longer think the above seems "wrong". If anything it's probably considered insufficiently weird in Ruby circles.

The Cookie Hack: using mod_perl to make IE7 think you're not using Basic Auth (even though you are)

You may have heard that the forthcoming MSIE 7 web browser made some "enhancements" for Basic Authentication (warning or optionally disallowing it unless used over SSL). You could buy a certificate or try converting to digest auth or you could implement a cookie hack. It goes something like this (assuming you're running Apache 1.3 with mod_perl):

  • Create an ErrorDocument 401 with an external redirect to an HTML page with a login form. Normally it's a bad idea to put external redirects on your 401 documents (because it turns them into 302s [or is it 301s?]). Anyway, it's still a bad idea but that's OK because this whole thing is a bad idea.
  • Create a "login form" page that looks something like this:

    <script>
    window.onload = function () {
      var F = document.forms['login'];
      F.onsubmit = function () {
        document.cookie =
         "auth=" + btoa(F['username'].value + ':' + F['password'].value);
        location.href = 'http://example.net/URL/THAT/REQUIRES/LOGIN';
        return false; // probably not necessary
       };
     };
    </script>
    
    <form name="login">
     <input type="text" name="username">
     <input type="password" name="password">
     <input type="submit" value="log in">
    </form>
    

    The above uses the little-known btoa() function. It encodes to base64. Too bad MSIE doesn't support it. You'll need to find or write your own base64 encoder. But then you've just screwed all the browsers that aren't running javascript. So then you write yourself some server-side CGI/PHP/ASP/JSP code that sets the cookie instead. Whatever you do, the result is a cookie called "auth" with a value that should look just like the right side of a typical "Authorization: Basic" HTTP header.

  • Here's the fun hack part. Write a mod_perl HeaderParserHandler that does something like this:

    use Apache::Constants 'DECLINED';
    
    sub handler {
    	my $r = shift;
    	my $h = $r->headers_in();
    	return DECLINED if $h->{Authorization};
    	if (my $c = $h->{Cookie}) {
    		for (split /\s*,\s*/, $c) {
    			if (m{\bauth=([a-zA-Z\d\+/]+)}) {
    				$h->{Authorization} = "Basic $1";
    				last;
    			}
    		}
    	}
    	DECLINED;
    }
    

    Now when Apache sees one of our "auth" cookies coming in, we make it think that you actually sent an "Authorization" header. If it's correct, it lets you in. If it's wrong, you get a 401 and get redirected back to your login page.

It's just as "secure" as always (that is, not at all) but it does have some advantages over basic auth:

  1. Delete the cookie, and you're logged out. No need for a browser shutdown as in basic
  2. Add an expiration date to the cookie, and your login "session" can survive a browser shutdown
  3. Set the domain of the cookie to .example.com and suddenly you don't have to maintain separate logins for http://www.example.com/ and http://example.com/ perhaps even https://www.example.com/

If you really want to run with this, you could work around the insecurity by encrypting the the username and password on the client side and expanding the mod_perl handler to decrypt before setting up the fake auth header. You'll have to figure out how to pass the key securely.

August 2006 Chicago-area Community Calendar

The Minutemen and their back catalog

Seeing We Jam Econo reminds me that the Minutemen need a reissue program. Here's how it should go:

Front cover of the My First Bells cassette
  1. A double CD reissue of the previously cassette-only My First Bells

    Though the original cassette sounds terrible, this compilation of their releases from 1980 to 1983 (mostly) in order, works as an album much better than any of the Post-Mersh CDs that came later. Side (or in this case, disc) 2 is especially good, starting with "Bob Dylan Wrote Propaganda Songs" and ending with "Little Man With a Gun in His Hand". Both songs' impact is blunted coming halfway through their respective CD compilations.

    If you have the three Post-Mersh CDs and download some stray compilation tracks, you can nearly recreate My First Bells in your own home (you'll still be missing "Clocks" from the Chunks compilation). Try it and you too will consider this to be the finest Minutemen collection, with the possible exception of...

  2. A (double, if necessary) CD reissue of the complete, original Double Nickels on the Dime

    All of the previous CD editions of this album are missing songs. Again, let the corndogs help you reproduce the experience (though you will still be missing most of the side ending and beginning "car jams").

  3. 1985

    Put both of their "commercial" records from 1985 together: Project: Mersh and 3-Way Tie (For Last), in that order on a single CD.

  4. A double "deluxe" CD reissue of Ballot Result

    This would include all the tracks from the original double LP, the cassette bonus tracks, and then pile on all the other odds & ends (possibly expanding to 3 discs): The Politics of Time LP, the Tour-Spiel EP, the Georgeless EP, and more Reactionaries material.

All four will come with full-color reproductions of all the original jacket art, obligatory Byron Coley liner notes, and won't be on SST.

older things