Skip to content

2005

Don't blog bugs, file bug reports (and read the manual before you do that)

Well, I'm disappointed again by John Lim's continual lack of a decent bug report; claiming that you lack the time while having had time to post two blog entries about it is pretty poor.

Let's see the code you're using to call into PDO, John; there's not much time before we release, and without your cooperation, the problems you're seeing won't get addressed.

I'll speculate that John's ADOdb snippet:

<?php
   $rs = $db->Execute("select * from table where a=? and b=?",array('a'=>1,'b'=>2));
 ?>

is trying to bind 'a' and 'b' by parameter names, but the parameters in his query are identified only by their positions (using question marks). I wonder how that is supposed to work? Maybe he should try this:

<?php
   $rs = $db->Execute("select * from table where a=:a and b=:b",array('a'=>1,'b'=>2));
 ?>

It's also worth noting (again) that PDOStatement::getColumnMeta is intentionally unimplemented on this first PDO release, hence its experimental status; in other words, don't use it. Most people don't need this kind of feature anyway.

Sun Studio 11 Compiler now available, and it's free

Sun's commercial grade compiler is now available for free on Linux (RHEL and SuSE) and Solaris platforms.

It will be interesting to see how the use of this takes off with the various OpenSource projects; the Sun compiler is pretty good, and should have some nice optimizations on AMD architectures (Sun's new favourite).

In other Solaris news, Intel Pro Wireless 2100 and 2200 chipsets are now supported on OpenSolaris, in addition to Atheros, which has been around for a little bit longer. I have the latter in my laptop and it works flawlessley.

In other-other Solaris news, Oracle announces that Solaris 10 is its preferred platform again.

Recent books

I've had a couple of longish flights recently, and opportunity for reading.

Life Expectancy is a Dean Koontz novel. I find that his books tend to be a bit cliche and predictable (but still enjoyable), but this one is different. It's not his typical horror novel; you're led through the story from the perspective of Jimmy Tock, born on the night his grandfather died. Before his death, he made 10 predictions about Jimmy, 5 of which are proven in short order and the remaining 5 are billed as terrible dates between his 20th and 30th birthdays. This is a humourous and thrilling story of a baker trying to figure out how best to tackle his fate in the face of some pretty heavy goings-on. While some parts are predictable (but again still enjoyable) there is some chain-yanking, in good humour.

Deception Point by Dan Brown. The first Dan Brown novel I've read; it's a fast paced story that ties some political interests to an important scientific discovery. Exciting, fast-paced and has a healthy dose of science in there too. Apparently, all of the cutting edge special forces gear mentioned in the novel actually exists. I enjoyed this book; not as much as I enjoyed Neal Stephensons Zodiac, but I think it's hard to come close to that one :) I can't really write too much without revealing parts of the plot that take a while to emerge; it was a good read.

Airframe by Michael Crichton. I bought this one to read on my flight back from the Zend Conference. While reading the first chapter or so, I began to wonder if this was a mistake, but quickly found that the point of the novel is not to dwell on an incident but to get to the bottom of it. The story follows Casey Singleton as she works towards this goal while trying to avoid harm from disgruntled employees at the aircraft manufacturing plant and unwanted attention from the press. Crichton does an excellent job of making the characters come to life, dosing you up with inside information about aircraft and aircraft safety along the way. It's easy to convince yourself that you've figured out the ending, but you're almost certainly wrong. It's not a plot twist so much as masterful misdirection; a damned good read that'll generally make you feel safe about flying.

Techie Books

In addition to some leisure reading, I've also read a couple of tech books in recent months. I was given a copy of Ilia Alshanetsky's book php|architect's Guide to PHP Security (signed by Ilia himself :) and also a copy of Chris Shiflett's book Essential PHP Security.

I like both books, and I'm not just saying that because the authors are friends of mine. Both books are short, with Ilia's book weighing in the heavier of the two. They're written in different styles; Chris very clearly presents the most common styles of web application attacks and explains how they work and what you should look out for, and how to defend against them. Ilia's book is more of a whirlwind exploration of a lot of different attacks coupled with (fairly specific) examples of how to counter them, while at the same time considering application usability based on his experiences with FUDForum. He also talks about the use of honeypots to draw attackers away from important or sensitive areas of your site.

Chris' book is easier to read, and although it is the shorter of the books, it will help instill the right kind of security thinking that will serve the reader very well. Ilia's book is much more comprehensive, although the very dense writing style can make it a bit harder to read and use as a reference.

If I had to recommend just one book, I'd find it hard. If really pushed, I'd probably suggest that Chris' book be recommended for more junior developers and Ilia's for more senior developers. I'd actually recommend both books to anyone who's really serious; use Chris' book as an introduction to firmly set you on the right track and then follow up with Ilia's book for some more advanced techniques.

I read SQL Server 2005 Service Broker Beta Preview on the flight back from Paris. I picked this up from the Microsoft booth at the Zend Conference. In truth, I only read it because I'd run out of reading material and it was still stashed in the side pocket of my suitcase. This book talks about the Service Broker feature in the new version of SQL Server. This is a reliable, optionally distributed, message queuing facility that ensures message ordering. You're either thinking "Big Deal", "Eh?" or "Neat". This facility is ideal for implementing workflows in a very robust manner. If you're on Windows and have a project coming up in this space, it's worth a read. It sounds like pretty neat stuff; enough so that I might even find some time to play around with it and write some examples in PHP + PDO.

Back from Paris

I'm back home from my Paris trip; it was a long day of travelling, but it all went smoothly. On the train from Gare du Nord to Charles de Gaule I saw a burnt out wreck of a truck; perhaps it was from the rioting, but I couldn't say for sure. This was the only sign of unrest that I saw on the whole trip; a big contrast from the country-on-fire images broadcast via CNN. Admittedly, I only saw a limited section of the Paris area while I was there, so who am I to make a sound judgement?

I've updated the PDO slides from my presentation at Forum PHP 2005. These slides are from the long version of my talk, rather than the shorter 45-minute version that I gave there.

After a slightly shaky start, the trip turned out to be a success. The start was shaky because the service at my hotel wasn't all that great; apparently just giving my surname was not good enough for them to find my reservation, so I had to scrabble around my email (lucky that I had my IMAP mailbox sync'd to my HD!) to find additional information. After then waiting for the english speaker to finish his cigarette break, I could finally confirm my reservation. I then had to wait for my room to be made up. Not the best service I've ever had; I think they probably assumed that I'd come from England that morning, when in fact I'd been travelling from the USA since the day before. Oh well.

