Taking PHP Seriously

When it comes to programming languages I love to work in, Ruby, Coffeescript, and JavaScript are my tools of choice. My introduction to server-side web programming came from PHP, and I still like to hack on WordPress stuff in PHP, but I have had my fair share of frustrations with the language. Even with those frustrations, there are some things I still love about PHP.

I recently watched this presentation titled Taking PHP Seriously by Keith Adams from Facebook. Keith makes some great points and it actually makes me want to build something with PHP again.

SOAP Server with PHP5 – part3: the glue code

Part 2 of this series of blog posts focused on creating your wsdl. Now we will move on to the “glue code” and putting it all together. In part 2, I created a wsdl that defined the application programming interface (API) for an inventory web service. We defined one simple function called getItemCount which takes a upc in the form of a string as a parameter and returns the count in the form of an integer.

Let’s go ahead and code up the function:

<?php //inventory_functions.php
function getItemCount($upc){
//in reality, this data would be coming from a database
$items = array('12345'=>5,'19283'=>100,'23489'=>234);
return $items[$upc];
}
?>

It is important to test all of your functions outside the scope of your web service to iron out all of the bugs, otherwise, you’ll be dealing with some nasty debugging as soon as you connect this with the SOAP glue code. I like to keep the functions or classes that are connected to the web service separated from the glue code, unlike the php soap extension tutorial does. That way I can test it more easily.

The glue code

The glue code is responsible for handling incoming soap requests and returning valid soap xml. It takes the wsdl service definition and it connects it with your function or class. Here’s what it looks like:

<?php //server.php
require 'inventory_functions.php';
ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache
$server = new SoapServer("inventory.wsdl");
$server->addFunction("getItemCount");
$server->handle();
?>

The inventory_functions.php contains my getItemCount function. It is important that the function has been included (or required) before the $server->addFunction("functionName"); is called. Also, make sure that you have no white space before or after your opening and closing php tags.

Once you know that your wsdl is correct, and you won’t be changing it, remove the ini_set function from the glue code.

Important: Make sure your wsdl’s service block is pointing to the http accessible url of the glue code (see part 2 for details).

Testing the service

Now is the moment of truth, to see if your service works like you had anticipated. Simply create a script like this one:

<?php //client-test.php
ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache
$client = new SoapClient("http://[path to the service]/inventory.wsdl");
$return = $client->getItemCount('12345');
print_r($return);
?>

Substitute the [path to the service] with your url path, and execute the script. Hopefully, you should be seing the results that you expected.

Tutorial Files

For all the files that have been discussed in this tutorial, download the tutorial.zip

Sorry, this post has received a barrage of spam. I had to shut down comments. Try one of the other posts in this series.

SOAP Server with PHP5 – part 2: fun with wsdl

Part 1 of this series of blog posts should help you get started with setting up a simple soap server with one function, a stockquote request. It points you to the soap extension tutorial on the Zend Developer Zone.

In this part, I’m going to explain some of the different parts of the wsdl so that the wsdl isn’t so intimidating. So let’s begin by examining the wsdl found on the tutorial here.

I’m going to start from the bottom of the wsdl and work my way to the top.

The ‘service’ block

<service name='StockQuoteService'>
<port name='StockQuotePort' binding='StockQuoteBinding'>
<soap:address location='http://[insert real path here]/server1.php'/>
</port>
</service>

This ‘service’ block of the wsdl gives some basic definitions for your soap server. You’ll want to pick a service name and stay consistent throughout the wsdl. This example uses ‘StockQuote’ for all its naming but you could use something like ‘Weather’ or ‘Inventory.’ Just stay consistent. So, if you were to make an ‘Inventory’ service, your service block of the wsdl would look something like this:

<service name='InventoryService'>
<port name='InventoryPort' binding='InventoryBinding'>
<soap:address location='http://[insert real path here]/server1.php'/>
</port>
</service>

The port name and binding connect this block with the other parts of the wsdl, so just keep to your naming convention and you’ll be fine.

The address location points to the location of what I call the “glue code” or the php script that glues your function to the soap extensions server libraries. The glue code is what handles all of your xml messages and passes the right parameters to your functions.

The ‘binding’ block

<binding name='StockQuoteBinding' type='tns:StockQuotePortType'>
<soap:binding style='rpc'
transport='http://schemas.xmlsoap.org/soap/http'/>
<operation name='getQuote'>
<soap:operation soapAction='urn:xmethods-delayed-quotes#getQuote'/>
<input>
<soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</input>
<output>
<soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</output>
</operation>
</binding>

