Month: September 2007

Gettin’ SOAPy with PHP5

Recently, with our company’s update to PHP5 (yeah yeah, I know) we were looking to replace the software we use on our web service to handle real-time payments and customer lookups. Since we’ve been running PHP4, our natural choice was the NuSOAP framework. It gave us a (relatively) simple way to create the service and was easy to use. Unfortunately, with the move to PHP5, we couldn’t really use it anymore – and yes, I’ve seen the “change this line to this” fix for it but that kind of stuff makes me nervous. So, I decided that using PHP5’s SOAP extension was the way to go. Thankfully, it’s been pretty smooth sailing so far, and I thought I’d share some of it to maybe help anyone else out there looking to do something similar.

First off, my goal for creating this new service was to make it as flexible as possible. I wanted to make the main server portion of it smart enough to call what was needed to make the request without having to load the functionality for everything into each server request. The general idea, then, is to have the main server assigned to the SOAP object that dynamically loads in a class for that type of request. Thankfully, PHP5 has some features that make this pretty simple.

Here’s some sample code for the server portion:

[php]
header(“Content-Type: text/xml”);

function __autoload($class){
$path=’/path/to/webservice/libs/’.$class;
if(is_file($path)){ include_once($path); }
}

class MyServer {

var $_valid = null;
var $_action = null;
var $_msg = null;
var $_pars = array();

function __construct($msg){
$this->_msg=$msg;
}
function __parse($msg,$args){
$dom = DOMDocument::loadXML($msg);
$xpath = new DOMXPath($dom);
$result = $xpath->query(“//SOAP-ENV:Envelope/SOAP-ENV:Body/*”);
foreach($result->item(0)->childNodes as $key => $value){
$this->_action = $value->parentNode->tagName;
$this->_pars[$value->tagName] = $args[$key];
}
unset($dom,$xpath,$result);
}
function __call($func,$args){
$obj = new $func($args,$this->_msg);
if(isset($obj->xsd_type)){
switch($obj->xsd_type){
case ‘array’: return new SoapVar($obj->data,SOAP_ENC_OBJECT,$obj->type); break;
case ‘string’: return new SoapVar($obj->data,XSD_STRING,$obj->type); break;
case ‘xml’: return new SoapVar($obj->data,XSD_ANYXML,$obj->type); break;
default:
return new SoapVar($obj->data,SOAP_ENC_OBJECT,$obj->type);
}
}else{ return new SoapVar($obj->data,SOAP_ENC_OBJECT,$obj->type); }
}

}

//Now we start up our server…
$input = file_get_contents(“php://input”);
$server = new SoapServer(‘http://www.example.com/my.wsdl’);
$server->setClass(“MyServer”,$input);
$server->handle($input);
[/php]

It’s not the simplest script, but I wanted to show you all of the parts first and then break it down into more manageable chunks. Let’s start where the flow starts – the bottom of the script. This chunk of code allows the script to intercept the incoming request and assigns the class to handle it. Our MyServer class is where the real fun starts.

Moving along the flow line, we hit the constructor of the class. The only thing we do here is assign the incoming message to the _msg property of the class. This is so that later, when we need to parse it, we can get at it. Some of the magic with the SOAP PHP functionality happens next – it tries to look for a function named the same as the request type (so if the SOAPAction is “getFoo” it looks for the “function getFoo()” in the class). I went a different route here, though – I didn’t define any of the methods it would need in the server class itself. Instead, I made use of the __call magic function to handle things.

When the __call catches the action, it gets the function name that was called and the arguments it was called with. Unfortunately, this argument array has numeric keys which made it hard for me to tell what the real order of the inputs was (they could have the “acct_num” in front of “last_name” in one request and after it in another). More on that later, though. Right inside the __call method, you’ll see the key to it all – the dynamic call to an object, based on the type of request, being created and called with the arguments and a copy of the message. Since the classes aren’t included yet – we only wanted what we needed – the __autoload kicks in and pulls in the file.

This brings us to one of our “action classes” – here’s an example:
[php]
class MyTestRequest extends MyServer {
function __construct($args=null,$msg){
parent::__parse($msg,$args);

$arr=array(‘testing’=>’1,2,3′);

$this->type=’Account’;
$this->data=$arr;
}
}
[/php]

This is the simplest kind of request we can have – it lives off in the directory (defined in the __autoload of the server) as a file called MyTestRequest.php. All of the action happens in the constructor and other functionality should probably be relegated to other methods on the class. Our server class calls this constructor with the two parameters which are then passed back to a function in the server class, __parse. This does something that’s a bit optional, but I wanted it to be sure I knew which parameter was which when they were passing it it. As it stood, I only had numeric indexes on the arguments array and was left to guess which order they were in (not good). To remedy the situation, I pass it off to this function for processing.

The __parse function loads the message into a DOM document and, using an XPath query, finds the node for the action inside the SOAP:BODY. Each of its child nodes are then pulled out and the tag names are assigned to the _pars array and the action to the _action property. With these set, we can come back and, instead of just assuming that $args[0] is the account number, we can know for a fact that $this->_pars[‘acct_num’] is the right information.

The $arr inside of the __construct in MyTestRequest is then passed back out to the script via the $this->data property (shared between the parent and child since it extends it) and the type for the response (from the WSDL) in $this->type.

Hopping back over to the MyServer class, we’re back inside the __call still and there’s just one last thing to do – echo out the response in a SOAP-friendly way. That’s what all of the SoapVar calls are for. The switch() call looks at an optional $this->type property and, of set, tries to match the output with the right data format. In our example, though, it just falls down to the “else” and calls it as an object.

And, voila – it’s done. The output is a formatted SOAP response!

Webmaster Jam Session 2007

Yeah, so it’s a little late to mention it (the conference starts bright and early tomorrow morning), but I’m going to be hanging out the next two days at this year’s Webmaster Jam Session here in Dallas. Looks like a good lineup this year – I’d wanted to go last year, but scheduling conflicts didn’t allow it.

Being all PHP, all the time is a nice place to be, but it’s good to branch out and get a little bit of the other side of things. My inner designer is practically jumping for joy.

Webmaster Jam Session 2007 at the Adam’s Mark Hotel in Dallas, Tx

Eclipse/Zend Launch PDT (PHP Development Tools) v 1.0

The Eclipse Foundation, in cooperation with Zend, have officially launched the first stable (1.0) version of a project that’s been in development for a few years now – the PDT (PHP Development Tools) project.

The PDT project is based around the already wildly popular Eclipse platform, making it not only one of the most powerful development platforms for PHP developers, but also one of the most flexible. If there’s something you see lacking in what PDT has to offer, fixing it is as simple as one of two steps – you can either go out to the wide repository of Eclipse projects out there and find the components you might need or step up to the plate and create your own component and share it with the rest of the community. With a list of around 1,400 Eclipse plugins, though, you probably won’t be hurting for any bit of functionality you might need.

I had a chance to talk on a conference call the other day to discuss the project and what sort of impact they (Eclipse and Zend) thought it would have on not just the PHP community but the entire Open Source community as whole. The reasoning is pretty simple – the PDT project was created with one goal in mind – to take the foundation that the Eclipse project already has and make it into something that PHP developers all over the world can look to as a strong, flexible IDE option wen they’re packing their editor of choice.

Even if you’ve already become set in your ways, you should definitely check out the features that this new version of PDT has to offer. It takes bits and pieces from other IDEs out there and packages them all together into an easy to use package including:

  • Handy code editing features like syntax highlighting, code folding (a personal favorite) and little hints to remind you the details of a function you’re adding
  • the addition of both a Project and PHP Explorer views that work with introspection to update dynamically as things are added to the project (add a class to your file and it’s reflexed in the Explorer)
  • Debugging support – this includes support for their debugger (Zend’s) and XDebug support
  • and, of course, the Eclipse framework itself allowing developers to make, well, whatever they want to sit on top of PDT

That’s where a lot of the real power of this project comes in – the extensibility. Other IDEs (with the exception of things like Komodo) don’t have much in the way of user-defined plugins, at least not to this level. The Eclipse platform was created to be as flexible as possible. As a result anything about the project can be changed, added, removed, duplicated…well, you get the idea.

According to their latest press release, the PDT project has already seen over 300,000 downloads – and that’s not counting what they’ll get when the announcement of this stable version hits the web.

Check it out and grab the download of this latest version. It might not be exactly what you’re looking for but that’s the beauty of it – you have the power to mold it into just the right tool for you.

ZendCon ’07 and the Revenge of the PHPDev T-Shirts

Just thought I’d drop a note to all that’ll be attending this year’s Zend/PHP Conference & Expo – the t-shirts that I made up last year (see here for what they look like) will be making an appearance this year as well.

I’m not sure exactly how many of the shirts I have left (I’ll update this post later on with the numbers) but I’ll be bringing them along and will have them with me during the conference. I think they’re mostly mediums and extra-larges.

So, if you’re attending and would like a free t-shirt (yes, that’s right – free! woo!) from PHPDeveloper.org, be sure to track me down and harass me. I’ll be wearing one the first day so I should be pretty easy to spot.

UPDATE: I checked out the t-shirt supply I have left – 8 mediums, 5 larges and 7 extra-larges. If you’d like me to save one (like Wez has already posted his preference) add a comment here and I’ll set one aside. It’ll be first come first serve after that, though – so if you’re wanting one, add a note or find me fast 🙂

Fun is…

…finally getting to the vacation spot (after two plane trips and a 1 1/2 hour layover – did I mention with a 3 month old) only to check your work email “real quick” only to discover that the SSL cert for your companies website expired the morning you left.

Nothing like 50 panicked emails sitting in your inbox from customers and fellow employees alike to make you feel bad for leaving on a work day – heh.