Skip to content


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']);

Evildesk 0.9.0 released

I uploaded release 0.9.0 of EvilDesk tonight. I realized that I hadn't made a release in over a year, so I tidied up a few bits and pieces and uploaded it. Feel free to review the changelog if you're curious.

Highlights include an improved dock style toolbar, a launcher plugin (type the name of a program or document to find it and run it, instead of poking around the start menu), simpler configuration of the toolbar positioning, translations for German and French, less bugs and support for 64-bit Windows.


2006 from Wez's perspective

Here's 2006 from my point of view. I did tinker a bit with the appearance of my blog, but that's not really a high point of the year for me. My year went a bit like this:

I started the year with a couple of EvilDesk releases, which in turn generated some snarky feedback from a couple of people in the PHP community, cooling my drive for working on PHP. Work and family pressures didn't help to restore my earlier level of PHP activity, and to be honest, some words and actions in the PHP community over the year didn't really help either.

MessageLabs chose us to provide their MTA infrastructure, which saw me back in the UK a couple of times at the start of the year while we worked together to plan part of the architecture.

I ported Solaris' memory manager (umem) to the "other" platforms (linux, windows and bsdish systems).

My older brother suffered a set-back this year, and I wish I could have helped him out a lot more than I did.

I started to test-drive google calendar, but that petered out because I can't put company confidential information in there. It's a shame, because it works well.

I finally got some of my writings published in a book, although not an entire book of my own.

I spoke at MySQLUC, OSCON, php|works and zendcon and attended the first MS web dev summit. Memorable moments around these events include being stuck in the seedier part of Phoenix for a night on the way to MySQLUC (not a fond memory to be sure!), awful karaoke at the Sun party @OSCON, excellent home-made sushi and xbox 360 on a 120" screen at a friends home in Seattle on the way back from OSCON, a really good British style pub in Toronto during php|works, reasonable karaoke at zendcon, Andrei's birthday party after zendcon and meeting Don Box at the MS web dev summit.

Our 4 year old son Xander started at pre-school and is doing well.

The death of my faithful toshiba m30 saw me adopt an intel based macbook, partly for the native unix environment and partly to force me to learn about the oddities of its runtime linker. I still have complaints about the way certain things work, but on the whole I am a happy user, made happier by Parallels because I still need Windows based software.

OmniTI has grown a decent amount this year, and we moved premises and now have two business units--OmniTI the Computer Consulting company and Message Systems the messaging company; both arms of the company have done well this year and are set to continue doing so in the future. Work continues to be fun, interesting and challenging, with great people on staff (that's all of them, not just the "internet celebrities").

I've been the architect of several large pieces of infrastructure for Ecelerity this year, one of which is in the realm of meta-meta programming (gives your brain a workout, guaranteed!). I'm looking forward to seeing the fruits of this labor in 2007, and to getting around to work on some more of the juicy ideas we continue to have for expanding and improving things.

What about PHP? I've been working on a unicode enabled version of PDO for the preview release of PHP 6. This should be completed soon, and I look forward to continued improvements in the PDO drivers and, in particular, the OCI driver which is long overdue some TLC. I've also been toying with something OSX specific for PHP that just isn't close to ready yet; maybe that will be something I can share in the first quarter of 2007.

Here's to a prosperous 2007!