The ‘binding’ block has a lot of stuff in it, but most of it is just defining how the soap client and server will communicate. There is very little code here that you’ll need to change to fit your service. There are 4 parts that you’ll need to modify in order to map the service to the function that you wish to put in the service. Those parts have been bolded and italicized above. Change the binding name and type, the operation functionName and the #functionName at the end of the soap:operation.

So, if we were to modify this for our inventory example we might change the getQuote to getItemCount and our binding block would be as follows:

<binding name='InventoryBinding' type='tns:InventoryPortType'>
<soap:binding style='rpc'
transport='http://schemas.xmlsoap.org/soap/http'/>
<operation name='getItemCount'>
<soap:operation soapAction='urn:xmethods-delayed-quotes#getItemCount'/>
<input>
<soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</input>
<output>
<soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</output>
</operation>
</binding>

If you were to add another function to your service, you would just copy the ‘operation’ section of this block, and paste it right below, and change the function name. Pretty simple.

The ‘portType’ block

<portType name='StockQuotePortType'>
<operation name='getQuote'>
<input message='tns:getQuoteRequest'/>
<output message='tns:getQuoteResponse'/>
</operation>
</portType>

The ‘portType’ block connects your binding block to the message blocks which define your method parameter and return types. The name should match the type from the binding block. You’ll also need to change the operation name and the input and output message attributes. The message attribute can be named however you wish as long as it matches the name of its corresponding message block, which we’ll talk about next.

For the inventory example, we’d change our portType block to the following:

<portType name='InventoryPortType'>
<operation name='getItemCount'>
<input message='tns:getItemCountRequest'/>
<output message='tns:getItemCountResponse'/>
</operation>
</portType>

Again, if you wish to add another method to your service, you would just have two operation blocks within the portType block.

The ‘message’ block(s)

<message name='getQuoteRequest'>
<part name='symbol' type='xsd:string'/>
</message>
<message name='getQuoteResponse'>
<part name='Result' type='xsd:float'/>
</message>

Here we have 2 message blocks that correspond to the message attributes found in the portType block of the stockquote.wsdl. This is where the meat of your wsdl resides.

The part element in the document specifies parameters for the requests messages, and the return structure for the variable returned by your function. For parameters, make sure you mape the name with the parameter name, and specify the type. Here is a list of primitive data types accepted: http://www.w3.org/TR/xmlschema-2/#built-in-primitive-datatypes.

For our inventory example, we might modify this section like so:

<message name='getItemCountRequest'>
<part name='upc' type='xsd:string'/>
</message>
<message name='getItemCountResponse'>
<part name='Result' type='xsd:integer'/>
</message>

The ‘definitions’ header

The definitions header is what defines the namespaces of your wsdl document. You can mostly leave this as it is from the example, but you should change a few parts. Here is how I’ve modified my inventory service header:

<definitions name='Inventory'
targetNamespace='urn:JimmyzInventory'
xmlns:tns='urn:JimmyzInventory'
xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
xmlns='http://schemas.xmlsoap.org/wsdl/'>

And that’s pretty much it. Creating your own wsdl isn’t really as bad as it appears.

My final inventory wsdl is located here.

See part 3 for implementing the web service.

SOAP Server with PHP5 – part 1

Setting up a SOAP web service with php used to seem pretty intimidating to me, until I finally decided that I would hunker down and build my own WSDL. Now that I’ve successfully gone through the process of building a SOAP web service with php5, I would say that it really isn’t all that bad. I was actually quite surprised at how easy it was in the end.

To get started, I recommend the PHP Soap Extension article found on the Zend Developer Zone website. Before going through the tutorial you’ll need to make sure that you are running on php 5 with the soap extension installed. If you’re not sure if you are on version 5 or if the SOAP extension is indeed installed, create a script with the following code:

<?php phpinfo(); ?>

That should give you all of your server configuration information that you need. Search that page for “SOAP” and if you find it there with some configuration variables, you’ll know that you’re good to go.

I recommend setting up the SOAP server that is given in the tutorial which requires 3 files: stockquote.wsdl, server1.php, and client3.php. Place those files in a directory that is accessible via http and modify the stockquote.wsdl file, replacing http://[insert real path here]/server1.php with the path to your server1.php file.

Test the service by running the client3.php script. As you modify the service to return more complex data types, you’ll want to change the print function with a print_r to get a dump of the whole data schema that has been returned.

Once you have that working, you can begin to modify the function or WSDL to do what you need it to do.

Important: Before you make changes to the WSDL, add the following line above the client code and at the top of the server1.php script:

ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache

Also, in the wsdl there is a part that has urn:xmethods-delayed-quotes. This has nothing to do with stockquotes, and you should just leave it alone.

See part 2 for an explanation of the wsdl.