As application developers, the ability to develop software and services for a wide range of platforms is a necessary skill, but not everyone uses the same language or platform and writing code to support them all is not feasible. If only there was a standard that allowed us to write code once and allow others to interact with it from their own software with ease. Well luckily there is… and it’s name is SOAP. (SOAP used to be an acronym which stood for Simple Object Access Protocol, but as of version 1.2 the protocol goes simply by the name SOAP.) SOAP allows you to build interoperable software and allows others to take advantage of your software over a network. It defines rules for sending and receiving Remote Procedure Calls (RPC) such as the structure of the request and responses. Therefore, SOAP is not tied to any specific operating system or programming language. As that matters is someone can formulate and parse a SOAP message in their chosen language In this first of a two part series on web services I’ll talk about the SOAP specification and what is involved in creating SOAP messages. I’ll also demonstrate how to create a SOAP server and client using the excellent NuSOAP library to illustrate the flow of SOAP. In the second part I’ll talk about the importance of WSDL files, how you can easily generate them with NuSOAP as well, and how a client may use a WSDL file to better understand your web service.
The Structure of a SOAP Message
SOAP is based on XML so it is considered human read, but there is a specific schema that must be adhered to. Let’s first break down a SOAP message, stripping out all of its data, and just look at the specific elements that make up a SOAP message.<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="https://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="https://www.w3.org/2001/12/soap-encoding">
<soap:Header>
...
</soap:Header>
<soap:Body>
...
<soap:Fault>
...
</soap:Fault>
</soap:Body>
</soap:Envelope>
This might look like just an ordinary XML file, but what makes it a SOAP message is the root element Envelope with the namespace soap
as https://www.w3.org/2001/12/soap-envelope
. The soap:encodingStyle
attribute determines the data types used in the file, but SOAP itself does not have a default encoding.
soap:Envelope
is mandatory, but the next element, soap:Header
, is optional and usually contains information relevant to authentication and session handling. The SOAP protocol doesn’t offer any built-in authentication, but allows developers to include it in this header tag.
Next there’s the required soap:Body
element which contains the actual RPC message, including method names and, in the case of a response, the return values of the method. The soap:Fault
element is optional; if present, it holds any error messages or status information for the SOAP message and must be a child element of soap:Body
.
Now that you understand the basics of what makes up a SOAP message, let’s look at what SOAP request and response messages might look like. Let’s start with a request.
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="https://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="https://www.w3.org/2001/12/soap-encoding">
<soap:Body xmlns:m="http://www.yourwebroot.com/stock">
<m:GetStockPrice>
<m:StockName>IBM</m:StockName>
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>
Above is an example SOAP request message to obtain the stock price of a particular company. Inside soap:Body
you’ll notice the GetStockPrice
element which is specific to the application. It’s not a SOAP element, and it takes its name from the function on the server that will be called for this request. StockName
is also specific to the application and is an argument for the function.
The response message is similar to the request:
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="https://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="https://www.w3.org/2001/12/soap-encoding">
<soap:Body xmlns:m="http://www.yourwebroot.com/stock">
<m:GetStockPriceResponse>
<m:Price>183.08</m:Price>
</m:GetStockPriceResponse>
</soap:Body>
</soap:Envelope>
Inside the soap:Body element there is a GetStockPriceResponse
element with a Price
child that contains the return data. As you would guess, both GetStockPriceResponse
and Price
are specific to this application.
Now that you’ve seen an example request and response and understand the structure of a SOAP message, let’s install NuSOAP and build a SOAP client and server to demonstrate generating such messages.
Building a SOAP Server
It couldn’t be easier to get NuSOAP up and running on your server; just visit sourceforge.net/projects/nusoap, download and unzip the package in your web root direoctry, and you’re done. To use the library just include thenusoap.php
file in your code.
For the server, let’s say we’ve been given the task of building a service to provide a listing of products given a product category. The server should read in the category from a request, look up any products that match the category, and return the list to the user in a CSV format.
Create a file in your web root named productlist.php
with the following code:
<?php
require_once "nusoap.php";
function getProd($category) {
if ($category == "books") {
return join(",", array(
"The WordPress Anthology",
"PHP Master: Write Cutting Edge Code",
"Build Your Own Website the Right Way"));
}
else {
return "No products listed under that category";
}
}
$server = new soap_server();
$server->register("getProd");
$server->service($HTTP_RAW_POST_DATA);
First, the nusoap.php file is included to take advantage of the NuSOAP library. Then, the getProd()
function is defined. Afterward, a new instance of the soap_server class is instantiated, the getProd()
function is registered with its register()
method.
This is really all that’s needed to create your own SOAP server – simple, isn’t it? In a real-world scenario you would probably look up the list of books from a database, but since I want to focus on SOAP, I’ve mocked getProd()
to return a hard-coded list of titles.
If you want to include more functionality in the sever you only need to define the additional functions (or even methods in classes) and register each one as you did above.
Now that we have a working server, let’s build a client to take advantage of it.
Building a SOAP Client
Create a file namedproductlistclient.php
and use the code below:
<?php
require_once "nusoap.php";
$client = new nusoap_client("http://localhost/nusoap/productlist.php");
$error = $client->getError();
if ($error) {
echo "<h2>Constructor error</h2><pre>" . $error . "</pre>";
}
$result = $client->call("getProd", array("category" => "books"));
if ($client->fault) {
echo "<h2>Fault</h2><pre>";
print_r($result);
echo "</pre>";
}
else {
$error = $client->getError();
if ($error) {
echo "<h2>Error</h2><pre>" . $error . "</pre>";
}
else {
echo "<h2>Books</h2><pre>";
echo $result;
echo "</pre>";
}
}
Once again we include nusoap.php
with require_once
and then create a new instance of nusoap_client
. The constructor takes the location of the newly created SOAP server to connect to. The getError()
method checks to see if the client was created correctly and the code displays an error message if it wasn’t.
The call()
method generates and sends the SOAP request to call the method or function defined by the first argument. The second argument to call()
is an associate array of arguments for the RPC. The fault property and getError()
method are used to check for and display any errors. If no there are no errors, then the result of the function is outputted.
Now with both files in your web root directory, launch the client script (in my case http://localhost/nusoap/productlistclient.php
) in your browser. You should see the following:
If you want to inspect the SOAP request and response messages for debug purposes, or if you just to pick them apart for fun, add these lines to the bottom of productlistclient.php
:
echo "<h2>Request</h2>";
echo "<pre>" . htmlspecialchars($client->request, ENT_QUOTES) . "</pre>";
echo "<h2>Response</h2>";
echo "<pre>" . htmlspecialchars($client->response, ENT_QUOTES) . "</pre>";
The HTTP headers and XML content will now be appended to the output.
Summary
In this first part of the series you learned that SOAP provides the ability to build interoperable software supporting a wide range of platforms and programming languages. You also learned about the different parts of a SOAP message and built your own SOAP server and client to demonstrate how SOAP works. In the next part I’ll take you deeper into the SOAP rabbit hole and explain what a WSDL file is and how it can help you with the documentation and structure of your web service. Comments on this article are closed. Have a question about PHP? Why not ask it on our forums? Image via Lilyana Vynogradova / ShutterstockFrequently Asked Questions (FAQs) about Web Services with PHP and SOAP
How can I handle SOAP faults in PHP?
SOAP faults are errors that occur during the processing of SOAP messages. In PHP, you can handle SOAP faults by using the try-catch block. When a SOAP fault occurs, a SoapFault exception is thrown. You can catch this exception and handle it appropriately. For example, you can display an error message to the user or log the error for debugging purposes. Remember to always handle SOAP faults to prevent your application from crashing and to provide a better user experience.
Can I use SOAP with PHP without using the SOAP extension?
Yes, it’s possible to use SOAP with PHP without using the SOAP extension. You can do this by manually creating the SOAP envelope and sending it using the HTTP protocol. However, this method is more complex and error-prone compared to using the SOAP extension. The SOAP extension provides a simple and efficient way to work with SOAP in PHP.
How can I debug SOAP requests and responses in PHP?
Debugging SOAP requests and responses in PHP can be done by using the __getLastRequest() and __getLastResponse() methods of the SoapClient class. These methods return the last SOAP request and response respectively. You can then inspect these values to identify any issues.
How can I add custom headers to a SOAP request in PHP?
You can add custom headers to a SOAP request in PHP by using the SoapHeader class. This class allows you to create a SOAP header that you can add to your SOAP request. You can specify the namespace, name, data, and other properties of the SOAP header.
How can I handle complex types in SOAP with PHP?
Handling complex types in SOAP with PHP can be done by using classes. You can define a class that represents the complex type and then use this class when creating the SOAP request. The SOAP extension will automatically convert the class to the appropriate SOAP type.
How can I call a SOAP method with multiple parameters in PHP?
You can call a SOAP method with multiple parameters in PHP by passing an array to the SoapClient’s __soapCall() method. The array should contain the parameters in the same order as they are defined in the SOAP method.
How can I use SOAP with PHP to consume a web service?
You can use SOAP with PHP to consume a web service by creating a SoapClient object and calling the web service’s methods. The SoapClient class provides a simple and efficient way to consume web services in PHP.
How can I use SOAP with PHP to create a web service?
You can use SOAP with PHP to create a web service by creating a SoapServer object and defining the methods that the web service should expose. The SoapServer class provides a simple and efficient way to create web services in PHP.
How can I use WSDL with SOAP in PHP?
You can use WSDL with SOAP in PHP by specifying the WSDL file when creating a SoapClient object. The WSDL file describes the web service and allows the SoapClient to know how to interact with it.
How can I handle SOAP exceptions in PHP?
SOAP exceptions in PHP can be handled by using the try-catch block. When a SOAP exception occurs, a SoapFault exception is thrown. You can catch this exception and handle it appropriately. For example, you can display an error message to the user or log the error for debugging purposes.
Stephen Thorpe is originally from London but now living in Tennessee. He works at an Internet and Telephone company as an applications developer primarily using PHP and MySQL.