Phase.org

Posts by tag: zend

So who is Microsoft anyway?

2008-12-14 22:31:00
"Microsoft? What on earth do they want to have to do with PHP?", I was asked incredulously last night.
Well, apparently, quiet a lot, although calling it "The greatest love story as yet untold" may be going a bit far (and possibly even a little creepy?)

To many of us, Microsoft is still seen as the antithesis of the Open Source world, something due in large part to their own behaviour. Most developers who've been around long enough to recall the browser wars, the EU antitrust case, the battles Samba used to have to interoperate, frankly don't trust them. Indeed my own last significant interaction with them was when we were developing the Sender Policy Framework, and Microsoft wanted to leverage their own Intellectual Property into it and then require a "RAND-Z" licence on top of it - which would have crippled open-source adoption, and thereby the standard itself.

So yeah, I'm not really predisposed to liking Microsoft.

But that experience was several years ago, and the Microsoft Behemoth is starting to turn. Led internally by figures such as Hank Jannsen and (in the UK) Will Coleman (who apparently exists only on Twitter), there's a strong "If you can't beat 'em, join 'em" pro-open-source movement gathering steam.

Microsoft appear to have realised that when they try and beat open source technologies such as PHP, everyone loses. That gives them the choice of ignoring it and hoping it'll go away, or working with the PHP movement to try and make IIS a good choice of platform to run PHP on (previously it's been dog-slow and unstable) and MS-SQL a good database to pair with.

Fortunately, they've gone with this last option, and there's a significant and growing effort within MS to make this work well, as can be seen at their Open Source blog.

It was for this reason that I (and a number of other UK "PHP community leaders") was invited to a "Microsoft PHP Community Event" last week. They're trying to engage the community at its own level, which in this case meant a few talks, and quite a bit of Q&A, in the back room of a pub. This comprised a video presentation from Hank Jannsen, and talks from Will Coleman from the MS side together with Ivo Jansch and Scott MacVicar from the community side. As this was all done in a Pecha-Kucha (20/20) fashion it was all slightly hectic. The community asked for a lot, and Microsoft promised a lot, in terms of technical assistance, time, cash, and attitude change.

It's worth admitting that MS already do a far bit - technical assistance to the Samba project, financial aid to the Apache foundation, and technical improvements to Zend Core which have brought the speed of PHP on Windows/IIS servers to parity with that on Linux/Apache. The question is whether they can do enough both to convince the community, and to convince businesses to combine Open Source and commercial platforms.

It'll be worth watching, but they've got some work to do.


Special mention has to be given both to the food at the Windmill pub - Sausage and Mash as finger food? How about Fish, chips and mushy peas? - and to the goodie bags; Santa hats, Xbox 360 games, whisky, very small trees, and and crunchie bars ("To make the credit crunch fun!"). Well, Will's a nice guy, but sometimes he worries me.

Going beyond actions in Zend Framework MVC

2008-11-21 20:45:00
The basic model of Zend MVC is the use of Modules, Controllers and Actions. Each URI is translated via a set of specified or default routes to call a specific action, which, in the default behaviour selects and populates a view which is then automatically rendered.

This works well for any behaviour which is URI-specific, but doesn't work so well for controller-wide or site-wide behaviour, or behaviour repeated in multiple (but not all) actions.

These are handled in plugins and helpers, but precisely how to use those can be confusing (by which I mean, it took me a while to work out). There are multiple event-triggered functions that can be implemented to run at various times, as well as those which are called according to route, or manually.

The complexity further increases because Plugins, Action helpers and even Controllers can fire on events. Plugins have six possible event triggers, and controllers and helpers can fire on preDispatch and postDispatch.

There's a useful visual guide to those timings at http://surlandia.com/2008/11/03/zend-framework-plugins-action-helpers-and-controllers-life-cycle-during-dispatch/

As for particular use cases:

Plugins are registered with the front controller in the bootstrap file, and fire at any of the 6 triggers for all routes / actions.

Controller events (pre/postDispatch) fire at specific times when their own controller is routed, alongside the appropriate Action functions which tend to perform the bulk of the work.

