19 December 2008

Belize: Day Off, Return

(This is part 6 of a 6-part description of a trip I took to Belize with friends just after Thanksgiving 2008. I put my pictures a flickr.)

We didn't plan anything for Thursday, so we slept in. After a leisurely breakfast, we headed north into the shopping areas of San Pedro. We visited several shops looking for souvenirs and gifts. I found that most of the offerings seemed to be overpriced tourist junk, but I did splurge on a couple of Belikin Beer T-shirts. This shopping trip was also a pub crawl: we hit four or five bars, having lunch in one of them. There are lots of dogs in San Pedro. One would adopt us for a while as we walked along, and another would pick us up as we left a shop or bar. We finished out our last full day of the trip with a delicious dinner at the restaurant of a nearby coastal resort.

We took it easy again Friday morning. I partook of some wireless Internet by the Xanadu pool (my friends were impressed that I'd held out for nearly a week), L and KL swam a bit, and H and K did a little more shopping. Then we packed up and took a cab back to the San Pedro airport. Another Tropic Air flight with more breathtaking views of the Caribbean took us directly to the Belize City International Airport. Other than K having a bit of trouble with immigration/customs in Houston, we had an uneventful trip home. The temperature change was pretty startling: from somewhere around 85F to 33F. Ouch. Back to reality. *shrug*

Caye Caulker

It was a fabulous trip. I'd do it again.

18 December 2008

Belize: Caye Caulker and Snorkling

(This is part 5 of a 6-part description of a trip I took to Belize with friends just after Thanksgiving 2008. I put my pictures a flickr.)

Wednesday morning started with another speedboat pickup from Searious Tours. They took us and several other tourists back to the Searious pier where we piled onto a catamaran. There were ten of us on the tour with two crewmembers. We headed out toward a popular snorkling spot just inside the barrier reef. I'd never been snorkling before, so I didn't know what to expect, but this turned out to be my favorite part of the whole trip. The water was only twenty or thirty feet deep, and it was teeming with fish. We even saw a few stingrays and a couple of moray eels. The fish would swim almost right up to me: I guess they get lots of practice sharing the water with snorklers. We probably got to spend the better part of an hour in the water at this spot.

After another short run on the catamaran, we found ourselves at what the crew called "Shark Ray Alley." As the name suggests, it's an area frequented by predators. One of the crew (Daniel) jumped in and caught a nurse shark. Daniel said that the animals are used to him, and they just swim right up to him. The shark was about four feet long, and it just sat patiently in Daniel's arms while we touched it. Its skin was courser than I would have guessed. After we'd all checked out the shark, Daniel released it and grabbed a stingray, which had a much smoother skin. Anyway, the underwater petting zoo was pretty cool.

Back on the catamaran, we sailed south to the island of Caye Caulker, with plenty of Bob Marley, Belikin, and rum punch along the way. The crewmembers jokingly described Caye Caulker as a drinking village with a fishing problem. We had a delicious lunch of ceviche and fish burritos, followed by a little shopping.

The return trip was straight into the wind (and seemed to narrowly avoid some bad weather), so the crew had to rely on the two outboard motors. Back at Xanadu, we made sandwiches for dinner and again fell into bed pretty early, most of us nursing sunburns.

Caribbean waters

17 December 2008

Belize: Altun Ha

(This is part 4 of a 6-part description of a trip I took to Belize with friends just after Thanksgiving 2008. I put my pictures a flickr.)

We got up early Tuesday morning and were picked up from the Xanadu pier by a speedboat from Searious Tours. There were already several other tourists on board (along with the three crewmembers), and we picked up a few more at other resorts along the coast. Then we headed out over the open waters toward the mainland.

The fellow from Searious who drove the boat (a two-engine job, about 40 feet long) and served as our tour guide as we left San Pedro was named Willie. He was very knowledgeable about the local flora and fauna, and he was fun to listen to: his speech was sort of a toned-down version of the frequently-overblown Caribbean stereotype (I'm thinking Predator 2 here). On the way to the mainland, we got to see a couple of bottle-nosed dolphins break the surface pretty close to the boat.

Once we reached the coast, we went up the Belize River a bit. We saw an iguana lounging about in one of the trees. We stopped at a dock and transferred to a van which took us to Altun Ha. The ruins there are pretty spectacular--I'll let the photos speak for themselves. We stayed for an hour or so. We got to climb to the top of one of the structures, and that was a real kick. There were no guardrails or anything to prevent a careless tourist from falling over the side--one of the many differences with tourist attractions in the litigation-happy US.

Belize River


Temple of the Green Tomb

After Altun Ha we spent a couple of hours at the Maruba Spa. They apparently offer massages, mud treatments, and several other odd things. We enjoyed a nice lunch and some time by the pool. Then we rode back to the dock (with one of the tour guides acting as bartender in the back of the van: Belikin and rum punch) and took the boat back to Ambergris Caye (the ride back offered a pretty spectacular sunset). That evening we walked up the beach to the Blue Water grill for some fantastic seafood (I had some snapper), and then we headed back to Xanadu and fell into bed.

Maruba Resort pool

Caribbean sunset

16 December 2008

Belize: San Pedro

(This is part 3 of a 6-part description of a trip I took to Belize with friends just after Thanksgiving 2008. I put my pictures a flickr.)

We had pretty luxurious accommodations in San Pedro, which is on the island of Ambergris Caye. We were in a three-level dome-topped structure, and we had the top two levels. Our downstairs had a well-equipped kitchen, a dining area, a common area (TV and couches), and a bedroom (L and KL took that one). There were two more bedrooms upstairs: I took one, and H and K took the other. Each bedroom had its own bathroom. There was a wonderful wooden deck/balcony off of our downstairs, and it looked out over the water. It was really quite fancy.

view from Xanadu balcony

The beach wasn't quite what I expected, because I hadn't read about the barrier reef. Ocean waves strike the reef, rather than the coast, which is a big part of why the water here is so clear. But that means that we didn't see or hear waves, which is one of my favorite ocean things. So that was a very minor disappointment, but it was still very cool being by the water. The reef is not that far out, so we could see waves breaking out on the reef just below the horizon, and that was pretty awesome to watch. The beach itself is very clean white sand, and it was fun walking around.

Caribbean barrier reef

San Pedro coast

That first afternoon in San Pedro we didn't do much more than have a good meal and settle in to Xanadu. We turned in early, because we knew we had an early start the next morning: the Mayan ruins at Altun Ha.

15 December 2008

Belize: Pook's Hill

(This is part 2 of a 6-part description of a trip I took to Belize with friends just after Thanksgiving 2008. I put my pictures a flickr.)

David introduced us to his co-manager (and wife) Kat and the owner (Ray) and took our bags to our cabanas (I'd never seen a thatched roof up close before). We took it easy that afternoon, and it got dark around 6PM. After the amazing sunsets, we mostly hung out at the main cabana, which has hammocks, chairs, a well-stocked bar, and a few sugar-water dispensers that were very popular with the local hummingbirds. This gave us an opportunity to get acquainted with some of the other guests: at one point I got to have a fun visit with a self-described "petrol head" from Britain, and we talked about Steve McQueen movies. After a few drinks, dinner was served downstairs, and we were treated to a delicious buffet-style meal. After some after-dinner coffee and tea (and maybe a few more cocktails), we retired to our cabanas for the night. I found that I really enjoyed falling asleep to the sounds of the jungle.

Pook's Hill sunset

American oil palm

main cabana

The next morning (Saturday), my companions went on the Actun Tunichil Muknal (ATM) adventure tour. I picked up a charming sinus infection around the time we began this trip, so I stayed at Pook's. My friends said that it was a great experience, in which they hiked, explored some caverns, and visited Mayan ruins. The hike to the ATM cave requires four river crossings each way, and there are no bridges: you swim across. So, although they said it was lots of fun, my friends told me that I'd made a good decision to skip it. So I had a quiet morning at Pook's, and by afternoon I felt perked up enough to do part of one of the hiking trails. By the time I got back to the lodge, my friends had returned from the ATM trip, and we enjoyed another evening at the main cabana.

Americal oil palm

Sunday morning we finished out the hiking trail I'd started the previous afternoon. That route took us across a large meadow and along several well-kept jungle trails. That afternoon we had a real treat: we went inner-tubing down the Roaring River. It was surprisingly fun and relaxing. The water was cool but not cold, and it was amazingly clear. There was a great swimming hole in a bend of the river, and we had a high time hanging around there for about an hour. We saw some sleeping bats hanging from a tree, some fresh footprints (probably a tapir) on the riverbank, and we got a kick out of watching the smaller fish nibbling at the skin of our feet (that tickled a bit).

canopy entry

River Trail bush

looking across the Roaring River

standing in the Roaring River

Sunday evening's pre-dinner drinking was on the roof of the owner's house, which is up at the top of the hill and afforded a breathtaking view of the valley. We saw several egret flocks fly to their nighttime nesting areas, and we were up high enough to see the hills.

flight of egrets

Monday morning we spent a little time on one of the other hiking trails near Pook's, this one through the jungle above the owner's house. At one point we all heard something moving around to our left, but we never saw what it was. And then we took the monstrously-bumpy road back to Teakettle Village, the Western Highway back to Belize City and its municipal airport, and a Tropic Air prop to San Pedro on Ambergris Caye. That was a really cool flight out over the water. It offered a great view of the clear waters of the Carribean and the barrier reef. A short cab ride got us to our home for the next four days: Xanadu Resort.


14 December 2008

Belize: Arrival

(This is part 1 of a 6-part description of a trip I took to Belize with friends just after Thanksgiving 2008. I put my pictures a flickr.)

Two friends of mine (L and KL) and I flew to Houston on Thanksgiving where we were met by two other friends (K and H). We spent the night there and then got up the next morning and took a Continental jet to the Belize City International Airport. After going through immigration and customs, we stepped outside and were met by David, one of the managers at Pook's Hill Lodge. Pook's is a great place in the jungle of the Cayo District, far away from any population centers.

David packed us and our stuff into a van, and we headed westward on the Western Highway. After about an hour, we stopped at a restaurant called Amigos and had a delicious lunch of stewed chicken, rice and beans, and Belikin beer. Due to import restrictions, Belikin is about the only beer you can get in Belize--fortunately it's very good.

After lunch we went to the Belize Zoo, which features howler monkeys, spider monkeys, owls, tapirs (which were quite a bit bigger than I expected), otters, coatis, a puma (also larger than I expected), a pair of HUGE crocodiles, a couple of jaguars, and some really foul-smelling wild pigs called peccaries. I didn't get many good pictures, but I got a short movie of one of the jaguars (he came right up to the fence).


Another hour on the Western Highway brought us to Teakettle Village. We took a monstrously bumpy dirt road for about a half an hour, and then we arrived at Pook's Hill Lodge, where we spent the next three days.

18 September 2008

Thursday at ZendCon

Today is the final day of ZendCon, and it's a half day. It started with sessions, rather than a keynote (the keynote is at the end). I was having trouble figuring out which session to attend, but then I looked at the presenter names, and that made it easy to pick "Scaling Mozilla's websites with PHP" with Laura Thomson. I've heard her speak at OSCON, and she always gives a good talk. She didn't disappoint today, as she told us about how she helped Mozilla get ready for the Firefox 3 "Download Day" (or, as she called it, D-Day). It was a fascinating case study of query/code optimizations, caching solutions, MySQL replication tricks, and other goodness. A couple of fun facts are that mozilla.com uses drupal, and D-Day saw saw 14Gb/s of downloads and 2Gb/s of web traffic.

Next Stefan Priebsch gave a good discussion and demonstration of Selenium. Several people have talked about Selenium at this conference, and it really looks like a great resource.

The closing keynote is by David J. Neff from the American Cancer Society. He told us about sharinghope.tv, a site with user-generated content from people affected by cancer. Pretty cool.

Here's a picture from the closing keynote. That's Cal Evans (ZendCon program chair) on the stage, and the (backs of the) heads of Laura Thomson and Paul Reinheimer. Sebastian Bergmann was also milling about (which would have put my three favorite speakers in the shot), but he wouldn't hold still long enough.

Cal on stage

17 September 2008

Wednesday at ZendCon

ZendCon started with a really interesting keynote today (I'm usually not big on keynotes). The first speaker was a Zend Framework developer named Wil Sinclair, and he talked about how PHP applications have evolved over time. He introduced the CEO and CTO of Varien, and then talked about their company's development of Magento. Magento looks really cool. It's an open-source e-commerce built on Zend Framework. It appears to be as full-featured as big commercial e-commerce sites like amazon.com. They apparently wrote the whole thing in a matter of months. Impressive. I'll definitely try it if I ever need to make an online store.

Then I checked out "Architecting for PHP5..." with Elizabeth Smith. She covered some of the features new to PHP5 and again encouraged us to use extensions whenever possible ("C is faster than PHP"). Looks like I need to read more about the SPL and the filter extension.

Stefan Esser gave a really good talk called "Lesser Known Security Problems in PHP Applications." Some of it was kind of scary. We even got to hear him announce a 0-day vulnerability with the ZipArchive extension (along with a more obscure problem with HTTP response splitting affecting users of older Netscape proxies).

After lunch was another keynote: "The State of AJAX" with Ben Galbraith. Not a lot of technical information, so not too interesting to me. It was mostly a survey of lots of shiny-looking, bleeding-edge stuff (which may or may not be around in six months). He speculated that HTML5 and (google) gears will be important to the future of AJAX. I was hoping he'd tell me which AJAX framework to use, and he did address this point. He said that it's sort of a toss-up between Dojo, Prototype/script.aculo.us, and jQuery, because they're all small, powerful, extensible (with community support) frameworks. So pick one. *sigh* Thanks.

In his "Phar Scape" talk, Marcus Boerger showed us some neat tricks to do with phar, a deployment tool modeled after Java's JAR.

I went to another talk by Sebastian Bergmann, this one called "phpUnderControl: A Quick Start to Continuous Integration." I'm pretty much the only PHP programmer where I work, so I don't really have to integrate my work with a team. But phpUnderControl looks cool enough that I'd like to try it. Besides, it makes nice pictures that could distract managers. (And Sebastian says that he likes doxygen more than phpDocumentor, so I'll give that a try, too.)

I finished out the day with an UnCon session called "Subversion Tips and Tricks" with Lorna Mitchell and Matthew Weier O'Phinney. It turned out to be mostly introductory in nature, but I still picked up a few things. It was very informal, and it was fun.


I've been playing with ScribeFire (a Firefox extension) today, and I'm finding it to be a pretty good HTML editor. It runs right in the browser (one of the configuration items lets you run it in its own tab, which is cool). It'll save drafts locally, which is good for offline writing. And if I put a URL in the copy-and-paste buffer, when I highlight some text in ScribeFire and click the URL button, the URL in the buffer automagically appears in the URL dialog box.

16 September 2008

Tuesday at ZendCon

Kind of a slow morning at ZendCon (to me, anyway). Started off with the keynote by Harold Goldberg, Zend Technologies CEO. Mostly business-speak, so not too exciting (I'm a nuts-and-bolts sort, I guess).

Then I went to "Of Haystacks and Needles" by Derrick Rethans. This looked interesting to me because of my php|arch article. One of the people who wrote about my article seemed to advocate storing records as documents, like maybe XML documents. I think that's a pretty interesting idea, because storing it like that sidesteps the whole issue of different records having different sets of fields. And I could just store the XML string in a text column or something. But I didn't know how I'd do searches--if I want to find a record submitted by someone whose last_name is Smith, it seems like I'd have to run a DB query to get the XML string for every record, pull it out of the DB and into application memory, parse each XML string, and look for any that match. So I was hoping that this would give me some ideas of how to do this (although lately I've been thinking about stored procedures). Anyway, the talk gave me several things to look at more closely later:

Lunch was a catered affair again, but no celebrities this time (not that I realized, anyway).

Things picked up after lunch, starting with "PECL Picks..." with Elizabeth Smith. This was a whirlwind survey of some PECL projects that Elizabeth deems "cool." Here are some of the ones that look interesting to me:

Next was "Knight Rider Methodology to Software Develoment" in which Eli White covered a lot of development tools and techniques. The theme was how Michael Knight got lots done on (the 80s TV show) "Knight Rider" by using the tools at his disposal (well, tool: the car, KITT). The talk was punctuated by clips from the show (one of my favorites as a kid, and it's far cheesier than I remembered--wow). Here are some fun quotes from Eli's talk:

  • "hardware is cheaper than people"

  • "use someone else's time as your own" (use libraries rather than re-inventing the wheel)

  • "nothing is right the first time: even 'hello, world!' needs internationalization" (debuggers)

After his talk, I'm looking forward to trying out some subversion GUIs like subcommander and rapidsvn.

Paul Reinheimer gave a great talk about how Web 2.0 breaks the browser's Back button, and he talked about a really interesting solution using the yahoo user interface (YUI). He also talked about how to deal with AJAX responses coming back in an order different from that in which they were sent. I think that'll take a few reads for it to sink in for me, but I'm looking forward to trying it out. Paul does PHP training, and he's a really good speaker.

Finally, Eddo Rotman gave a good presentation about PHP errors and exceptions. His talk has inspired me to write a cron job which knows a list of PHP application error logs and emails me the entries made in the last 24 hours: maybe it'll append a marker to each log file and email the entries written since the previous marker.

15 September 2008

Monday at ZendCon

Today at ZendCon I attended two tutorials, and I enjoyed them both. In both cases, there was a lot of review, but I also learned new things in both. The morning session was "PHP Developer Best Practices" with Matthew Weier O'Phinney and Mike Naberenzy. They covered a pretty broad set of topics:

  • They spent quite a bit of time on source control. They talked mostly about subversion, but they also discussed some git's advantages, particuarly for offline development (like on a laptop on a plane). Some of the other things that were interesting to me were the ability to link one SVN repository to another with the svn:internals feature, using post-commit hooks to send emails (to other developers) or to rebuild documentation (e.g., via phpdoc), and using branches for maintaining older product lines (the example that occurred to me is that the Apache developers might have a branch for the 1.3.x line).

  • They talked a lot about coding standards, and then advocated the PEAR standard. I think that's the default standard which is enforced by PHP_CodeSniffer, which is one of the coding tools they discussed (which I started using a few weeks ago).

  • They spent some time on testing, and they pointed out that when coupled with xdebug, PHPUnit can do coverage analysis. I didn't know that, and I think that's pretty cool. I've never been able to get xdebug to work for me, but that's a good reason to try again. They also made PHPUndercontrol look interesting enough to play with.

  • They talked about phpDocumentor, which is something I've been using and enjoying lately. They also touched on DocBook, which evidently is just fairly straightforward XML. I'll have to give that a try.

  • They concluded with a few remarks about deployment issues. I'd hoped they'd talk about phing or phar, and they might have, but they sort of ran out of time.

Lunch was catered box lunches, served in a large room with lots of big tables. So I had lunch with strangers, but one of them turned out to be Jay Pipes. I'd heard him speak at OSCON previously, and he had some interesting insights about Sun's MySQL acquisition (he said that Sun had so far mostly left MySQL alone). Jay was wearing a cool T-shirt with the Decepticon logo. And Paul Reinheimer was sitting behind me. I don't know his face, but I recognized his voice. Sounded like he was keeping his tablemates well entertained.

The afternoon session was "Quality Assurance in PHP Projects" with Sebastian Bergmann. I've been fiddling with PHPUnit for a little while, and the talk gave me several things I want to research a bit more when I have time:

  • the --testdox option

  • the @group phpdoc tag

  • xUnit Test Patterns, a language-agnostic book about software testing

  • the DbUnit feature

  • using sqlite for testing DB stuff

  • using the dataProvider feature for throwing a large stack of specific test data at the code

Sebastian also talked a lot about mocks and stubs and such, but that's still a bit over my head. But we got to see the --ansi feature of the shiny new v3.3.0 (which he just released this morning).

The eee pc had good moments and bad. This convention center did a pretty poor job of providing power outlets (people were sitting up front so that they could plug into surge suppressors for the sound systems, and others even pried some metal plates off the floor to get at electrical outlets), so I was on battery all morning (I scored an outlet in the afternoon). The eee pc battery held, but perhaps only because I dimmed the screen and turned off the wireless. But I'm still happy with it--it's light enough that I don't feel tired or sore at the end of the day. And although I make more mistakes than usual on the little keyboard, it's plenty good enough for note-taking.

Sunday at/before ZendCon

I'm at ZendCon this week. I flew in to San Jose airport yesterday and got the hotel shuttle to the hotel (which is in Santa Clara). I got in pretty early (around 10AM local time), but my room was already ready, so I got to go straight in.

A bit later I took the hotel shuttle to the Santa Clara Convention Center, which is where the conference is being held. Conference check-in only took a few minutes (I gave them my name, and they gave me my conference packet), so I had the rest of the afternoon play.

I had the hotel shuttle take me to the local CalTrain station, and I took that into San Francisco. I was wanting to go to Pier 39 (a touristy shopping area with Bay cruises and an aquarium), but I had a terrible time finding the right bus. The nice woman who answered the Pier 39 phone number told me to take the 9x bus. As far as I can tell, that particular bus runs approximately once every two weeks. I only ever saw one 9x bus, and it was going the wrong way. I almost gave up a couple of times and just took the train back early.

I eventually got to Pier 39 (I caught the 10 bus, which runs fairly regularly, and which got me to within a block of the pier), but I didn't have much time there (I needed to get back to the train station by 7PM for the return to Santa Clara). But the pier offers a nice view of the Bay, and I took several pictures. I could see Alcatraz Island, and there was a neat view of the Golden Gate Bridge in the distance. Some of the other shorelines were wrapped in a neat fog, and seeing the sea lions was cool.

I got back to the hotel and had some dinner in the hotel restaurant. By then I was pretty tired (I didn't sleep much the night before, and the time change added an extra two hours to the day), so I turned in a bit early.



08 September 2008

Robocop vs. Terminator

Topless Robot had a post a couple of days ago about a fan mashup on youtube called Robocop vs. Terminator. Mindless fun.

07 September 2008

eee pc

I got an Asus eee pc (model 900) the other day (I ordered it through buy.com). I'm going to a conference next week (zendcon), and I didn't want to lug around my laptop (it gets pretty heavy after a few hours). I didn't need much--something with a Web browser, an ssh client, something to pull images off of my camera (a Kodak Easyshare v1003), and a text editor for taking notes. The eee pc fits that nicely, and it only weighs about 2.5 pounds.

It's got an 8" screen which I'm finding to be perfectly readable. The keyboard is pretty small, but I'm getting used to it (I'm posting this from the eee pc).

It has an SD/MMC card reader, 3 USB 2.0 ports, and built-in wireless (802.11 g/b). It has 1GB of RAM and a 20GB solid-state hard drive (the thing boots to the login prompt in about 30 seconds). It even has an integrated 1.3Mpixel Web cam.

I'm finding the eeeuser wiki to be very helpful (especially a post about getting gwenview to import photos from my camera).

One little wrinkle I experienced was that the wireless adapter was inadvertently disabled, and it took me a little while to figure out what had happened. The eee pc typically recovers well from going to standby mode, but once when I tried to resume, the screen looked like static and I couldn't get it to do anything. I had to hold down the power button and reboot. When it came back, it refused to join my wireless network. I finally figured out (with the help of the diagnostic tools) that the wireless adapter had been disabled (dunno if I accidentally did that, or if it was a fluke). Anyway, holding down the special function key ("Fn" in the lower left) and hitting F2 toggles the adapter, and I was back in business.

30 August 2008

feedback to php|arch article

I noticed a couple of blog posts written in response to my (somewhat) recent php|arch article:
Reading these was initially discouraging, as both authors are critical of the concept of my article. Although I don't necessarily agree with them, they both make good points in their posts, and I encourage you to read them both if you are interested in the topic. I particularly appreciate the point about table-level locking in MyISAM tables, and how that might affect performance in the frequently-updated value tables.

Although this is not a very useful rebuttal, about all I can say is that the EAV method has worked well for me. As with anything, your mileage may vary. I'm not running reddit or facebook, and the systems I've built on EAV don't have thousands of simultaneous users. So I really can't say how well it would perform in a large-scale deployment.

After I sort of got over being defensive about the whole thing, I'm just glad that people found the article interesting enough to talk about it.

23 August 2008

LAMP pconnect

I had a bad experience a few years ago using pconnect() in a PHP program running in/on/under Apache on Linux to talk to a MySQL database. My memory is somewhat vague, but we had to restart the MySQL service (and switch to non-persistent connections). Ever since then, I've had an irrational fear of pconnect() and have never used it.

Looks like I'm not the only one who doesn't trust pconnect().

16 August 2008

HTTPS in Apache in Ubuntu

If there's an easy way to make Apache in Ubuntu (v7.10, gutsy) do HTTPS, I can't find it. So I played around with it this morning and got it working.

First you need to generate an SSL certificate. I just went with self-signed certificates:

openssl genrsa -out apache.key 1024
openssl req -new -key apache.key -x509 -out apache.crt \
-days 365 -set_serial `date +%s`

I saved these two files as /etc/ssl/certs/apache.crt and

And then I saved the following as

NameVirtualHost *:443
<VirtualHost *:443>
DocumentRoot "/var/www"
ServerName www.example.com:443
ErrorLog /var/log/apache2/ssl_error.log
TransferLog /var/log/apache2/ssl_access.log
LogLevel warn
SSLEngine on
SSLCertificateFile /etc/ssl/certs/apache.crt
SSLCertificateKeyFile /etc/ssl/private/apache.key

Then after enabling the new site (a2ensite default-ssl) and restarting Apache (/etc/init.d/apache2 reload), I was able to connect to https://localhost/. FireFox3 complained bitterly about the self-signed certificate, but adding the exception straightened that out.

27 July 2008

barn swallows: alive and well

Today I saw the four fledgelings perched on a nearby railing. Their parents still bring them food.

When I got home last night, two of them were perched on a door frame near where the nest used to be.


24 July 2008

barn swallows: moving on

When I left for work this morning, the nest appeared to be empty--I didn't even see Stoopy lurking in it. I guess they were all off doing...well, whatever barn swallows do (eat insects and make poop, I suppose).

When I got home from work, I saw that the painters had taken down the nest so that they could paint the entryway. Lame, but at least they waited until the hatchlings had become fledgelings. If that was a deliberate decision, it was a nice one.

This evening as I left for a bike ride, the entire crew swooped past me single file through the entryway, as if to say "hello" (or perhaps "oh god it's a human fly away as fast as you can"--it's a subtle difference). And when I came back, one of the fledgelings was perched on the doorframe close to where the nest used to be.

So I guess they'll be OK. It was nice having them as neighbors for a while.

23 July 2008

fledgeling barn swallows

Maybe they hatched earlier than I thought, because a couple of them were flying a bit today.

When I came home from work, one of them was perched on a rail about 30 feet away from the nest.

Another one was fluttering around a bit near my doorway. He didn't seem comfortable going too far, but he was able to hover and then land on the nest. (That was pretty cool to see.)

A third one was staying in the nest. That one holds his (her?) wings a bit funny--up higher closer to his head. It almost makes him look like an old man with a stoop. I'm wondering if that one is healthy.

When one of the parents came to bring food, Stoopy was the only one I saw stick his head out of the nest. So I can't account for one of the hatchlings. I looked around a bit but didn't find the fourth anywhere nearby on the ground.

Update: I just stepped outside to have a look, and all four hatchlings are back in the nest. They're big enough now that it's pretty crowded.

22 July 2008

barn swallows; bigger and bolder

They're painting my building, so each day I fear that I'll come home to find that the painters have "evicted" the hatchlings (which they probably wouldn't survive). But they were still there again today.

It amazes me how much they've grown in just over a week. wikipedia says that barn swallows fledge (I believe that more-or-less means "leave the nest") after about 18-23 days, so they've got another week or two.

3 of the hatchlings

17 July 2008

php|arch article

I got another article published. In fact, it looks like I made the cover of the June 2008 issue of php|architect. The article is titled "EAV Modeling" and talks about a database design I've used in a couple of recent projects.

Working with the editor on this assignment was a good experience. She made me feel a lot more involved in the process than I did with the Linux Journal article. *shrug*

16 July 2008

barn swallows

About a month ago I started noticing a bird's nest attached to the wall near the door to my apartment. I'd occasionally see a couple of small, orange-and-black birds coming and going. Because of something that happened a couple of days ago, I wanted to find out what kind of birds they were.

A Web search directed me to whatbird.com. This site has a pretty cool search feature allowing you to enter certain characteristics of a bird (size, color, tail shape, etc.), and it'll help you figure out what kind of bird it is. Turns out that my neighbors are barn swallows.

The thing that happened earlier in the week is that their eggs hatched. So now I have about four other new neighbors. I took a few pictures and posted some of the better ones to my flickr account:



12 July 2008

PHP frameworks: performance

For some time now I've been trying to figure out what to do about PHP frameworks. Most notably I've been wondering which one would be best for my needs and whether or not it's worth my time learning one. The problem is that there are so many. Zend, Cake, and Symfony appear to be pretty popular (at least, they are frequently mentioned in PHP blogs).

developertutorials.com has a post which highlights a recent performance analysis of Zend, Cake, and CogeIgniter. The concluding sentence is a good summation:

...if you’re building small applications, CakePHP will clearly save you time in development, CodeIgniter will offer massive performance benefits, and Zend will give you a reasonable middle ground.

Still not sure which one I want to try, but I lean a bit toward Zend (although it has received some recent criticism regarding its coding conventions and documentation). I like it that you can use it as a full-blown framework or just import the features you need for your application.

When I get some time, I guess *shrug*

07 July 2008


mod_security is an open source Web application firewall which operates as an Apache module. mod_security inspects incoming requests (and, I believe, can also inspect outgoing responses) and take certain actions if a request (or response) matches a pattern. These actions can include logging and/or blocking the request. mod_security works sort of like anti-virus software, in that it comes with a ruleset which can identify common malicious activity (like cross-site scripting and SQL injection attempts). Like anti-virus software, it's necessary to update the ruleset from time to time.

I installed mod_security on a couple of production RHEL5 Web servers lately, and here are a few of my observations.

Installing mod_security is pretty easy and is documented in the mod_security download. I found that I needed to install the following packages to meet some dependencies and to build mod_security:
  • apr-devel
  • gcc-c++
  • httpd-devel
  • pcre and pcre-devel
  • libxml2-devel

I had the support of my managers to put mod_security in full blocking mode, so after copying the rules directory to /etc/httpd/modsecurity.d, I saved the following in /etc/httpd/conf.d/modsecurity.conf:

LoadFile /usr/lib/libxml2.so.2

LoadModule security2_module modules/mod_security2.so
LoadModule unique_id_module modules/mod_unique_id.so

<IfModule mod_security2.c>
Include modsecurity.d/*.conf
Include modsecurity.d/optional_rules/*.conf

The Web servers run a variety of custom Web applications as well as some canned software like Webcalendar and Wordpress. I didn't experience any problems with the custom applications or Webcalendar, but mod_security took issue when someone tried to edit an existing blog post in Wordpress (curiously, there wasn't any trouble when submitting a new post). So I put the following in /etc/httpd/modsecurity.d/modsecurity_crs_15_customrules.conf:

<Directory /path/to/wordpress/wp-admin>
SecRuleEngine Off

I'm in the fortunate (and perhaps unusual) situation of being able to restrict access to the wp-admin directory by IP address, so I don't have the entire Internet hammering at the thing. Looks like blogsecurity.net has a custom mod_security configuration for Wordpress which I just haven't had time to try yet.

Another wrinkle I had was that some command-line Perl programs I run would be blocked because they weren't providing "accept" and "user-agent" request headers. One of these programs looked something like this:

#!/usr/bin/perl -w

use strict;
use HTTP::Request::Common;
use LWP::UserAgent;

my $ua = LWP::UserAgent->new();
my $uri = shift @ARGV;
my $res = $ua->request( GET $uri );
print $res->content();

I had to make the following two changes/addition:

my $res = $ua->request( GET $uri, accept => 'text/html' );

(Looks like just about any non-blank user-agent will do.)

Another trick I've learned is that instead of using SecRuleEngine Off (like I did for the Wordpress wp-admin directory, which makes mod_security totally ignore that directory), you can use SecRuleEngine DetectionOnly, which makes mod_security log what it would do without actually blocking requests. This can be good for debugging.

And although I haven't needed it, the mod_security documentation suggests a way to whitelist requests from a specific host:

SecRule REMOTE_ADDR "^192\.168\.1\.100$" nolog,phase:1,allow

All in all, installing mod_security has been a fairly easy transition, and it's nice having another layer of protection.

06 July 2008

xephem in Ubuntu

I was out with friends last night (4th of July fireworks), and they asked me to identify a bright object in the sky (I used to be an astronomer). I'm really out of practice at that kind of thing, so I speculated that it was Sirius (there was some light cloud cover, and I couldn't see whether or not this object was southeast of Orion, but it was pretty bright). Turns out I was wrong.

There's a really cool desktop ephemeris program called Xephem from the Clear Sky Institute. So I installed that on my Ubuntu desktop this morning to find what that thing was last night. I had to fulfill a few dependencies to compile xephem. Here's what I had to install first (I just explicitly installed the ones in bold--apt-get installed the packages in parentheses as dependencies):
  • libxt-dev (libsm-dev, libice-dev)
  • x11proto-print-dev
  • libxp-dev
  • libxext-dev (x11proto-xext-dev)
  • libxmu-headers (?)
  • libxmu-dev

(I'm not sure I needed libxmu-headers.)

After that I mostly just followed the directions in the INSTALL file from the xephem download. I copied the data directories (auxil, catalogs, etc.) to /usr/share/xephem (a directory I created) and put the following in ~/.xephem/XEphem (xephem didn't seem to want to read /usr/X11R6/lib/X11/app-defaults/XEphem as the INSTALL file suggested):

XEphem.ShareDir: /usr/share/xephem

I also gziped the man page (xephem.1) before copying it to /usr/share/man/man1/xephem.1.gz. And I created /usr/share/doc/xephem-3.7.3/ and copied in the Copyright, INSTALL, and README files.

By the way, that object turned out to be Jupiter. shrug

05 July 2008

apt-get: "kept back"

I have the following (executable) file in /etc/cron.daily on my Ubuntu desktop:


apt-get update
apt-get -s upgrade

This lets me know when updates are available: the -s option lists available updates without running them unattended.

Occasionally I'll get a list saying that some updates have been "kept back." I always have trouble remembering what to do in this case. It's typically just some dependency problem. This issue is addressed in the APT HOWTO on the Debian Web site. In my (limited) experience, this has always been overcome by doing apt-get instal pgkname, where pkgname is the offending package which is being "kept back."

29 June 2008

n800 maemo updates

I got a Nokia n800 Internet tablet a few months ago and installed the Maemo os2008 software platform. I put the n800 in red pill mode to install some packages, and I just left it that way and forgot all about red/blue pill mode.

It didn't take long for me to find that updates just didn't work, but I never put the two things (red pill mode and broken updates) together. Looks like this is a well-known problem (see the bottom of the red pill mode wiki page linked above).

So if you put your n800 in red pill mode and updates don't work (mine complained that it needed to resolve libglade dependencies: it seemed to want to update to a version which was already installed), put it back in blue pill mode and try running updates. That worked for me.

22 June 2008

mcrypt randomness in PHP

The other day I was trying to debug a PHP program which was being really slow. I'm not bright enough to use proper debugging tools (like xdebug), so I just sprinkled in a bucketload of error_log() calls until I figured out what was gumming up the works.

It turned out to be an mcrypt_create_iv() call. Sometimes that call would run in a fraction of a second, and sometimes it would take over a minute, with no discernible pattern. I had pretty much done a copy-and-paste from the mcrypt_module_open() manual page, which shows using the MCRYPT_DEV_RANDOM constant as the second argument to mcrypt_create_iv(). It finally occurred to me to try using the MCRYPT_DEV_URANDOM constant (note the "U"), instead, and the encryptions immediately became consistently fast.

This was happening on a VMWare ESX guest running RHEL4. A Web search or two found a good comparison of /dev/random v. /dev/urandom, and my problem turned out to be a good illustration of /dev/random blocking the caller until sufficient entropy is attained.

21 June 2008

HTML form attack

The other day I came across a post about the HTML form attack.

I don't think I'd seen this before, and I'm not well versed in JavaScript attacks (authors of the planet-websecurity.org blogs would probably point, laugh, and yell "NOOB!"). But when I sort of figured out what it was talking about, it occurred to me that a form on a page which is vulnerable to cross-site scripting could be made to POST to an arbitrary location. Try the following in a JavaScript-enabled browser, and see where it ends up taking you when you click the submit button:

<form id="gakkk" action="/good.html">
<input type="submit" />
<script type="text/javascript">
// <![CDATA[
document.getElementById('gakkk').action = '/bad.html';
// ]]>

20 June 2008

GPG wallet in cygwin

The other day it occurred to me try my password wallet in cygwin. The wallet requires dialog, but cygwin doesn't seem to have a dialog package. So I figured I'd try building it.

dialog requires ncurses, which meant that I needed to install the ncurses-devel cygwin package (using the cygwin setup tool). Then I downloaded the dialog source and did configure && make && make install, and that "just worked" to get dialog in cygwin. And then the wallet "just worked," too.

So if you're running Windows and want to try the password wallet, install cygwin and give a wallet a try.

19 June 2008


(I'm practicing for an "Unreadable blog post title" contest.)

Here are a few hints on how to use SSL certificates when connecting to MySQL from a PHP program using the AdoDB database abstraction layer. (You may want to see my previous post on setting up SSL certificates for MySQL connections.)

The trick is to use a DSN in the NewADOConnection() call (rather than authenticating with a Connect() call) and to use the mysqli driver (looks like the mysql driver won't work for this). The DSN syntax allows you to supply client flags, and there's a mysqli flag for using SSL certificates.

After creating a CA certificate (we'll say it's at /path/to/ca-cert.pem), make sure that the following item is in the [client] stanza of /etc/my.cnf or the connecting user's ~/.my.cnf on the client host:


Then try the following PHP program:

// these are part of the AdoDB library
require '/path/to/adodb-exceptions.inc.php';
require '/path/to/adodb.inc.php';

* I got the '2048' from running
* printf( "%d\n", MYSQLI_CLIENT_SSL )
* in a PHP program (w/ the mysqli extention installed)
$dsn = 'mysqli://ssluser:sslpass@dbhost/test?clientflags=2048';

$dbh = NewADOConnection($dsn);

$sql = "show status like 'ssl_cipher'";
$res =& $dbh->Execute($sql);
print_r( $res->fields );

This should generate output similar to like this:

[0] => Ssl_cipher
[Variable_name] => Ssl_cipher
[1] => DHE-RSA-AES256-SHA
[Value] => DHE-RSA-AES256-SHA

17 June 2008

SSL in MySQL connections

Last week I wanted to figure out how to use SSL certificates in MySQL connections. This is well-documented on the MySQL Web site, but here are a few wrinkles I experienced while figuring out how to get this working (this was with MySQL5 on CentOS5 and RHEL5).

After creating the certificate authority (CA) certificate/keyfile pair, you can specify them in the mysqld section of /etc/my.cnf:

When making certificates for a client connecting locally (e.g., ssluser@localhost), it's important to supply localhost as the "common name" when prompted by openssl. (Yes, it's probably pretty silly to use SSL for a connection over the loopback interface, but you might be in this situation if you were testing.)

If you want to specify the CA (whose signature must appear in client certificates) when setting up a MySQL user (as you might when using the require x509 syntax), the fields should be separated by backslashes ('/'): grant usage on *.* to ssluser@localhost require issuer '/C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd/CN=www.example.com/emailAddress=webmaster@example.com';
The following command will more-or-less correctly format the issuer for the grant statement:

openssl x509 -text -in /path/to/ca-cert.pem | grep Issuer \
| cut -d':' -f2 | sed -e 's/, /\//g'

Using issuer and subject items imply x509, and it's an error to try using x509 and issuer.

Depending on the require clause in the grant statement, you can use one or more of the following to connect to the SSL-enabled server:

  1. mysql -u ssluser -p

  2. mysql -u ssluser --ssl-ca=ca-cert.pem -p

  3. mysql -u ssluser --ssl-ca=ca-cert.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem -p

If you use require none or omit the require clause, you can use any of the three connection commands. If you use require ssl, you can use #2 or #3. And if you use require x509, you have to use #3 (note that #3 includes the --ssl-ca option). After connecting, type status (or just \s) and make sure that the SSL item says something encryptiony (mine says Cipher in use is DHE-RSA-AES256-SHA).

Unless client certificates are really necessary (extra client-level authentication), it's probably adequate just to use require ssl and to have the client provide the CA certificate (this appears to provide as high a level of encryption as the client certificate does). But note that you still need to generate the server certificate and key, even if you're not using client certificates.

15 June 2008

MIME-decoding email attachments

Occasionally a friend will forward a message to my gmail account, and the forwarded message ends up as a plain-text attachment in the message I receive. If the original message had an attachment, that attachment appears as a MIME-encoded section of the attachment.

If this happens to you, you could try the following. Save the attachment as a text file, and open that file in a text editor. Delete all the lines except the lines which represent the encoded attachment (don't keep the attachment headers, just the lines of text which are 76 characters wide [the last line may be shorter--keep that one, too]). Don't forget to get rid of the lines after the attachment. Save the file as encoded.txt.

Save the following to an executable file called mime_decode somewhere in your $PATH:

#!/usr/bin/perl -w

use strict;
use diagnostics;

use Carp;
use MIME::Base64;

my $usage = "$0 infile outfile";
if ( @ARGV != 2 ) {
die "usage: $usage\n";
my ( $infile, $outfile ) = @ARGV;

open my $fh, '<', $infile or croak "cannot read $infile";
my $encoded = join '', <$fh>;
close $fh;

my $decoded = decode_base64($encoded);
open $fh, '>', $outfile or croak "cannot write $outfile";
print {$fh} $decoded;
close $fh;

Then run the following command:

mime_decode encoded.txt decoded

decoded should be the original attachment.

If you know of a standard utility which does this (especially if it doesn't require the user to prune the email message), please leave a comment.

13 June 2008


As a big Transformers fan and someone who, well, goes to the bathroom, I thought this was pretty cool.

01 June 2008

Fallen Tree

There was a ferocious wind-and-rain storm here a week ago, and it knocked over some trees. I took some pictures of one of the more impressive casualties. I think it was an elm tree, and (judging by the rings) it appears to have been around forty years old. They cut it up to cart it off, and they made a cut just above the roots. It was probably around two feet in diameter at the base.

Here are a couple of the pictures...

another ring detail

gnarled roots

Burning Universal Studios

A couple of years ago I visited L.A. with friends, and we checked out Universal Studios. We took the tour, which included the cheesy-but-fun King Kong attraction.

That part of the tour was destroyed by fire this morning. The same fire damaged the town hall clocktower from the Back to the Future set, and damaged over 40,000 reels of film (fortunately, there are duplicates in another location--someone was awake during the "Make Backups" lecture at film school).

Tourist attractions have had a hard time of it lately.

24 May 2008

RPMs on a tight filesystem

I've ended up managing a couple of CentOS servers which don't have much free space left on their root (/) filesystems. I was looking through their lists of installed packages, and I discovered a useful trick. The following command will give the size (in bytes) of the original RPM of an installed package:
rpm -q --qf '%{archivesize}\n' pkgname

So if you needed a report indicating roughly how much filesystem space each installed package on an RPM-based distribution was consuming, you could try this:
rpm -qa --qf '%{archivesize} %{name}\n' | sort -rn

When I did this on a CentOS4 box with a full install, I was rather unsurprised to find that the top offender is the OpenOffice.org internationalization package openoffice.org-i18n.

21 May 2008

Hard Time

From the AP news wire:

Lou Pearlman, the man who created the Backstreet Boys and 'N Sync, was sentenced Wednesday to 25 years in federal prison for engineering a decades-long scam that bilked thousands of investors out of their life savings.

Well, at least he's going to jail, even if it may be for the wrong reason.

And I willfully acknowledge the irony of tagging this post with the 'music' label.

19 May 2008

root ssh access trick

Free Software Daily had an interesting post the other day about securing SSH services (that post points to a Tux Training article). This particular tutorial included a configuration item I hadn't seen before. It's a configuration value for the PermitRootLogin field.

If I'm running an SSH service which is visible to the Internet (or even a large intranet), I tend to disable PermitRootLogin (PermitRootLogin no), because the script kiddies can be reasonably sure that an SSH service will have a user called root, and if they try hard enough, they might get lucky with the password.

(I'm also a big fan of the AllowUsers option, which allows you to provide a list of users allowed to log in via ssh. If a valid user not on that list tries to log on, ssh acts as though the user has provided the wrong password.)

The new (new to me, anyway) trick in this tutorial is setting PermitRootLogin without-password. This allows root to log in with a key, but not with a password. This is a really good compromise if you have a server where you need root to be able to log in over ssh. Backups over rsync are a good example of this: to preserve file ownership and permissions, it's sometimes necessary to have rsync run as root.

18 May 2008

Bletchley Park financial problems

A recent Slashdot post talks about financial problems at Bletchley Park. Bletchley Park was home and workplace to Allied cryptographers in WWII. Some say that their success at deciphering German Enigma messages was responsible for the Allied victory against the Nazis. At the very least, their efforts probably significantly shorted the war (in the European theatre, anyway).

It's sad to me to see such an important historical site threatened. They'd probably turn it into condos and shopping centers.

16 May 2008


The other day Film School Rejects (great blog, with a great podcast) has a post about a flickr set of lunchpails. Reminded me of a Hong Kong Phooey lunchpail I used to have.

10 May 2008

problem w/ PHPUnit reports on CentOS5/RHEL5

Yesterday I was trying PHPDocumentor and was going through its Quickstart guide. After I ran phpdoc on the sample code, I threw the reports in my CentOS5 Apache document root so that I could look at the output. Several of the pages wouldn't load. After a quick look at the Apache error log, I saw that those pages were generating PHP errors (the T_STRING gripe), even though the files were named something like sample.php.html.

(CentOS5 and RHEL5 have Apace v2.2.x.)

It took me a while to figure it out, but it's due to an odd feature of Apache which honors multiple extensions in filename. RHEL5 does an AddHandler php5-script .php which tells Apache to run all files with a .php extension through the PHP5 interpreter. I didn't know this, but it even does this for files with names like sample.php.html, where .php isn't at the end of the filename. So even though the phpdoc output files should just render as HTML, they were being interpretted as PHP and were throwing errors.

So I created a directory called /var/www/html/phpdoc and added the following to /etc/httpd/conf.d/php.conf in a Directory container (and restarted Apache): RemoveHandler .php

That convinced Apache not to run any files in that directory through the PHP5 interpreter. Incidentally, I had previously tried SetHandler default-handler for that directory, and it disabled PHP5, but it also disabled nice things like autoindexing (which broke URLs like http://localhost/phpdoc/sample/: Apache would refuse to serve a directory).

By the way, this doesn't seem to affect CentOS4/RHEL4 (Apache 2.0.x and PHP4), because Apache sets up PHP a little differently: it does an AddType, so there's no conflict of having both a text/html content type and a PHP5 handler.

08 May 2008


Today digg had a story highlighting a topless robot post offering
The 11 Best Songs from Geek-Movie Soundtracks. Most of the 11 songs didn't really do it for me, but one of them was Prince's Batdance from Batman. I probably hadn't seen that in fifteen years, and it was fun watching it again.

07 May 2008

Satellite imagery of post-cyclone Myanmar

Estimates of the death toll in Myanmar have gone up and up over the last few days, and a Dot Earth post showing satellite images before and after the cyclone illustrate why.

06 May 2008

"Star Trek: The Experience" maybe closing

I went to Las Vegas with friends a few years ago, and one of the things we did was to check out Star Trek: The Experience at the Vegas Hilton. It's expensive, but you can walk through a museum which has props from the shows and a timeline of the Star Trek universe, there's a bar modeled after Quark's in DS9, and there are two rides: The Borg Invation 4D and Klingon Encounter. I actually didn't much care for the Borg show, the the Klingon ride was pretty cool. Walking through the museum was fun, and Quark's was a kick. There's also a good gift shop that'll be happy to overcharge you for souvenirs.

Looks like they may be shutting the thing down. So if you're in Vegas before September, and if you like Star Trek (and are OK with throwing away some cash), go check it out while you still can.

05 May 2008

MySQL query optimization from Jay Pipes

Jay Pipes has posted slides from a recent presentation in which he discussed query optimization in MySQL. Pretty good pointers, worth a look.

26 April 2008

updated WordPress security whitepaper

blogsecurity.net has released version 1.2 of their "How to secure WordPress" whitepaper. Looks like they've added some v2.5-specific details along with updated information about security-related plugins.

25 April 2008

Wil Wheaton and Radio Free Burrito

I've recently started reading Wil Wheaton's blog, and I've really enjoyed it. He's a very good writer with a lot to say.

Perhaps like many viewers, I felt that Wesley was one of the dimmer lights in Star Trek: The Next Generation. I think Wil might reply to that kind of comment with something along the lines of "I was a kid. I did what they told me to do." Look me in the eye and tell me you'd have done any differently. Thought so. And me neither.

(Besides, he got to make out with Ashley Judd. Look me in the eye and tell me you'd have done any differently. Thought so. And me neither.)

Anyway, this week he posted a couple of episodes of his Creative Commons podcast called Radio Free Burrito, on which he plays some music from podsafe. It's totally awesome and you're totally a hoser for not listening. So get over there and start listening.

18 April 2008


Battlestar Galactica is finally back, and I'm really enjoying it. The other day I found the Battlestar Wiki and thought it was pretty cool. I'm pretty eager to find out who the twelfth Cylon is. My money is on Tom Zarek. Or maybe Dualla.

16 April 2008

Prompt for new firefix window

I tend to run my window manager (fluxbox) with four desktops, and I typically have firefox windows open in two of them. Occasionally I have to open a firefox window on the third or fourth desktop, and it's a nuisance to go to one of the first two desktops, open a new window (Ctrl-N), and move the new window to the other desktop (and I acknowledge the irony of considering that a "nuisance").

I recently discovered the -new-window command-line option to firefox. It takes a URL as an argument, and it opens that URL in a new window. So I wrote a shell script that prompts me for a URL and then opens that page in a new browser window. If you want to try this, save the following to a file (I saved it to ~/bin/ffwin), and remember to make the file executable:


URL=$( dialog --stdout \
--backtitle ffwin \
--title 'new Firefox window' \
--inputbox 'URL:' 8 40 )
if [ ! -z "$URL" ]; then
exec firefox -new-window $URL

When you run this, a new xterm window will open, and dialog will prompt you for the URL. Preceding the firefox call with exec means that the xterm will go away after you enter the URL.

As a further refinement, make it so that you can run this from a menu-click. I added the following entry to ~/.fluxbox/menu, so that I just have to right-click on the desktop and select "ffwin":

[exec] (ffwin) {xterm -e ~/bin/ffwin}

Other window managers would likely allow you to create a custom application launcher from a toolbar or menu or widget or something.

14 April 2008

XML in PHP5: the weather

My favorite weather-related Web site is the weather underground, but their pages can be a bit heavy. Usually I just want a quick summary of current conditions and a forecast for the next day or two. Thankfully, wunderground provides this in XML format. Here's the example for Portland, Oregon: HTML, XML.

I thought it would be fun to write a quick PHP program to download the XML file, parse it, and present it in an easy-to-read format. I decided to use the SimpleXML extension for PHP5, because my XML-parsing needs are pretty modest for this project. And I'll use the curl extension to fetch the XML file.

$url = 'http://rss.wunderground.com/auto/rss_full'
. '/OR/Portland.xml?units=both';

$ch = curl_init($url);
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_HEADER, 0 );
$xmlstr = curl_exec($ch);
$res_info = curl_getinfo($ch);
if ( $res_info['http_code'] != 200 ) {
header( 'content-type: text/plain' );
die("couldn't open $url");

$xml = new SimpleXMLElement($xmlstr);
$epoch = strtotime( $xml->channel->pubDate );
$date = date( 'H:i:s l j F Y', $epoch );
$report_uri = htmlentities(
$xml->channel->item[0]->link );
$content = '';
$forecast_items = array();
foreach ( $xml->channel->item as $item ) {
$desc = strip_tags( $item->description );
$forecast_items[] = array(
'guid' => $item->guid,
'desc' => htmlentities( html_entity_decode($desc) ),

echo '<html><body><h1>Weather Underground Report</h1>',
'<h2>Portland, Oregon: ', $date, '</h2>';
foreach ( $forecast_items as $item ) {
$id = '';
if ( !empty($item['guid']) ) {
$id = ' id="' . $item['guid'] . '"';
echo "<p$id>", $item['desc'], '</p>';
echo '<p><a href="', $report_uri, '">Full report</a></p>',

There's some magic in the first foreach loop. Just as you should never trust anything typed into a Web form, you should also be skeptical of content from a foreign XML document, hence the strip_tags() and htmlentities() calls. But some of the characters in the wunderground XML are already HTML-encoded (like the degree symbol), so it's useful to call html_entity_decode() first (otherwise the temperature might look like "75&#176;F", rather than "75°F").

The code is otherwise straightforward. If you look at the raw XML, you'll find that the entire report is wrapped in a <channel> container, inside which the report date is wrapped in a <pubDate> container, etc. As its name implies, SimpleXML makes parsing XML pretty easy, and it's a great choice for small projects like this.

08 April 2008

fopen($url) v. curl in PHP

Occasionally you'll see PHP code which uses require() or include() or fopen() or file_get_contents() to import code from a remote location (the argument to those functions can be a URL). This sort of thing is generally considered to be a bad security practice, especially if you don't control the code at the remote location (it could unexpectedly change in such a way as to do something destructive to your application).

Many PHP security experts tend to recommend disabling the allow_url_fopen option in php.ini. Disabling this feature can even serve to prevent inadvertent code injection. Imagine an application which calls require($file) where $file is dynamically determined. If your application has some sort of problem which allows an attacker to set the value of $file, the attacker can inject the code of his/her choosing into your application.

So I feel that disabling allow_url_fopen is a good idea, but sometimes you need to initiate HTTP requests in your PHP code. The curl extension provides a good way of doing this. The following snippet will put the contents of the Web page at $url into the $page variable:

$ch = curl_init($url);
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_HEADER, 0 );
$page = curl_exec($ch);

The previous example is a GET request, but you can also do POST:

$postdata = 'var1=value1&var2=value2';
$ch = curl_init($url);
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_HEADER, 0 );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $postdata );
$page = curl_exec($ch);

07 April 2008

undeclared attributes in PHP classes

I was recently surprised to discover that a PHP object can have attributes (variables) not declared in the class. The following works in PHP4 and PHP5 (it prints 'ick' and then 'yark'):

class Gakkk {}

$gakkk = new Gakkk();
$gakkk->blech = 'ick';
echo $gakkk->blech, "\n";
$gakkk->blech = 'yark';
echo $gakkk->blech, "\n";

At best, this strikes me as a very poor programming practice. Who knows when this sort of thing will stop working (in a future version of PHP)? And what kind of code readability is this?

I really like PHP, but this is just weird to me.

06 April 2008


Since last year's announcement that PHP4 will reach end-of-life this summer, I've been wondering what will become of PHP in the versions of Red Hat's Enterprise Linux distribution which shipped with PHP4. Looks like Red Hat will continue to provide bugfix and security updates for PHP4 throughout the lifetime of its PHP4-relevant distributions.

05 April 2008

Falkirk Wheel

Friends of mine like roller coasters. Screw that. I wanna ride the Falkirk Wheel:
I've long been fascinated by locks and canals (I walked over the Erie Canal twice a day my first year of grad school), and this is one of the cooler mechanisms I've seen. It's even quite energy efficient: because the two caissons (the 'chairs' of this two-chair merry-go-round) always weigh the same, it takes very little energy to run the thing.

If I'm ever in Scotland, I'm totally checking this out.

24 March 2008

rate-limiting in iptables

I recently learned about a useful feature in iptables which might help prevent denial of service (DOS) attacks. The iptables "recent" extension dynamically creates a list of source addresses against which your ruleset can match, for example, to block someone who is making too many connection attempts in a given time interval. The Debian Administration blog has a good example of using this to block DOS attacks against an ssh server.

23 March 2008

iterating through an array in bash

Every now and then I need to iterate through an array of items in a bash script, and I can never remember the syntax--I always have to look it up. So here's a quick example...


things=( first second third )

for i in ${things[@]}
echo $i

If the number of array elements is large, it can be useful to have one element per line:

things=( \
first \
second \
third \

16 March 2008

another Highlander sequel

The other day I rented Highlander: the Source, and I watched it this evening. Although the original film is one of my favorites, I didn't have very high hopes for this one: all of the sequels have been disappointments (although I seem to remember thinking that the fourth film wasn't horrible).

But I got a bit of a surprise. There's more to say about this movie than I would have imagined. I was surprised because this newest installment is actually worse than Highlander II, which I did not think was humanly possible. Highlander II at least had a fun villain. This film stars Adrian Paul as Duncan MacLeod from the Highlander TV show, and in the film Paul is surrounded by a handful of characters who are even less interesting than he is.

So if you're in the video store and you see a copy of Highlander: the Source, keep walking, and rent something better, like Ishtar, Plan 9 From Outer Space, or Highlander II.

15 March 2008

relativistic economics

There was an interesting Slashdot article the other day about a satirical speculative analysis of the economics of interstellar trade. The idea is that if you're shipping something to another star system, you've made a significant financial investment in the goods you are shipping, and the duration of the voyage will be long enough that there should be an interest rate applied to your investment.

The interesting wrinkle appears when you consider that for interstellar trade to be worthwhile, the cargo vessels will need to travel at relativistic speeds. Special relativity describes the effect of time dilation, the phenomenon of a measurable discrepancy in the voyage duration as measured by the ship's crew versus that of a stationary observer (like the investor).

So whose measurement of time do you use to compute the interest?

To extend this nonsense to other predictions of special relativity, the ship's mass and length will also be affected, which might complicate matters for the interstellar equivalents of weigh stations.

09 March 2008

Class::Accessor constructors

I'm a pretty big fan of Class::Accessor. It's great for those occasions when you need to write a Perl module which has lots of attributes. You tell your module to inherit from Class::Accessor, provide a list of attributes, and your module automatically has accessors and mutators for all of those attributes. Class::Accessor even takes care of creating your module's constructor.

That last point was actually giving me some trouble the other day. I was writing a Perl module, and it turned out to have several attributes (counters that needed to be incremented while parsing a file), so I decided to have my module inherit from Class::Accessor. But one of the attributes was going to be an instance of another class (I wanted to use composition, rather than multiple inheritance), and I wanted to instantiate this object when my object is instantiated. But since Class::Accessor creates my constructor automatically, it wasn't clear to me how I'd do this.

With a little fiddling, I was able to override the Class::Accessor constructor in such a way that it still created my accessors and mutators, but also allowed me to do other object initialization tasks:

package Gakkk;

use strict;
use diagnostics;
use warnings;

use base qw/ Class::Accessor /;

use Some::Other::Class;

sub new {
my $class = shift @_;

my $self = $class->SUPER::new(@_);
$self->flamningle( Some::Other::Class->new() );

return $self;

# other methods, ...


The call to $class->SUPER::new(@_) gives what's left of the argument list (@_) to the constructor of the parent class (Class::Accessor) and returns an instance of my class. I'm then able to initialize my object attributes without requiring that the calling code do it explicitly. Without overriding the constructor, the caller would have to do something like this:

my $gakkk = Gakkk->new(
flamningle => Some::Other::Class->new(),
line_number => 0,
num_parse_errors => 0,
num_zortbiptons => 0,

Having overridden the constructor, the caller can instantiate the class like this:

my $gakkk = Gakkk->new();

01 March 2008

IntranetAddress PHP class

I've added another Google code project. This one is called IntranetAddress, and it's a PHP class which you can use to determine whether or not an IPv4 address belongs to a set of network ranges (specified in CIDR notation in a configuration file). The class requires the Net::IPv4 PEAR package, and a PHPUnit test suite in included.

18 February 2008

overnight at the lake

I'm writing this from my friends' lakehouse. I've been here since yesterday afternoon, and it's been a nice break from routine. I took a few pictures which I think came out pretty well.

There was a brief snowstorm yesterday afternoon with wonderfully large snowflakes:

lake snowstorm 12 of 15

This morning I took a picture from a similar angle. The lake was so still this morning--like looking at glass:

lake sunrise 2 of 7

16 February 2008

password wallet update

Yesterday I discovered an interesting (and somewhat alarming) problem with my password wallet.

I use vim for my text editor (I have export VISUAL="/usr/bin/vim" in my ~/.bashrc). Yesterday I used the wallet script to update my password list, and then later I was using vim to edit a totally unrelated text file. I fat-fingered what I was doing and typed some magical set of keystrokes (still not sure just how I did that), and suddenly I was looking at several lines from my password file. I recognized those lines as lines that I had highlighted, deleted, and then pasted to a new location when editing the password file when I was using wallet. I then had a forehead-slapping moment when I realized that such edits are saved for posterity in the ~/.viminfo file.

Oops. That's a potential information leakage vulnerability.

But it is easily remedied by adding the following line to ~/.walletrc:
VISUAL="/usr/bin/vim -i NONE"

The -i option tells vim to use some file other than ~/.viminfo for its state information. In this case, it tells vim not to store state information at all. The trick of putting it in ~/.walletrc (rather than in ~/.bashrc) means that vim only skips storing state information when running wallet--vim will keep state information in ~.viminfo any other time you run vim.

So if you're using wallet with vim, I urge you to make the above change to your ~/.walletrc file.