Skip to content


It's the weekend: test PDO

It's the weekend, time for relaxation and recreational hacking. The perfect opportunity to give PDO a whirl :-)

Please do try it out soon as you can; with PHP 5.1 beta due on the first of March, it's really important to make sure that we don't have any "brown-paper-bag" bugs sooner rather than later.

If you pass up on this round of testing, and then you find a bug in PDO in PHP 5.1, it's your fault. :-)

Let's try to make 5.1 as "gold" as we can!

PDO: Iterators

[Updated to fix missing execute()]

Louis-Philippe Huberdeau posted this comment to an earlier post, asking:

I have been playing with PDO this morning, looks great! I just wonder if it could use a few more PHP5 features and SPL kind of thing.

The gist of what he was suggesting is already present. His first request was to be able to access the columns as properties of the statement handle. While you can't do that exactly, you can do something similar. His second request was being able to iterate the rows using foreach(). Here are two ways to acheive that, using alternative syntax:

   $stmt = $db->prepare("select foo from bar");
   foreach ($stmt as $row) {
       echo $row->foo;

and the less verbose version:

    foreach ($db->query("select foo from bar", PDO_FETCH_LAZY) as $row) {
        echo $row->foo;

PDO_FETCH_LAZY is almost exactly the same thing as having the properties show up on the statement handle; the "lazy object" you get on each iteration is internally aliased to the statement handle. If you're familiar with the concept of interfaces from other languages, the lazy object is actually the same object instance, it's just a different interface.

The implication of this is that you can't simply copy a $row into another variable and expect its contents to remain as they were at that point; $row still references the current active row of the statement, so if you fetch() another row (either direct or by advancing the iteration with foreach) $row will refer to the new row.

PDO_FETCH_LAZY doesn't mean that you can be lazy, it means that PDO can be lazy. :-)

If you want to be lazy, and still want $row->foo, use PDO_FETCH_OBJ instead; the sample above will work the same.

PDO beta releases

[Update: I forgot to mention that windows binaries are availaing from snaps; all PDO drivers are present, including MS-SQL, which doesn't show up in the PECL package list yet. Note that the sqlite driver has a bug that has already been fixed in CVS; wait a couple of hours for the next snapshot build before trying to use it on windows. ]

I posted this message to the PHP internals and PECL development lists just now. I'm soliciting beta testers for PDO. If you want to help QA PDO ready for its PHP 5.1 debut, please read on.

You may have noticed my "drive-by release" of various different PDO packages tonight/this morning.

This is stage one of the "PDO push".

I'd like to encourage you all to try it out; as you should know, we're going to be releasing PDO as part of PHP 5.1, so we need as many people as possible to play around with it to discover any remaining issues.

Some drivers have had more testing and support than others, simply because they are easier or more convenient to develop and test against.

If you find any missing features, inconsistencies between drivers, bugs or crashes, please report them using the PECL bug tracking system. Please categorize bugs correctly, and, if possible, try out more than one driver. If you have the same problem for more than one driver, report the bug using the PDO bug reporting page, otherwise use the bug reporting page for your driver. The bug reporting pages can be found by visiting<extensionname> and clicking on the "Package Bugs" link. Please don't submit the same problem more than once; add your feedback to existing bugs if it is appropriate.

During the PDO push, I want to release updated PDO packages at the end of each day in which a bug is found and fixed. Please help me with this task by reporting any issues as clearly and completely as possible. Now is the time to test and evaluate PDO; if we don't get enough feedback over the next couple of weeks, it won't make it into PHP 5.1 and you'll have to wait until the next major PHP release.

You'll no doubt be wondering how to use PDO, so here are some useful resources:

The PHP manual

Various posts from my blog; some information is slightly outdated, one of the links includes slides from one of my talks on PDO at the php|works conference last year:

PDO semi-toy example

php|works slides

More on PDO

First steps

My article on the Oracle Technology Network giving an overview of PDO, again, some information my be slightly outdated.

Also during the PDO push, I'll be working with Dan to help flesh out the official PHP documentation for PDO, and quite probably blogging little handy snippets for some of the newer/more advanced features.

Thanks for your attention, and looking forward to your feedback.


50 gmail accounts up for grabs

[Update: 35 remaining]

Yes, 50.

If you're smart enough to figure out how to email me (NOT post a comment on the blog; I need a functional email address from you) to ask for one, you're welcome to it.

blog spam - a solution

Today, this blog got its first ever spam, via the trackback interface. How annoying. Here's how I've stopped it (yes, the regexes could be better, and the parse_url() call eliminated, but its late and this is a quick hack):

function ne_rbl_check($ip) {
   static $lists = array('');
   $ip = gethostbyname($ip);
   foreach ($lists as $bl) {
      $octets = explode('.', $ip);
      $octets = array_reverse($octets);
      $h = implode('.', $octets) . $bl;
      $x = gethostbyname($h);
      if ($h != $x) {
         return false;
   return true;
function ne_surbl_checks()
   $things = func_get_args();
   foreach ($things as $thing) {
      if (preg_match('/^\\d+\\.\\d+\\.\\d+\\.\\d+$/', $thing)) {
         if (!ne_rbl_check($thing)) return false;
      if (preg_match_all('~(http|https|ftp|news|gopher)://([^ ]+)~si',
            $thing, $m = array(), PREG_SET_ORDER)) {
         foreach ($m as $match) {
            $url = parse_url($match[0]);
            if (!ne_rbl_check($url['host'])) return false;
   return true;

These two functions implement RBL and SURBL checks. RBLs, as you probably already know, are real-time block lists; you can look up an IP address in a block list using DNS, and if you get a record back, that address is in the block list. The first of the two functions implements this, in a bit of a lame hackish way.

The second function implements content-based checks, commonly known as SURBL; the text is scanned for things that look like IP addresses or URLs; those IP addresses or host names are extracted from the content and then looked up in the RBL using the first function.

Why is this good? A comment spammer will typically want to inject a link to their site onto your blog, and you can be fairly sure that their site is listed in a good RBL. The RBL used in my sample above is an aggregation of the SBL and XBL lists which contain known spammers and known zombie/exploited machines, so it should do the job perfectly.

Now to hook it up to the blog; this snippet is taken from my trackback interface:

if (!ne_surbl_checks(get_ip(), $_REQUEST['excerpt'], $_REQUEST['url'], $_REQUEST['blog_name'])) {
   respond('you appear to be on SBL/XBL, or referring to content that is', 1);

get_ip() is a function to determine the IP address of the person submitting the page; I haven't included it here for the sake of brevity; it's fairly simple to code one, but keep in mind that it needs to be aware of http proxies. respond() returns an appropriate error message to the person making the trackback and exits the script.

And that's all there is to it; you can do similar things with your comments submission and pingback interfaces.


Scheduling tasks on win32 with PHP

The other product of last night was another win32 only extension, this time for manipulating scheduled tasks. Why do you need an extension? The reason is that Microsoft chose to expose the "mstask" API as non-automation compatible COM APIs; that means that you can't simply use the PHP COM extension (which is really "PHP-OLE") to work with it.

The win32scheduler extension provides 5 functions:

  • win32_scheduler_enum_tasks() - returns an array containing the names of the scheduled tasks that are present on the system.
  • win32_scheduler_run(string taskname) - requests that the system run a given task immediately. It does not wait for the task to complete.
  • win32_scheduler_get_task_info(string taskname) - returns information about a given task.
  • win32_scheduler_set_task_info(string taskname, array info [, bool new]) - updates or creates a new task.
  • win32_scheduler_delete_task(string taskname) - deletes a named task.

It's fairly self explanatory, although the details for the task info are a little weird. I'll document those for PHP at a later date, but if you're interested in working with it now, you'd do well to read the MSDN docs on the Task Scheduler; the structures and unions docs will help you to figure out the task info format. If you want to create a task, you'll find it helpful to var_dump() the info returned from an existing task; the set_task_info() function uses the same data format. Top tip: you need to supply a "Password" field and set it to the password for the user account you set in "RunAs".

This extension should also be showing up on the PHP 5 PECL snaps page in the next couple of hours.


Setting up MSDE with PHP

  • Download it and run it to extract it
  • Open up a command prompt
  • cd \\MSDERelA
  • setup.exe SQLSECURITY=1 SAPWD=yoursecretpassword
  • cd \\Program Files\\Microsoft SQL Server\\80\\Tools\\Binn
  • SVRNETCN.exe
    • - enable TCP
  • net start mssqlserver

php|tropics 2005


php|cruise was good, and this years offering from php|arch (php|tropics 2005) looks set to exceed it. I particularly enjoy a good conference; they're not just about learning new things, but also about getting together and sharing ideas, attendee:attendee, speaker:attendee and speaker:speaker.

I'm fortunate enough to be making two presentations, on the following topics:

PHP and Databases Grown-up: PDO

PHP 5.1 features a new data access layer, PHP Data Objects (PDO), that provides a clear, simple (but powerful) unified API for working with all our favourite databases. Features include prepared statements with bound parameters (for all databases, even those that don't natively support them), transactions, cursors, LOBs and flexible error handling. Join me in this talk to learn more about the future of database access in PHP.

Speaking of grown up, following my talk is Dan Scott from IBM on using DB2 with PHP (hopefully your audience will be bigger this time Dan :-)

PHP Streams: Lucky Dip

A roundup of a bunch of handy things you can do with streams in PHP 5. We'll look at time saving functions like get and put contents, as well as multiplexing clients/servers, user space wrappers and other streamy tricks. In short, a whole bunch of Streams tid-bits for your toolbox; let's get out of the fread($fp, filesize($filename)) age.

I very warmly encourage you to attend the conference; the pricing is pretty good (and keep in mind that it's an all inclusive resort--that includes alcoholic beverages and food). If your boss isn't interested, but you really are, why not make php|tropics your vacation destination for the year?

WinXP Desktop Shell Replacement

A little while back I mentioned some annoyances with virtual desktop software under windows. It occurred to me that the only sane way to implement virtual desktops is to do away with the explorer shell and use something else.

This is not a new idea: GeoShell, LiteStep and BB4win all try to do this kind of thing, with varying degrees of success. I tried to use each of these and found that they all have their rough edges that just made them unusable for me.

So I was frustrated. Motivated by frustration and curiosity, I wrote my own shell replacement for WinXP. It features low resource consumption and a low-clutter interface that I suppose is somewhat similar to the OSX dock, even though that wasn't my original intention.

screenshot full-size.

My shell, dubbed "WezDesk" for want of a better name (EvilDesk!?), implements the following features:

  • Quicklaunch icon bar
  • System Notification area (aka "Tray"), including tray bubbles
  • Clock with day/date
  • No classic taskbar, but "flashing" windows have their icons bounced to get your attention
  • Light-weight icon-free start menu
  • Kludge-free Workspace management; use up to 4 virtual desktops
  • icon-free desktop

If you feel like a change from explorer will also do you some good, then feel free to download and test-drive my latest offering.

Disclaimer : the software is provided as-is in binary form only with no warranty. I am not liable for any bad mojo, be it mental, physical or meta-physical, that arises from its use. By downloading it, you assert that you will not decompile or reverse engineer the software in any way, and that you will not re-distribute it to any third party in any form without my express consent. All rights reserved; All liabilities disclaimed.

Caveat Emptor : when switching desktops, some naughty apps (notably gaim and the MSDN help browser) occasionally get "warped". Restarting the app is one solution, not switching desktops is another. (Running miranda instead of gaim saved several MB of RAM at runtime, runs faster and has no weird interactions that I know of).

Caveat Emptor 2 : tray "bubbles" sometimes miss updates to their text content.

Despite these niggles, I've been happily using the current build for over a month, >15 hours per day and it's been a pleasure to use.

Download wezdesk.msi


Double click the .msi file to install. Note that installation is non-destructive; it simply installs the app into your start menu. You can then go into:

Start | Programs | Evil, as in Dr | Shell | Set Shell

to register it as your shell. You need to log out and log back in again to use it.

If you want to go back to explorer.exe, call up the start menu (right click on the desktop):

All Programs | Programs | Evil, as in Dr | Shell | Reset Shell

and log out and log back in again.

You'll also find the online docs available in the start menu; in there you'll find out about the various hotkeys available.