Action helpers designed as pluggable functionality that can be registered and called as required (usually by Action functions), but can also "prepare" and "clean up" after themselves by means of their triggered functions.

The role of this post is only to clarify (partly for my own benefit) the above options and differences; for more detail, Matthew Weier O'Phinney has some excellent articles at Zend DevZone:
http://devzone.zend.com/article/3372-Front-Controller-Plugins-in-Zend-Framework for Plugins and
http://devzone.zend.com/article/3350-Action-Helpers-in-Zend-Framework for Action Helpers.

Using Zend_OpenId_Provider

2008-11-21 12:17:00
Zend Framework's Zend_OpenId_Consumer makes accepting OpenID logins on your site pretty easy, but its companion, Zend_OpenId_Provider is a little harder to get on with.

There's a few reasons for this:

1 - As per the philosophy of Zend Framework, you're given key parts of the tool, but have to fill in a lot yourself.

2 - There's a lot more data to manage and store for a Provider than a Consumer, and the OpenID system deliberately puts the complexity on the Provider side.

3 - The documentation of Zend_OpenId_Provider is, frankly, not too hot. To quote:
"Building OpenID servers is less usual tasks then building OpenID-enabled sites, so this manual don't try to cover all Zend_OpenId_Provider features as it was done for Zend_OpenId_Consumer."

The documentation is, unfortunately, written in somewhat stilted english, and the examples given are over-simplified and not altogether clear.

Now, there's no point simply ranting about this, as someone will quite reasonably request more detail...

So, given that ZF is a community effort, and that I've managed to work out enough of the code to get a basic provider running, here's a quick guide on how it seems to work:

As per the flowchart at http://framework.zend.com/manual/en/zend.openid.html#zend.openid.introduction.how, it's a multi-step process:

First, the user requests a login to the consumer site by provide an OpenID URI.
The consuming server checks the page at that URI for a server delegation metatag, and then contacts the server this identifies (optionally following a further delegation chain).

The providing server must accept a direct HTTP request from the consuming server and call:
$server = new Zend_OpenId_Provider; // Instantiate server with default settings
echo $server->handle(); // By default, look in $_GET for openID data and respond to it.

This can be done as for any other page so long as you only ouput the return value.

Unfortunately, this default behaviour will simply return an OpenID CANCEL command to the consumer, because:
- The Provider will call self::hasUser($id), which in turn calls Zend_OpenId_Provider_Storage->hasUser($id)
- The default storage mechanism has no users until configured (hence the hack in the first example in the docs)
- Failing to locate the user causes Zend_OpenId_Provider to decline the request.

So, we need to provide a form of storage that will respond 'true' for an ID we should be able to serve.

The very simplest way to do this is to subclass Zend_OpenId_Provider_Storage_File and pass that in to the provider class's constructor (it accepts any object inheriting from Zend_OpenId_Provider_Storage as a 4th parameter, but uses the file variant if none is provided).

The only function you'll need to override at this time is Zend_OpenId_Provider_Storage::hasUser($id). My personal quick hack was:

public function hasUser($id){
return ($id==='http://myuser.openid.server.com/');
}


Obviously for production you'll want to do something a bit smarter, but for now it's enough to give you the idea.
You could also try to use somthing like the documentation hack to register an id in the file storage, but I'd rather make ZF work my way.

So, if the ID is known (even if it has no relation to the current provider site visitor), the Provider will associatte with the Consumer in order to be able to confirm the identity securely. This association is stored by Zend_OpenId_Provider_Storage::addAssociation(), but for now I'm letting the Zend_OpenId_Provider_Storage_File handle this.

Once it's associated, the Provider will (I believe) see if it's aware of the owner of that identity being logged into itself (via a prior call to Zend_OpenId_Provider::login()). If so, it will move on to confirming that the user trusts the consuming site (ie, is happy to confirm their identity to it).
If the user is not logged in to the provider (NOT the same as being logged into the providing SITE), the user's browser will be directed to the provider's login page, as specified as the first parameter in the provider's constructor. Note that if the login URI is not provided to the constructor, a default URI is used as per the documentation.

