Sunday, December 2, 2012

PHP SOAP Web Service With NuSOAP

nusoap

In this tutorial, we create a SOAP web service in PHP.  We use NuSOAP as a third party library for this tutorial. NuSOAP is a very useful library that eases SOAP  web service implementation.

It is a set of PHP classes - no PHP extensions required - that allow developers to create and consume web services based on SOAP 1.1, WSDL 1.1 and HTTP 1.0/1.1.
Download NuSOAP

Copy the lib folder to the project.

We use a simple function that performs zip code loookup as our web service.

First we create SOAP server which exposes the functionality for its clients.

zip_code_server.php

[sourcecode language="php"]
<?php

require_once 'lib/nusoap.php';

//Perform client authentication
//Unauthenticated clients are not allowed to access functionality
function doAuthenticate() {
if (isset($_SERVER['PHP_AUTH_USER']) and isset($_SERVER['PHP_AUTH_PW'])) {

if ($_SERVER['PHP_AUTH_USER'] == "codezone4" && $_SERVER['PHP_AUTH_PW'] == "123")
return true;
else
return false;
}
}

//Retrieve zip code for textual area
//Logic of the web service
function get_zip_code($area) {
//Can query database and any other complex operation
if (!doAuthenticate())
return "Invalid username or password";
if ($area == "Temple Hills") {
return 20757;
} else if ($area == "Cheltenham") {
return 20623;
} else {
return "Can not find zip code for " . $area;
}
}

$server = new soap_server();
$server->configureWSDL("zipcodelist", "urn:zipcodelist");

//Register web service function so that clients can access
$server->register("get_zip_code",
array("area" => "xsd:string"),
array("return" => "xsd:int"),
"urn:zipcodelist",
"urn:zipcodelist#get_zip_code",
"rpc",
"encoded",
"Retrieve zip code for a given area");

$POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA'])? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
$server->service($POST_DATA);
?>
[/sourcecode]

Now, run the server. You will see a link to wsdl file. Click that link and view the generated wsdl file. Clients who access the web service needs this wsdl. Save this file with .wsdl extension. You need to specify the URL for wsdl file within client.

zip_code_client.php

[sourcecode language="php"]
<?php
require_once('lib/nusoap.php');
$client = new nusoap_client("http://localhost/NuSOAP/zip_codes.wsdl", true);

$error = $client->getError();
if ($error) {
echo "<h2>Constructor error</h2><pre>" . $error . "</pre>";
}
//Use basic authentication method
$client->setCredentials("codezone4", "123", "basic");
$result = "";

if ($client) {
$result = $client->call("get_zip_code", array("area" => "Cheltenham"));
}
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>zip code</h2><pre>";
echo $result;
echo "</pre>";
}
}

echo "<h2>Request</h2>";
echo "<pre>" . htmlspecialchars($client->request, ENT_QUOTES) . "</pre>";
echo "<h2>Response</h2>";
echo "<pre>" . htmlspecialchars($client->response, ENT_QUOTES) . "</pre>"
?>
[/sourcecode]

Download Project

Some additional stuff

How to use complex types?
//A complex method
function HelloComplexWorld($mycomplextype)
{
return $mycomplextype;
}

//Create a complex type
$server->wsdl->addComplexType('MyComplexType','complexType','struct','all','',
array( 'ID' => array('name' => 'ID','type' => 'xsd:int'),
'YourName' => array('name' => 'YourName','type' => 'xsd:string')));

//Register our method using the complex type
$server->register(
// method name:
'HelloComplexWorld',
// parameter list:
array('name'=>'tns:MyComplexType'),
// return value(s):
array('return'=>'tns:MyComplexType'),
// namespace:
$namespace,
// soapaction: (use default)
false,
// style: rpc or document
'rpc',
// use: encoded or literal
'encoded',
// description: documentation for the method
'Complex Hello World Method');

6 comments:

  1. Hello!!!

    Thanks for your example. But I´m having a problem... Just copy your code example on my server, but when I´m tying to work it. It´s send me an error Invalid username or password.

    So. I´cant view anything on this vars: $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] it´s happen to me on any examples....

    Have I configure something on my server for run this example? My problem always was a authentication code....

    ReplyDelete
  2. Hi, Did you change credentials within the code that server is looking for a valid username or password? If so, you obviously need to change it in client.
    $client->setCredentials("codezone4", "123", "basic");

    If this is not the case please let me know your problem with any changes you made.
    Thanks,

    ReplyDelete
  3. Hi,

    I saw your post to create a HelloComplexWorld function, it's returning array of data when I test a single function it returning a result. But when I register this function into WebService it's returning only column names not displaying result. Could you tell me where I went wrong?

    my code is:

    //index.php

    configureWSDL("HelloExample");
    // set our namespace
    $server->wsdl->schemaTargetNamespace = $namespace;

    //Register a method that has parameters and return types
    $server->register(
    // method name:
    'HelloWorld',
    // parameter list:
    array('name'=>'xsd:string'),
    // return value(s):
    array('return'=>'xsd:string'),
    // namespace:
    $namespace,
    // soapaction: (use default)
    false,
    // style: rpc or document
    'rpc',
    // use: encoded or literal
    'encoded',
    // description: documentation for the method
    'Simple Hello World Method');


    //Create a complex type
    $server->wsdl->addComplexType('MyComplexType','complexType','struct','all','',
    array( 'ID' => array('name' => 'ID','type' => 'xsd:int'),
    'YourName' => array('name' => 'YourName','type' => 'xsd:string')));

    //Register our method using the complex type
    $server->register(
    // method name:
    'HelloComplexWorld',
    // parameter list:
    array(),
    // return value(s):
    array('return'=>'tns:MyComplexType'),
    // namespace:
    $namespace,
    // soapaction: (use default)
    false,
    // style: rpc or document
    'rpc',
    // use: encoded or literal
    'encoded',
    // description: documentation for the method
    'Complex Hello World Method');

    //Our Simple method
    function HelloWorld($name)
    {
    return "Hello " . $name;
    }

    //Our complex method
    function HelloComplexWorld()
    {
    //return $mycomplextype;
    $result = array();
    $result[] = array( 'ID' => 1, 'YourName' => 'manoj');
    $result[] = array( 'ID' => 2, 'YourName' => 'bojjaiah');

    return $result;
    }

    // Get our posted data if the service is being consumed
    // otherwise leave this data blank.
    $POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';

    // pass our posted data (or nothing) to the soap service
    $server->service($POST_DATA);
    exit();

    ?>

    //client.php

    call('HelloWorld',array('name'=>'Bojjaiah'));

    $result1 = $response->call('HelloComplexWorld',array());

    print_r($result);

    echo '';

    print_r($result1);

    //echo '';

    //var_dump($result1);


    ?>

    my result is:

    HelloWorld function result is: Hello Bojjaiah

    HelloComplexWorld function result is :
    Array
    (
    [ID] =>
    [YourName] =>
    )

    see here not returning field result.

    Could you tell me where I went wrong?

    thanks in advance............

    ReplyDelete
  4. looks interesting, i've been looking for a few days for an example with authentication, i will try it and let you know the result.

    ReplyDelete
  5. Hi, I tried your code above, and modify a little so it will fit in my project. But I keep on having this error , "Operation '' is not defined in the WSDL for this service". Why is that so?

    ReplyDelete
  6. Hi!

    I the authentication works perfectly on localhost but not on server. Nothing changed

    ReplyDelete

How to enable CORS in Laravel 5

https://www.youtube.com/watch?v=PozYTvmgcVE 1. Add middleware php artisan make:middleware Cors return $next($request) ->header('Acces...