Skip to content


PHP Recap/Redux

I've been pretty damned busy of late (we're in the late stages with going gold for our next Message Systems product release), but have managed to be involved in a couple of things PHPish, although I haven't had much time to follow up and talk about them.


I was invited to be a panelist at Microsoft's MIX conference for a discussion on the traditional pain points of getting PHP to run in a Windows environment and interoperating with ASP apps, and how Microsoft have taken a number of steps to help make the experience nicer, by improving the developer experience with IIS, shipping FastCGI support and working with PHP core developers to identify and tune some hotspots in PHP. The panel was pretty well attended given that it was one of the last sessions of the conference. You can find a recording of this session online here.

At MIX, the hot news was mostly Silverlight. It really demos very nicely and really does seem like a Flash killer, particularly because the tools are very nicely done. The really nice thing about Silverlight from my perspective is not so much the eye candy (sweet as it may be), as the Dynamic Language Runtime (DLR). The DLR allows you to run a subset of "dot-net" on the client side (both Windows and Mac), including scripting languages like Ruby and Python. This allows for some interesting possibilities, from something as basic as being able to use the same languages on both the client and the server side (very compelling from a maintenance perspective), to being able to use multiple languages (and libraries written in those languages) and call between them in your client side app.

This stuff isn't really all that new (you've been able to do some of that with COM compatible scripting interfaces for years--there's also a PHPScript implementation for the brave), but what's exciting is that it is bundled up into a runtime that has eye candy and support for two common OS platforms. The trick is in the eye-candy; that feature will wow people and cause a more rapid adoption of Silverlight than if it was just the DLR on its own.

Speaking of the DLR, Andi Gutmans and myself made it to the excellent Just Glue IT! talk presented by Jim Hugunin and John Lam (I love that URL!), on Python and Ruby (and more) in the DLR on Silverlight. It was very informative as well as humorous and with some nice live demos. You might be wondering if we're interested in PHP running on the DLR. I would love to see it there, even if it was just a subset of the PHP that we know and love. Perhaps the Phalanger project might shift in that direction?

From an organizational point of view, MIX, the conference, was very well put together. Some nice touches included: a speaker room equipped with snacks (ranging from power/protein bars and fruit to chips and candy), soda (which is typically very difficult to find at a conference without having to walk out of the conference area and paying exorbitant prices. This is very important for me, as coffee is a migraine trigger.), and what really clinched it for me: red bull (including sugar free).

Another nice touch was a double-sided laminated name tag--those things have a habit of flipping around so that you can't read them and find out who you're talking to. There was also a "sandbox" for you to bail out from the conference and sit down and play with the new technologies (they provided a number of machines for that purpose) or just sit down and talk. Minus points for not having enough (any?) power strips in the sessions themselves though; it made it difficult to get some work done while absorbing a session.


It felt like php|tek was the first true PHP conference I've done this year (and that might even be true--I didn't bother to look back and check), so I was looking forward to being there, and also to see a bit more of Chicago, although I was a little disappointed to find that the conference was set in the "airport town", just far enough away from the real city to make visiting it a hard prospect. Such is life.

I think the php|architect folks did a fine job considering that the hotel threw a few spanners (or wrenches for you American folks) into the works, pushing a number of people (myself included) out of the conference hotel proper and into its more plain cousin a block or two down the street. I particularly wanted to attend Jeff Moore's talk on maintainable code but there was no room--people literally fell out of the session when I opened the door to get in there.