This login page should verify the user's identity by whatever means the providing site already uses, then call a redirect to the trust page (the second constructor parameter). Note however that Zend_OpenId_Provider is written to expect that you log into itself directly (by username and password) and is written in a way that makes it hard to write the Zend_OpenId_Provider_Storage::checkUser function that needs to validate the username and password. Unusually for Zend Framework code, the encapsulation here is too weak, and developers will often need to replace or sidestep this particular bit of functionality.

Once the trust page is reached, the provider needs to verify that the user is happy for the consumer to know their identity. There are various options here; if you use the full built-in abilities of the provider, you may have previously told it "This site is always OK" or "This site is never OK". It should use that data (as stored by the Storage, IIRC) at this point if available, otherwise it will display the Trust page.

Note - there's a *lot* going on under the hood of the provider, and without testing every route I'm not exactly sure of program flow! For this guide, I'm covering the basic operation, and the principles, but for trust storage you'll have to experiment for now. It seems likely that if the user is already logged in to the Provider, and has designated the consuming site as "Trust Always", then Zend_OpenId_Provider will not try to display either the login or trust pages.

Finally, whatever method you use to verify trust, if you the user agrees to it, you then need to call
$server->respondToConsumer($_GET);
which will be the Provider's last act, confirming your identity and returning you to the consuming site.


To summarise the code required (we'll assume an MVC environment; this code isn't tested as-is):



class OpenIdServerController extends Zend_Controller_Action {
function init()
{
$this->_provider = new Zend_OpenId_Provider(
'/openid/server/login', // login path
'/openid/server/trust', // trust path
null, // default user session manager
new My_OpenId_Provider_Storage() // our tweaked storage class
);
}

function serverAction() //This is called first, by the consuming server
{
echo $this->_provider->handle(); // handle 'GET' params by default
exit; // Don't render views, etc
}

function loginAction() // The user is directed to this page if they're not logged in to Zend_OpenId_Provider
{
if(/* we can verify this user */) {
//optionally call $this->_provider->login() to maintain user identity on providing server
Zend_OpenId::redirect("/openid/server/trust", $_GET);
} else {
// Display login form and post back to this page
}
}

function trustAction() // The user is sent to this page after being logged in
{
if(/* we have permission to trust this consumer */) {
$this->_provider->respondToConsumer($_GET);
} else {
// Display a form asking whether to trust this consumer; post back to this page
}
}
}

Refer to the ZF manual for suggested forms.

Our hacked My_OpenId_Provider_Storage just looks like:
class My_OpenId_Provider_Storage extends Zend_OpenId_Provider_Storage_File
{
public function hasUser($id){
return ($id==='http://myuser.openid.server.com/');
}
}



NOTE that this process basically expects the user to log in, or be logged in, and to re-verify trust each time. Using the "Provider Sessions" is beyond the scope of this guide.

I might as well blog while I'm waiting

2008-08-22 11:56:00
to see if Zend Studio crashes again.

I used to be fairly happy with Zend Studio, but these days it seems to be featuring as one of the banes of my working life. As a developer it should be the program I spend most of my time using (and so needs to Just Work), and indeed on my own system at home (smallish codebase, local files & webserver) it does. Usually.

In the office, however, we have a much bigger codebase, shared mounts for sandboxes (as per the ongoing series on this blog), and an occasionally slow or patchy network. This gives Zend Studio (both 5.5.x and 6.0.x) a myriad of ways and reasons to fall over or just seize up. To be honest, I'm not sure Java's a great language for an app of this complexity, but for whatever reason it will frequently just stop dead, fail to open files, or just ignore all input.

So, to work out how to get around this and actually be able to edit my files (with code completion, debugging, code lookup and all those things which make vim Not An Option), I've been trying to debug my way around the problem.

Firstly, I've been trying to work out if it really is the network that's the issue. So, remove that from the equation: read the files from a samba mount with no network latency; in other words, from a local samba server.

