Tuesday, April 5, 2011

Creating web services using PHP

 

What is web service?


first of all I want to explain or define what is web service ? , you can think of web services as DLL files over the web you write the code then compile it and every one can use it whatever the language they are using , but in the web you don’t compile anything , actually when I started using webservices , I was writing c# code so .Net was doing every thing for me , I couldn’t understand what is happening behind the scene I just type [webservice] above the function and everything is running , so In this article i ‘m going to explain what is happening

 

How it works?

web_service

 

1) WSDL

first you have to define what you are serving , think of it as a menu in a restaurant, you can define this by creating WSDL file (web service definition language)  you actually define what are the functions you are using , types

2) SOAP

you can consider SOAP as a waiter in a restaurant , he writes your order ,delivers it to the kitchen and gets the food back to you, that is actually what the soap does; you encapsulate your request to a standard format that matches the definitions in your WSDL file , and the server in the return encapsulates the result into a standard format based also on the WSDL file ; you can consider the WSDL file as the menu in the restaurant , you have to order something from the menu , and the kitchen has to deliver to you what you requested according to the details on the menu

What do you need?

php soap

if you are using php 5 or more  on windows , go to your php.ini and uncomment the following line extension=php_soap.dll , when run your phpinfo you should see it installed

if you are uisng linux , you can intall it using the following line

yum install php-soap

if you are using php 4 you can use nusoap

Creating your first web service

we are going to create a web service for a library , users can search for authors, books , browse each author’s books

each author has the following :

author_id

author_name

and each book has the following:

book_id

book_name

author_id

we are going to assume that each book is written by only one author to simplify the example

 

Creating the WSDL file

I’m going now to create the WSDL file “menu” , here is the code

<?xml version="1.0" encoding="UTF-8"?>

<wsdl:definitions name="Library" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="Library" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="Library" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"  >
    <xsd:documentation></xsd:documentation>
    <wsdl:types>
     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="Library">
            <xsd:complexType name="Book">
                <xsd:sequence>
                 <xsd:element name="ID" type="xsd:integer"></xsd:element>
                 <xsd:element name="NAME" type="xsd:string" ></xsd:element>
                 <xsd:element name="AUTHOR" type="tns:Author" ></xsd:element>
                </xsd:sequence>
            </xsd:complexType>

            <xsd:complexType name="Author">
                <xsd:sequence>
                 <xsd:element name="ID" type="xsd:integer"></xsd:element>
                 <xsd:element name="NAME" type="xsd:string" ></xsd:element>
              <xsd:element name="BOOKS" type="tns:Book"
               minOccurs="0" maxOccurs="unbounded">
              </xsd:element>
             </xsd:sequence>
            </xsd:complexType>

            <xsd:complexType name="Authors">
                <xsd:sequence>
              <xsd:element name="AUTHOR" type="tns:Author"
               minOccurs="0" maxOccurs="unbounded">
              </xsd:element>
             </xsd:sequence>
            </xsd:complexType>

            <xsd:complexType name="Books">
                <xsd:sequence>
              <xsd:element name="BOOK" type="tns:Book"
               minOccurs="0" maxOccurs="unbounded">
              </xsd:element>
             </xsd:sequence>
            </xsd:complexType>
     </xsd:schema></wsdl:types>
  <wsdl:message name="searchAuthorsRequest">
   <wsdl:part name="NAME" type="xsd:string"></wsdl:part>
  </wsdl:message>
  <wsdl:message name="searchAuthorsResponse">
   <wsdl:part name="AUTHORS" type="tns:Authors"></wsdl:part>
  </wsdl:message>
  <wsdl:message name="searchBooksRequest">
   <wsdl:part name="NAME" type="xsd:string"></wsdl:part>
  </wsdl:message>
  <wsdl:message name="searchBooksResponse">
   <wsdl:part name="BOOKS" type="tns:Books"></wsdl:part>
  </wsdl:message>
  <wsdl:portType name="Library">
    <wsdl:operation name="searchAuthors">
      <wsdl:input message="tns:searchAuthorsRequest"/>
      <wsdl:output message="tns:searchAuthorsResponse"/>
    </wsdl:operation>
    <wsdl:operation name="searchBooks">
     <wsdl:input message="tns:searchBooksRequest"></wsdl:input>
     <wsdl:output message="tns:searchBooksResponse"></wsdl:output>
    </wsdl:operation>

 </wsdl:portType>
  <wsdl:binding name="Library" type="tns:Library">
   <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
   <wsdl:operation name="searchAuthors">
    <soap:operation soapAction="http://localhost/Blog/Library/library.php" />
    <wsdl:input>
     <soap:body use="literal" namespace="Library" />
    </wsdl:input>

    <wsdl:output>
     <soap:body use="literal" namespace="Library" />
    </wsdl:output>
   </wsdl:operation>

   <wsdl:operation name="searchBooks">
    <soap:operation soapAction="http://localhost/Blog/Library/library.php" />
    <wsdl:input>
     <soap:body use="literal" namespace="Library" />
    </wsdl:input>
    <wsdl:output>
     <soap:body use="literal" namespace="Library" />
    </wsdl:output>
   </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="Library">
    <wsdl:port binding="tns:Library" name="YLibrary">
      <soap:address location="http://localhost/Blog/Library/library.php" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