It was good to catch up with people again (and slightly weird to meet people that I'd seen a couple of weeks earlier at MIX--it's a bit surreal to be jumping timezones and locations and still see the same people), and to meet some more PHPWomen face-to-face. We had fun in the PHP trivia competition, and some of us were roped in to doing a podcast which came out surprisingly coherent despite the amount of alcohol in the room (I suspect that's because it was largely consumed by one of the Facebook guys ;-)

As someone who's been doing these conferences for a few years now, it's interesting to see the increasing number of MacBook laptops in use. I didn't count everybody's laptop, but the areas I frequented during the conference appeared to have MacBooks in the majority.

One of these conferences, I'll make it to one of Joe Stagner's talks and be there for the whole thing--I've tried to make that happen for at least the last 4 that I've been to, but it hasn't managed to work out how I've planned it, so far.

php|tek, here I come

I'll be heading out for Chicago in a little while to attend php|tek, where I'll be giving my "pdo" and "mail" (a.k.a: "not pdo") talks.

I should be getting in to the hotel sometime around 7:30pm local time.

I've been really busy recently, so I haven't yet had a chance to figure out which other sessions I'll attend, but I do know that I'm really looking forward to re-sync'ing with everybody.

We're recruiting again, and I'm looking for both C and PHP folks to join my team at OmniTI/MessageSystems, so if you're going to be there and are interested, please make a point of finding me--I'd love to hear from you.

See you there :)

Soliciting questions for PHP and panel at MIX

As I mentioned previously, I'll be at MIX this year on a panel discussing ASP and PHP interoperability, along with Jesse Liberty, Bill Staples, Joe Stagner and Brian Goldfarb.

I've been told that MIX has sold out and that there is a lot of interest in our slot, so I'm sure we'll have plenty to talk about, but I'm looking for questions to break the ice and get things rolling.

If you have any questions, comments or other insights on PHP running on Windows, or on getting PHP apps working together with apps, please comment on this blog post, and I'll try to work them into the panel, and to feed back the results of the discussion here on my blog.

If for some reason your comment doesn't go through, or if you prefer email, you can also mail them to me at

I'll be at MIX'07

I've been invited to participate in a panel at Microsoft's MIX conference this year. The panel is entitled "Can't ASP.NET and PHP just get along?" and is to be a "spirited but friendly" discussion on PHP and interop.

For those folks clicking through from the MIX site, you might be wondering who I am and why I'm on the panel... I've been partly responsible for development of the PHP core and primarily responsible for a lot of the Windows specific portions of PHP. I work for OmniTI, a world respected internet technologies consultancy.

I'm looking forward to MIX, partly because I've heard that it's a lot of fun, and partly because it will a great opportunity to meet with a different crowd--the conferences that I usually attend have attendees that are largely LAMP focused, so the Windows platform focus will be an interesting change. I'm hoping to gain some insight into what people perceive as short-comings in PHP on Windows, and feeding those back into PHP.

If you see me there, stop me and say hi!

Portable umem released via OmniTI Labs

We've migrated our port of Solaris umem from SourceForge to OmniTI Labs, and have finally gotten around to making a source release.

You can find the project page here, which includes a link to the downloadable source.

The tarball will build you libumem and libumem_malloc. The latter version can be used as an LD_PRELOAD to replace malloc for a target process, which is useful for debugging. The former is more useful when deliberately linked into an app that wants to take advantage of the slab allocator APIs directly.

I'm interested to see if using this in PHP will lead to performance gains, but currently lack the time to do any benchmarking. I doubt that performance will suddenly improve just by preloading libumem_malloc, but there might be a gain if the zend engine allocator were tied into libumem.

Perhaps someone reading this blog entry does have the time to investigate and could post the results?

OmniTI does OpenSource: OmniTI Labs

Earlier this week, we announced OmniTI Labs, a home for various pieces of useful technology that we've worked on, either as part of working on projects for clients, internal products or just for fun.

Alexandria is a library of PHP code that will continue to grow as we find more time to drop components into it. Right now there's not too much stuff in there, but the main pieces that are likely to be of immediate use are a PHP smtp_injector extension and a supporting PHP 5 class that should prove useful to folks that generate mailings from PHP. You can read more about those in the documentation.

I want to stress that Alexandria is not a framework. Each piece is relatively self contained and tries to avoid imposing a particular programming paradigm on the apps that use it.

