Wednesday, February 16, 2011

Web Service Clients in PHP Part 1: POST to REST using a CURL client

The two most common types of web services are SOAP services and REST services. Today I will be talking about the latter. The most basic way to describe a RESTful service is that it is a URL that can be accessed through an http GET or POST (the author of the web service may only allow one or the other, or possibly both).

In my experience the easiest way to connect to a RESTful service is using CURL. I am going to show you a short and simple example here.

So you have just received an e-mail from a client with details on a web service they need to connect to. The information might look something like this:

Web Service URL: http://www.mywebservice.com/superduperfunction.php

POST variables: EmailAddress, FirstName, LastName, APIKey

Your APIKey: Eie73k08@12k

With a little help from CURL, connecting to this web service will be a piece of cake:

   // first we initialize an array and pre populate it with the
   // data we would like to post to the web service
   $postFields = array();
   $postFields['EmailAddress'] = 'fredflinstone@hannabarbara.com';
   $postFields['FirstName'] = 'Fred';
   $postFields['LastName'] = 'Flinstone';
   $postFields['APIKey'] = 'Eie73k08@12k';
   
   // now we are going to loop through our array and create a 
   // query string that we can actually post
   $varList = '';
   foreach ($postFields as $myKey => $myVal) {
      $varList .= $myKey.'='.urlencode($myVal).'&';
   }
   // strip the last & from the end of the query string
   $varList = substr($varList,0,-1);

   // now we initialize CURL, passing it the URL of the web service
   $ch = curl_init('http://www.mywebservice.com/superduperfunction.php');

   // follow redirects 
   curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);

   // dont return http headers
   curl_setopt($ch, CURLOPT_HEADER,0);

   // return the contents of the call
   curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);  
   
   // here we are telling CURL that we are using POST
   curl_setopt($ch, CURLOPT_POST,1);

   // now we load our query string 
   curl_setopt($ch, CURLOPT_POSTFIELDS,$varList);

   // actually post the data and save the response to a variable
   $response_data = curl_exec($ch);
  
   // close our CURL instance
   curl_close($ch);

   // here you could do whatever you need to do with the 
   // response from the web service
   

And there you have it ... Fred Flinstone is now a proud member of some neat new website, and all because you now know how to use CURL.

Thursday, February 3, 2011

Using Memcached in PHP in addition to a MySQL Database

I've been hearing a lot of buzz lately about NoSQL solutions. I personally don't think that relational databases will ever be obsolete. However, I do know from experience that you can dramatically improve the performance and scalability of your MySQL based web app by implementing a caching layer using Memcached.

I am going to walk you through some basic examples here.

I am assuming that you already have your caching server or servers set up, this is just going to walk through the PHP code to talk to your existing servers. If you need set up instructions check out This Link.

I usually use objects to access my database so first I am going to create an abstract class with a memcached connection method for the child classes to inherit.

abstract class MasterData
{
 
   protected $myCache; //memcache object
 
   /********************************************************
   *************** Start MasterData Methods ****************
   *********************************************************/
 
   /* Constructer. Initialize all objects */
   public function __construct() {
      // here we call our memcache creation method
      // in real life our constructor would do more 
      // than this, but this isn't real life, this is
      // my blog
      $this->createCache();
   }
 
   /* Create memcache object */
   public function createCache() {
      // load a memcache object into the myCache property
      $this->myCache = new Memcache;
      
      // CACHE_HOST and CACHE_PORT are constants that should be set
      // in your configuration file to the ip address and port of 
      // your cache server
      $this->myCache->connect(CACHE_HOST, CACHE_PORT);
   }
  
   /********************************************************
   ************** End MasterData Methods *******************
   *********************************************************/

}

Now we are going to create a child object that can extend this MasterData object.

// our fictional CommentData class that extends our MasterData class
class CommentData extends MasterData
{
   /********************************************************
   *************** Start Comment Methods *******************
   *********************************************************/
 
   /* get comment list for a post */
   public function getPostCommentList($postID) {
      // first we check to see if this data is cached.
      // we send the get method a unique key that we
      // use to save this queries data
      $cacheResult = $this->myCache->get('postcomments:'.$postID);

      // if we found a valid cached result for this, we dont have 
      // to run our query, we can just return the result
      if ($cacheResult !== FALSE) {
         return $cacheResult;
      } 
      
      // we didnt find our comment in the cache, so now we will get 
      // it from the database, this example is using Propel ORM to run
      // our query, google PHP Propel for more info
      $commentList = tblPostCommentQuery::create()
         ->filterByPostID($postID)
         ->setFormatter('PropelArrayFormatter')
         ->find();
  
      // update the cache, from now on we wont have to look in the database
      // since we are saving a valid cache result.  The parameters here are 
      // first, a unique key, second, our actual data, third, false to tell 
      // memcache not to compress the data, and last our MCEXPIRE constant is 
      // set to the expiration time in seconds up to 2592000 (30 days).
      $this->myCache->set('postcomments:'.$postID, $commentList, false, MCEXPIRE);
  
      // return the result
      return $commentList; 
   }

   /********************************************************
   ************** End Comment Methods **********************
   *********************************************************/
}

As you can probably guess, since Memcached stores information in memory and uses a single key to grab your data, it will be much more efficient than your MySQL database. Using Memcached this way allows you to retain the advantages of long term storage in a relational database, while utilizing a NoSQL layer for short term performance gains.

In other words, you can have your cake and eat it to.