As I've recently received a higher-spec machine at work, with parallels supplied, my first step was to create a small internal ubuntu server with a samba share to see what happened.

What happened was that I discovered that ubutu 8.10 server doesn't run under parallels, although it installs fine.

So, I switched to the Ubuntu JeOS distro instead, which does run. A few apt-get's later and I have a local samba share. I check out our codebase, point a new project at it in Studio 5.5.1, open a file deep in the class tree, and do some other work for a while.

Result: ZDE seizes up and can't do code clickthroughs or open files. Great. So it's not the network. (I'm working on the basis that it's not my new intel 8-core mac, either). Maybe the virtual machine's too slow? Check out to local drive, perform same test, same fail. Ok, so ZDE 5.5 needs to be dragged out into a quiet alley and shot. I've suspected that for a while.

So, chuck out 5.5; try 6.0.1 (which I've tended to avoid as the interface, menu and naming is completely confusing, and it still falls down). And it turns out that I can load, edit and clickthrough a local project if I use a local folder as a project (acheived, uninituitively enough, by starting a new PHP project, and overriding first the file location and then the verification dialogue (and finding that in the manual was fun)).

[As an impromptu aside; ZDE 6 is modal. Very modal. It loves nothing more than to throw up an "information" dialogue that prevents you from editing, saving, or quitting. Except possibly for jumping to the foreground when you're working in another app and it wants attention.]

So, yeah... I can edit locally. Unfortunately, my dev server is my local box (yes, I could set it up that way for myself, but the live server is Linux not OSX, and I'm not configuring local servers for the entire team) and I need to save my files to the dev box. The good news here is that ZDE has a myriad of Remote Systems support; the bad news is that they're utterly baffling. FTP only is easy enough to understand, but then there's 'Linux' (which, last time I looked, was not a network protocol), 'Windows' and Unix (ditto), Local (which didn't sound very remote), SSH only (which turns out to mean SFTP), and Telnet Only (Experimental) which just sounds like bad news.

'Linux', btw, turns out to mean some weird perl/java hybrid server that you have to install on a linux server. Personally, I'd rather steer clear...

Having decided that SFTP looked the best bet, I thought I'd give that a go. Fairly easy (despite the interface's best efforts to confuse matters); set up a server, browse, select a folder and right-click to Create Remote Project. Wait while it refreshes, wait a bit longer while the progress bad gets stuck near the end, and wait while runs out of Java Heap space and crashes with an "Insufficient Memory. This advises you to refer to the "Running Eclipse" section of the readme.txt file; a quick glance in there shows that Zend have removed that section, and indeed most of the rest of the file. Might be nice if they updated their code to reflect this?

A quick google later and I find this page, which tells me to burrow into the depths of ZendStudio.app and edit 'eclipse.ini'.

Of course, that wouldn't do for Zend; they had to rename the file ZendStudio.ini. So, edit that instead.

Setting max memory up from 256M to 1024M crashes ZendStudio at startup. Setting it to 512M or 768M means it gets stuck even longer at the end of the "Create Remote Project" progress bar before crashing.

So, ok, abandon SFTP for now - let's try setting it up as a local PHP project on the Samba share. Set name, set directory, hit "finish", and it hangs - fortunately, only briefly. We can now open and edit files... but as yet, no code clickthroughs; the "processing" bar's spinning at the bottom of Eclipse and it's "building PHP Project" and "building workspace". Experience suggests it may do this forever, so I'm going for a cup of tea.


As suspected, it's got stuck at 4% in the depths of the Zend Framework.


Now what to try?

Erm, force-quit Zend Studio, restart it, and watch it all miraculously work, apparently? Ok, that's a complete anti-climax; maybe the extra memory fixed it. I'll update if it fails again.

ZF, but not so's you'd know it.

2008-05-18 21:47:00
phase.org is now running (in part at least) on the Zend Framework, v 1.5, with a lightweight front controller.

As far as I know, this makes absolutely no difference to the end user, but I figured it was worth mentioning.

Archive