Labs contains more than just a PHP library; we have a number of other projects, and more will make appearances over time.


(See also what Theo says about Labs and what Laura says about Labs)

PHP Meetup @ OmniTI HQ in Baltimore/DC area

I've been meaning to blog about this for a while, but haven't found the time until now.

This Monday 5th March, join us for the Columbia PHP Meetup.

OmniTI are providing the venue, PHP experts and pizza. This first meetup will have a number of lightning talks and provide the opportunity to exchange ideas and talk about code, architecture, innovation, and open source in general. Anyone interested in PHP is welcome!

Please RSVP via the meetup link. digg crossed with social networking it's kinda fun: you sign in with your OpenID and make claims about things (doesn't matter what) and vote on those claims. You can also give credit to other people, join and create groups and record contacts and relationships.

Sounds pretty standard, but what I find interesting is that there are a set of APIs for querying group membership. This could potentially allow an application to restrict access to an invitation-only group defined on jyte, and then only people who are members of those groups will be allowed through.

Another interesting area is the upcoming credit API; it will be possible to query the overall credit score of an identity. I'm wondering if a high enough credit score will be acceptable as "proof enough" that a user is not a bot, and that we could then remove the captcha step for those users.

It will be interesting to see where these concepts go as the year progresses.

OpenID (and TypeKey) using native OpenSSL functions in PHP

Update: fixed a flaw in my implementation

I may have hinted at this a couple of times before, but now I'm actually saying something useful about it... I have a patch (php-openid.diff, for PHP 5, might also apply to PHP 4) for the openssl extension that makes it easier to build OpenID and TypeKey authentication support into your PHP apps.

I don't have a canned solution for you to deploy, but I can give you some pointers on how to use these bits. I'm assuming that you know a bit about how OpenID works.

This worked for me in my tests; it's not necessarily the most optimal way to do it, but it highlights how it works.

Thanks to the folks at JanRain, there was a flaw in my implementation that is now fixed.


Association allows you to generate a relationship with an OpenID server by generating and exchanging keys. It has nothing to do with an authentication request per-se; the result of the request can be used to authenticate a user later (and other users of that same identity server). The results of the association should be cached.