the wsdl file contains main 4 parts :

  1. types
            you simply define the types that you are going to use , it looks like the variables definition in a PASCAL
            program.
  2. messages
            each function in the web service has two messages; one for the input and the other for the
            output , also you can add one message to handle the exception. 
  3. port type
            the port type combines one or messages to represent a function , for example the “searchBooks”
            operation combines two messages; one for the input and one for the response
  4. binding
             in the binding section , you define protocol details for the web service 
            






I will create two classes to hold the data  one for books and the other for authors, please notice that you have to name the members exactly the same way you did in the WSDL file 

The BookData class

<?php
class BookData {
     public $ID; 
     public $NAME; 
     public $AUTHOR; 
}
?>

 

The Author Data class

<?php
class AuthorData {
 public $ID; 
 public $NAME;
 public $BOOKS; 
}
?>

?>

now I am going to create wrapper classes

book class

<?php
class Book {
 private $_nID; 
 private $_strName; 

 public function __construct($ID,$Name){
  $this->SetID($ID); 
  $this->SetName($Name); 
 }
 public function SetID($ID){
  $this->_nID=mysql_real_escape_string($ID); 
 }

 
 public function GetID(){
  return $this->_nID; 
 }

 public function SetName($Name){
  $this->_strName=mysql_real_escape_string($Name); 
 }

 public function GetName () {
  return $this->_strName; 
 }

 public function CreateBook (){
  //Code to create Book
 }

 public function UpdateBook () {
  //code to update book 
 }

 public function DeleteBook () {

  //code to delete book 

 }
 public function SearchBooks () {
  $SQL = "SELECT * 
     FROM books
                 INNER JOIN authors
                         on books.author_id=    authors.author_id
     where books.book_name like '%{$this->_strName}%'
    "; 
  $Query = mysql_query($SQL) or die (mysql_error()); 
  
                $NumOfBooks = mysql_num_rows($Query); 
  $Result= array () ; 
  for ($i=0;$i<$NumOfBooks;$i++){

   $Author = new AuthorData(); 
    $Author->ID=mysql_result($Query, $i,"author_id");
    $Author->NAME=mysql_result($Query, $i,"author_name");
    //we will set this when we search by author name
    $Author->BOOKS=array(); 

   $Book = new BookData(); 
    $Book->ID = mysql_result($Query, $i,"book_id"); 
    $Book->NAME=mysql_result($Query, $i,"book_name");
    $Book->AUTHOR=$Author;

   $Result[]= $Book; 
  }
  return $Result; 
 }
}?>

Author Class

<?php



class Author {

 private $_nID; 
 private $_strName; 

 public function __construct($ID,$Name){
  $this->SetID($ID); 
  $this->SetName($Name); 
 }

 public function SetID($ID){
  $this->_nID=mysql_real_escape_string($ID); 
 }

 public function GetID(){
  return $this->_nID; 
 }

 public function SetName($Name){
  $this->_strName=mysql_real_escape_string($Name); 
 }

 public function GetName () {
  return $this->_strName; 
 }

 public function CreateAuthor (){
  //Code to create Author
 }

 public function UpdateAuthor() {
  //code to update Author
 }

 public function DeleteAuthpr() {
  //code to delete Author
 }


 public function SearchAuthors() {
  $SQL = "SELECT * 

     FROM
     authors
     where authors.author_name like '%{$this->_strName}%'
    "; 

  $Query = mysql_query($SQL) or die (mysql_error()); 
  $NumOfAuthors= mysql_num_rows($Query); 

  $Result= array () ; 

  for ($i=0;$i<$NumOfAuthors;$i++){
   $Author = new AuthorData(); 
    $Author->ID=mysql_result($Query, $i,"author_id");
                                $Author->NAME=mysql_result($Query, $i,"author_name");
    $Author->BOOKS=$this->GetBooksByAuthorID($Author->ID);  
   $Result[]= $Author; 
  }
  return $Result; 
 }

 public function GetBooksByAuthorID($ID){

  $SQL = "select * from books where author_id = $ID"; 

  $Query = mysql_query($SQL);  
  $NumOfBooks = mysql_num_rows($Query); 

  $Result = array () ; 

  for($i=0;$i<$NumOfBooks;$i++){

   $Book = new BookData(); 
    $Book->ID=mysql_result($Query, $i,"books.book_id");
    $Book->NAME=mysql_result($Query, $i,"books.book_name");

   $Result[]= $Book ; 

  }
  return $Result; 
 }
}
?>