The hotel was ok though, and they had free wifi access for guests. It was WEP protected and when I asked about the WEP key, the guy at the desk said he didn't have any more boxes. Strange. The next night I was lucky and managed to obtain a box... it turns out that they use a little box with a wifi-to-ethernet bridge in them; one end of the box plugs into the AC outlet in the wall, and the other into your ethernet port. Interesting approach; it means that they don't need to worry about giving out their WEP keys, can provide service to people without wifi cards and that they don't need to plumb in wired ethernet either.

I've arrived at Forum PHP

I'm sitting in the soundproof booth at the Forum PHP in Paris. I've been up for more than 24 hours straight (don't you just love timezone shifts!) so I'm feeling pretty tired. Contrary to the doom and panic mongering that was on CNN while I was waiting at the airport in Atlanta (that's the airport with the really long walk between the domestic and international concourses), Paris doesn't seem like it's about to be torn down by rioters; seems pretty peaceful and not tense at all. I've been told that the unrest is mainly in the suburbs, and was mostly outside of Paris itself last night.

I've also heard pretty bad things about Charles de Gaule airport, but found it to be quite empty and easy to navigate when I arrived just before 7am local time; maybe I've just been lucky :)

While I'm here, I'll be giving my PDO talk and sitting in on a Q&A panel with the other PHP big wigs that are also here (Rasmus, Zeev, Andrei and Zak). After the conference itself, we'll be holding a meeting to hammer out some of the finer details for PHP 6; the other other PHP big wigs are making their way to Paris after the PHP conference that is concurrently underway in Frankfurt.

pecl4win

I don't know if you're all aware of pecl4win.php.net. This new service, graciously provided by Emini A/S, continually builds PECL extensions against the various different branches of PHP so that you can very easily find the latest version of a given PECL extension to match the version of PHP that you're running.

Edin Kadribasic from Emini has been looking after the official Windows build of PHP (he builds our Windows distribution) for some time, and this service is his latest innovation; thanks Edin!

PDO 1.0RC2 released via PECL

I released the next release candidate for PDO tonight. You can find the full changelog here. There are two changes of note (I can't take credit for these, you can (blame|thank) Ilia and Marcus):

  • Changed PDO_XXX constant names into PDO::XXX and renamed pdo_drivers() to PDO::getAvailableDrivers()
  • Removed the "final" attribute from the PDO and PDOStatement constructors, making it significantly easier to extend PDO in your apps. You'll probably want to look at PDO::setAttribute(PDO::ATTR_STATEMENT_CLASS) if you're doing that sort of thing.

I also released the next installment for the various drivers; mostly bug fixes here and there. The biggest patch was making LOBs work for the OCI driver.

You can find the updated packages in PECL, and find pre-compiled Windows extension DLLs at pecl4win.

Enjoy!

Trying out feedburner

I've redirected my feeds via FeedBurner so that I can get some idea of how many people are reading this stuff. If this causes some burps and "re-runs" of my earlier posting in the various aggregators out there, I apologize.

I've also added a limit on the number of items that wind up in my feed, so you won't have to fetch my entire blog history when polling for new articles.

The feedburner migration should be transparent; no action should be required by subscribers; the URL is the same.

LOB support added to PDO_OCI in PHP 5.1 CVS (finally)

[update: corrected information about STRINGIFY_FETCHES]

It's been a looong time coming, but it's finally here. Here's how to insert a BLOB via PDO_OCI:

<?php
   $db = new PDO("oci:", "scott", "tiger");
   $db->beginTransaction(); // Essential!
   $stmt = $db->prepare(
       "INSERT INTO blobtest (id, contenttype, blob) ".
       "VALUES (:id, :type, EMPTY_BLOB()) ".
       "RETURNING blob INTO :blob");
   $stmt->bindParam(':id', $id);
   $stmt->bindParam(':type', $type);
   $stmt->bindParam(':blob', $blob, PDO::PARAM_LOB);
   $type = 'image/gif';
   $id = 1; // generate your own unique id here
   $blob = fopen('/path/to/a/graphic.gif', 'rb');
   $stmt->execute();
   $stmt->commit();
   ?>

This will suck the contents of the graphic.gif up and store it into the newly inserted row. This syntax most closely matches the generic blob insert syntax that I talk about in my PDO presentation, there are two differences that are peculiar to Oracle. The first is the RETURNING blob INTO :blob that's tacked onto the end of the INSERT query. The reason for this is that Oracle stores "LOB Locators" rather than LOB contents in its table rows.

A LOB Locator tells Oracle where it stashed the actual LOB contents without making the table rows overly large, and allows some clever optimizations when manipulating LOBs. You can't just conjure up a LOB Locator though, so you need to insert a brand new empty LOB into a table and then fetch it's locator back out before you can start modifying it. (If you're coming from a mysql background, you can think of the locator as being something like a mysql auto-increment field; you need to insert a row before you find out what the value of the field is.)

Rather than issuing 2 queries just to make an insert, Oracle provides the RETURNING ... INTO syntax as a shortcut; it's equivalent to SELECTing the columns back out again, but it bundled up into a single query, saving the effort of parsing multiple queries and the overhead of multiple network round-trips to get everything where it needs to be.

This means that the :blob parameter is actually an output parameter, even though it smells like an input parameter. There's some intuitive magic at work here; if you bind a stream or a string to a PDO::PARAM_LOB parameter, the PDO_OCI driver will assume that you want to store the contents of that stream-or-string into the LOB that gets returned after the execute. So, that's what it does. Post-execute, all the LOB parameters are checked to see what PHP-space variables were bound, and data is written to the LOBs. This has an important implication; if you're doing this, you'd better have a transaction open, otherwise your new LOBs will be committed as part of the execute--before the PDO_OCI driver can write the data into the LOBs.

So, we can insert just fine. What about binding a LOB for output? Here's how:

<?php
   $db = new PDO("oci:", "scott", "tiger");
   $db->beginTransaction(); // Essential!
   $stmt = $db->prepare(
       "INSERT INTO blobtest (id, contenttype, blob) ".
       "VALUES (:id, :type, EMPTY_BLOB()) ".
       "RETURNING blob INTO :blob");
   $stmt->bindParam(':id', $id);
   $stmt->bindParam(':type', $type);
   $stmt->bindParam(':blob', $blob, PDO::PARAM_LOB);
   $type = 'image/gif';
   $id = 1; // generate your own unique id here
   $blob = null;
   $stmt->execute();
   // now $blob is a stream
   fwrite($blob, "GIF89a");
   ...
   fclose($blob);
   $stmt->commit();
   ?>

OK, this sample is still inserting data into the LOB, but it's doing it by binding the LOB for output, and giving you access to the LOB stream so that you can manually do things with it. The same approach will work if you issue a query that returns an existing read-only LOB. This syntax is closer to the traditional oci8 extension LOB support, except that the LOB is mapped as a PHP stream, so that you can use all the usual PHP streams functions to work with it.

LOBs are also handled for simple SELECTs that return rows with LOB columns. The PDO_OCI driver returns each LOB column as a stream; no data is transferred from that column until you start to read from it:

<?php
    $stmt = $db->prepare('select blob from blobtest where id = ?');
    $stmt->execute(array($id));
    $row = $stmt->fetch();
    var_dump($row);
    var_dump(stream_get_contents($row[0]));
    ?>

this will output something like:

    array(2) {
      ["BLOB"]=>
      resource(7) of type (stream)
      [0]=>
      resource(7) of type (stream)
    }
    string(886) ".....BLOBDATAHERE..."

Notice that I'm using stream_get_contents() to transform the LOB stream into a string. If you're writing a portable application (good luck!) you need to be prepared to handle columns coming back as a stream, even if you didn't explicitly bindColumn and ask for it to be delivered as a LOB. If you're not looking forward to handling that dynamically, you might be interested in setting the STRINGIFY_FETCHES database attribute:

<?php
    $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
    // now ALL non-NULL columns will be converted to strings when fetched
    ?>

This will convert all columns to strings, regardless of their original type, when fetches. This does not include NULL columns. This does NOT translate data being inserted. Use your brain before deploying this setting!