If you haven't already associated with an OpenID server, you'll want to do something like the following:

  // convert openssl unsigned big endian into signed two's complement
  // notation
  function btowc($str) {
    if (ord($str[0]) > 127) {
      return "\\x00" . $str;
    return $str;
  $assoc = array();
  $crypto = array();
  $dh = openssl_dh_generate_key(OPENID_P_VALUE, '2');
  foreach (openssl_dh_get_params($dh) as $n => $v) {
    $crypto[$n] = openssl_bignum_to_string($v, 10);
  $params = array(
     'openid.mode' => 'associate',
     'openid.assoc_type' => 'HMAC-SHA1',
     'openid.session_type' => 'DH-SHA1',
     'openid.dh_modulus' => base64_encode(
     'openid.dh_gen' => base64_encode(
     'openid.dh_consumer_public' => base64_encode(btwoc(
  $r = perform_openid_rpc($server, $params); // talk to server
  if ($r['session_type'] == 'DH-SHA1') {
    $s_pub = openssl_bignum_from_bin(
    $dh_sec = openssl_dh_compute_key($dh, $s_pub);
    if ($dh_sec === false) {
      do {
        $err = openssl_error_string();
        if ($err === false) {
        echo "$err<br>\\n";
      } while (true);
    $sh_sec = sha1($dh_sec, true);
    $enc_mac = base64_decode($r['enc_mac_key']);
    $secret = $enc_mac ^ $sh_sec;
    $assoc['secret'] = $secret;
    $assoc['handle']  = $r['assoc_handle'];
    $assoc['assoc_type'] = $r['assoc_type'];
    $assoc['expires'] = time() + $r['expires_in'];
  } else {
    $assoc = false;

Performing Authentication

Authentication is browser based; the user enters their URL into your site, and you then redirect to their OpenID server with a sprinkle of magic sauce in the get parameters. Here's how you create the sauce:

  // $identifier is the URL they gave to you
  // $server is the server you discovered
  // $delegate is the identity you discovered
  // $returnURL is your auth endpoint to receive the results
  $x = parse_url($server);
  $params = array();
  if (isset($x['query'])) {
    foreach (explode('&', $x['query']) as $param) {
      list($k, $v) = explode('=', $param, 2);
      $params[urldecode($k)] = urldecode($v);
  // get assoc details from cache, or associate now.
  $assoc = $this->associate($server);
  $params['openid.mode'] = 'checkid_immediate';
  $params['openid.identity'] = $delegate;
  $params['openid.return_to'] = $returnURL;
  $params['openid.trust_root'] = YOUR_TRUST_ROOT_URL;
  $params['openid.sreg.required'] = 'nickname,email';
  if ($assoc !== false) {
    $params['openid.assoc_handle'] = $assoc['handle'];
  $x['query'] = http_build_query($params);
  // you can now assemble $x into a URL and redirect the user there

Once the user has authenticated against their ID server, they'll be redirected back to your $returnURL:

    $assoc = $this->associate($args['srv']);
    $token_contents = '';
    /* note well: the name in the token_contents hash is the
     * name without any prefix.
     * This nuance can keep you occupied for hours. */
    foreach (explode(',', $_GET['openid_signed']) as $name) {
      $token_contents .= "$name:" . $_GET["openid_" . str_replace('.', '_', $name)] . "\\n";
    $x = hash_hmac('sha1', $token_contents, $assoc['secret'], true);
    $hash = base64_encode($x);
    if ($hash === $_GET['openid_sig']) {
      // Authenticated
      return true;
    /* not valid for whatever reason; we need to do a dumb mode check */
    $params = array();
    $signed = explode(',', $_GET['openid_signed']);
    $signed = array_merge($signed, array('assoc_handle', 'sig', 'signed', 'invalidate_handle'));
    foreach ($signed as $name) {
      $k = "openid_" . str_replace('.', '_', $name);
      if (array_key_exists($k, $_GET)) {
        $params["openid.$name"] = $_GET[$k];
    $server = $args['srv'];
    /* broken spec.  You need to set openid.mode to
     * check_authentication to get it to do the auth checks.
     * But, it needs openid.mode to be id_res for the signature to work.
    $params['openid.mode'] = 'check_authentication';
    $res = perform_openid_rpc($server, $params);
    if (isset($res['invalidate_handle'])) {
      if ($res['invalidate_handle'] === $assoc['handle']) {
        /* remove association */
        $this->associate($server, true);
    return $res['is_valid'] === 'true';

Didn't he also mention TypeKey?

Yeah, here's how to validate the signature you get when your user is redirected back from TypeKey:

    $keydata = array();
    $regkeys = cache::httpGet('', 24*60*60);
    if ($regkeys === false) {
    foreach (explode(' ', $regkeys) as $pair) {
      list($k, $v) = explode('=', trim($pair));
      $keydata[$k] = $v;
    $sig = str_replace(' ', '+', $_GET['sig']);
    $email = $_GET['email'];
    $name = $_GET['name'];
    $nick = $_GET['nick'];
    $ts = $_GET['ts'];
    $msg = "$email::$name::$nick::$ts::" . TYPEKEY_TOKEN;
    if (time() - $ts > 300) {
      die("possible replay");
    list($r_sig, $s_sig) = explode(':', $sig, 2);
    $r_sig = base64_decode($r_sig);
    $s_sig = base64_decode($s_sig);
    $valid = openssl_dsa_verify(sha1($msg, true),
                                $keydata['p'], $keydata['q'],
                                $keydata['g'], $keydata['pub_key']);