finally we will create php file who is supposed to receive the request from soap clients and return results , this file is the one written in the soap action attribute in the WSDL file

library.php

<?php

mysql_connect("localhost","root",""); 
mysql_select_db("library");


function __autoload($ClassName) {
 require_once $ClassName.".php";
}

function searchAuthors ($NAME) {
 $Author = new Author(null, $NAME); 
 return $Author->SearchAuthors();
}

function searchBooks($NAME){
 $Book = new Book(null, $NAME); 
 return $Book->searchBooks();
}

ini_set("soap.wsdl_cache_enabled", "0"); 

$classmap = array(
 "Book"=>"BookData",
 "Author"=>"AuthorData"
);
$server = new SoapServer("Library.wsdl",array("classmap"=>$classmap));
$server->addFunction("searchAuthors"); 
$server->addFunction("searchBooks"); 
$server->handle();
?>

 

please notice you have to create a map between your complex types and your classes ”the ones that hold the data”

for example here , I mapped between Book ”the complex type in the WSDL file ” and BookData “The php class”

 

now everything is ready , lets call the web service

index.php

<?php
$client = new SoapClient("http://localhost/Blog/Library/Library.wsdl",array("trace" => 1)); 
try
{
 $response = $client->searchAuthors("Beh");
 //$response = $client->searchBooks("comp");

 var_dump($response);
 echo "Request".htmlspecialchars($client->__getLastRequest())."<br>";
 echo "Response".htmlspecialchars($client->__getLastResponse())."<br>";

}catch(Exception $e){
 var_dump($e);
 echo $client->__getLastRequest();
 echo $client->__getLastResponse();
}
?>

21 comments:

hippomegas said...

Muy buena aportación, felicidades

comic pictures said...

thanks a lot for the tutorial it helped me so so much friend.

mindroots said...

Hi
Nice Article
Very Beneficial
Thanks for the Post

Windel said...

Very Nice....
thank a lot!!!

filmsupload.net said...

this is wonderful tutorial .. i read it 3 times and get a fantastic results and sure i put a
copy of this lesson on my site here

phptuto said...

This article is not saying PHP is the best thing in the world, it is just saying most of the negative opinions are no longer relevant. I know several Ruby developers – some who give talks at the conferences you probably go to – and they are incredibly smart people. That said, they switched away from PHP around version 4 and some of them dont even know about autoloading of __call(). They’re complaining about things being missing that have been in the core for 5 years.

There are people going around giving strong opinions against PHP who actually don’t know all that much about it and I see this happen all the time. We’re all prone to it. How many of you like ASP.NET? Had a chat with somebody who uses it? They’ll probably tell you things got a lot better since version X.

Side note: for the love of god, can everyone stop saying “fuck it, use Rails!”. I love Rails, its really good; shiny syntax, great gems, we’ve got it: Rails is good! Now go and tell your boss he’s doing it wrong. Then go and tell all of your clients to switch servers and fire their development team. Not really an option is it.

hassan_adel9999 said...

this is wonderful tutorial .. i read it 3 times and get a fantastic results and sure i put a
copy of this lesson on my site here

www.egypttourists.blogspot.com

Anonymous said...

thanks a lot for the tutorial it helped me so so much
http://www.bn5l.com/

Anonymous said...

Very Beneficial
Thanks for the Post


http://www.ta7777.com/vb/

Rajat said...

thanks for this useful tutorial.

Anonymous said...

wow

Anonymous said...

wow
http://hotnewslanka.info

Anonymous said...

very good... keep posting like this

Anonymous said...

please provide the complete source code files..

Unknown said...

Hi,

I would be pleased if you could try the generator WsdlToPhp on http://www.wsdltophp.com, I would be pleased to have your feedbacks,

regards

Sahasra said...

Please provide the source code files

Thanks

Sahasra said...

Please provide the source code files

harshad said...

i am getting error as below Array
(
[Code] => Array
(
[Value] => soap:Receiver
)

[Reason] => Array
(
[Text] => Array
(
[!xml:lang] => en
[!] => An error occurred on the server.
)

)

[Detail] =>
)

Unknown said...

Thanks for describing code in better pattern. I am sure this library will help many programmers like me for PHP Website Development Services and easier work.

We Travel Now said...

this is wonderful article .. i read it many times, And I use it in my website www.wetravelnow.com and get a fantastic results, And I am sure any one will read it,will like it.

Anonymous said...

The blog was absolutely fantastic! lot of great information which can be in some helpful or the other way. keep updating the blog, looking forward for more happy ... great job, keep it up ... PHP Website Services