Sunday, March 23, 2008

How to make OpenID really rock (user signup process)

Robby finds himself asking why come I have 75 openids, and why can't I just transfer my details from site to site?

Well Robby, this is for you.


First, you need to grab XML_GRDDL. It's fairly stable at the moment, and a PEPR proposal.

For now, do a

pear install http://xmlgrddl.googlecode.com/files/XML_GRDDL-0.0.4.tgz

... but if it gets through PEPR, this will be easier.


Be warned, you'll need version of PHP 5.2.5+ unless you can compile php with a decent version of libxml / libxslt.

You also need the XSL extension.

Open up your favourite editor.

Paste in:

require_once 'XML/GRDDL.php';

/**
* Example: Fetch multiple URLs about a specific user
* and get useful information out.
*/
$urls = array();
$urls[0] = 'http://flickr.com/people/clockwerx/';
$urls[1] = 'http://www.linkedin.com/in/clockwerx';
$urls[2] = 'http://www.last.fm/user/CloCkWeRX/';
$urls[3] = 'http://clockwerx.blogspot.com/';

//For each URL, pretend it has these urls in <head profile="foo" />
//These look for hcard, hcalendar, etc.
$profiles[$urls[0]][] = 'http://www.w3.org/2002/12/cal/cardcaletc';
$profiles[$urls[1]][] = 'http://microformats.org/wiki/hresume-profile';
$profiles[$urls[1]][] = 'http://www.w3.org/2002/12/cal/cardcaletc';
$profiles[$urls[2]][] = 'http://www.w3.org/2002/12/cal/cardcaletc';
$profiles[$urls[3]][] = 'http://www.w3.org/2002/12/cal/cardcaletc';

//Set what kind of transformations we're interested in.


$options = XML_GRDDL::getDefaultOptions();
$options['quiet'] = true;

$grddl = XML_GRDDL::factory('xsl', $options);
$results = array();
foreach ($urls as $n => $url) {
$data = $grddl->fetch($url);

$data = $grddl->prettify($data);

$modified_data = $grddl->appendProfiles($data, $profiles[$url]);

$stylesheets = $grddl->inspect($modified_data, $url);

$rdf_xml = array();
foreach ($stylesheets as $stylesheet) {
$rdf_xml[] = $grddl->transform($stylesheet, $modified_data);
}

$results[$url] = array_reduce($rdf_xml, array($grddl, 'merge'));
}

print "We scuttered " . count($urls) . " urls and found these results\n";
foreach ($results as $url => $rdf_xml) {
print $url . "\n";

$sxe = simplexml_load_string($rdf_xml);
$sxe->registerXPathNamespace('vcard', 'http://www.w3.org/2006/vcard/ns#');
$sxe->registerXPathNamespace('ical', 'http://www.w3.org/2002/12/cal/icaltzd#');

print "We found the following pieces of information, choose which are yours:\n";
$xpaths = array();
$xpaths["Formatted name"] = '//vcard:fn';
$xpaths["First name"] = '//vcard:givenName';
$xpaths["Last name"] = '//vcard:familyName';
$xpaths["Email"] = '//vcard:email';
$xpaths["Homepage or URl"] = '//vcard:url';
$xpaths["Workplace name"] = '//vcard:organization-name';
$xpaths["Photo URL"] = '//vcard:photo';
$xpaths["Locality"] = '//vcard:locality';
$xpaths["Position/Title"] = '//vcard:title';

foreach ($xpaths as $name => $xpath) {
$results = $sxe->xpath($xpath);
if (empty($results)) {
continue;
}

print $name . ": ";
foreach ($results as $node) {
print trim((string)$node);
$attributes = $node->attributes(XML_GRDDL::RDF_NS);
if (!empty($attributes['resource'])) {
print trim((string)$attributes['resource']);
}
print "\n";
}
}
//print $rdf_xml . "\n\n";
print "\n";
}


Save it, run it.

You *should get*:

---------- PHP ----------
We scuttered 4 urls and found these results
http://flickr.com/people/clockwerx/
We found the following pieces of information, choose which are yours:
Formatted name: DanielO'Connor
First name: Daniel
Last name: O'Connor
Homepage or URl: http://clockwerx.blogspot.com/
Locality: Klemzig
Position/Title: Web Developer

http://www.linkedin.com/in/clockwerx
We found the following pieces of information, choose which are yours:
Formatted name: Daniel
O'Connor
Adelaide Institude of TAFE
PEAR member
LIXI Members member
First name: Daniel
Last name: O'Connor
Homepage or URl: http://http;//clockwerx.blogspot.com
http://www.valuationexchange.com.au
Workplace name: PEAR
Valuation Exchange
Fresh FM
Self-employed
Adelaide Institude of TAFE
PEAR member
LIXI Members member
Locality: Adelaide Area, Australia
Position/Title: Developer at Valuation Exchange
Contributer
Software Developer
Web Developer
Freelancer

http://www.last.fm/user/CloCkWeRX/
We found the following pieces of information, choose which are yours:
Formatted name: Daniel O'Connor
NoBloodForOil
Homepage or URl: http://clockwerx.blogspot.com
Photo URL: http://userserve-ak.last.fm/serve/160/682792.jpg
http://userserve-ak.last.fm/serve/50/690470.gif

http://clockwerx.blogspot.com/
We found the following pieces of information, choose which are yours:
Formatted name: Daniel O'Connor
Email: mailto:daniel.oconnor@gmail.com
Homepage or URL: http://clockwerx.blogspot.com/
xmpp:daniel.oconnor@gmail.com
Workplace name: Valuation Exchange


Output completed (30 sec consumed)


Now, how neat is that. You can grab any url which publishes microformats, grab out the hcards from it, grab the information from those, and viola! A pre-populated signup form.


Why is this neat?
* If an OpenID url has Microformats, bam! You can read it.
* If you are a bit more hardcore, you can hook up xOperator and a triplestore to this information.
* Or you could use it in Drupal.

There you have it, ladies and gents: semantic web in a box, with practical applications for user signup.

No comments: