Friday, January 25, 2013

Creating web services using PHP

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 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.

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 a WSDL file (web service definition language) where you actually define what are the functions and types you are using.

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 and SOAP.
If you are using php5 or above 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 using linux, you can install it using the following line:

yum install php-soap

If you are using php4 you can use nusoap.

Creating your first web service

We are going to create a web service for a library, where users can search for authors, books, browse each author's books etc.
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:




    
    
     
            
                
                 
                 
                 
                
            

            
                
                 
                 
              
              
             
            

            
                
              
              
             
            

            
                
              
              
             
            
     
  
   
  
  
   
  
  
   
  
  
   
  
  
    
      
      
    
    
     
     
    

 
  
   
   
    
    
     
    

    
     
    
   

   
    
    
     
    
    
     
    
   
  
  
    
      
    
  

The WSDL file contains main 4 parts:

  • types: you simply define the types that you are going to use (it looks like the variables definition in a PASCAL program)
  • 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.
  • 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
  • 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:


The AuthorData class:


Now I am going to create wrapper classes.

Book class:

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:

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 a 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

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 that 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 that everything is ready, lets call the web service.

index.php

 1)); 
try
{
 $response = $client->searchAuthors("Beh");
 //$response = $client->searchBooks("comp");

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

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