Tuesday, August 9, 2011

Recursion in PHP

"In order to understand recursion, one must first understand recursion." - Anonymous

Today I am going to give an example of recursion in PHP. There are some cases where recursion will be a more elegant solution to a given problem than iteration will be.

If you don't already know what recursion is, the simplest way I can explain it is recursion is a function that calls itself.

To give you a better idea of how you can use recursion, here is a very simple example.

Let's say you want to be able to call a function that will count down from whatever number you send as an argument to zero ... but you don't want to use a loop. Instead you could do the following:

//recursive count down function 
function count_down($number) { 
    // check to make sure we have been sent a number
    if (is_numeric($number)) {
        return false;
    }

    // echo pause between numbers
    echo ' ... ';

    // if $number is less then 1, we end our count down
    if ($number < 1) { 
        // echo final output
        echo 0; 
    } else { 
        // if we can still continue our count down we echo the number to the 
        // screen and call count_down again, as you can see this could also be 
        // done in a loop, but for our purpose we are using a recursive function
        echo $number;
        count_down($number-1); 
    } 

    return true;
} 

// call to our count down function and see if it was successful
if (count_down(10)) {
    echo ' ... Lift Off!';
} else {
    echo 'You are doing it wrong!';
} 

This function would output the following:
... 10 ... 9 ... 8 ... 7 ... 6 ... 5 ... 4 ... 3 ... 2 ... 1 ... 0 ... Lift Off!

Obviously this is a very basic example and further study is recommended, but I hope that I have made the concept a little bit easier to grasp.

Friday, May 13, 2011

Web Service Clients in PHP Part 2: SOAP

In my last post I explained how to post to a RESTful web service using CURL. Today I will be posting an example of a SOAP client.

So your imaginary client has now e-mailed you some instructions on how to connect to their SOAP service, probably something like this:

WSDL URL: https://www.example.com/soap/wsdl/ApiUser.wsdl

Method Name: addUser

Parameters: email_address,first_name,last_name (must be passed as an object)

Using this information we can now create our client code:

// first we assign the WSDL url to a variable
$URL = 'https://www.example.com/soap/wsdl/ApiUser.wsdl';

// next we create our soap client using the php SoapClient object
$client = new SoapClient($URL, array("trace" => 1));
  
// we are going to create a standard object to send our parameters
$objRequest = new stdClass();
$objRequest->first_name = 'Jon';
$objRequest->last_name = 'Doe';
$objRequest->email_address = 'jondoe@example.com';
  
// now we wrap our actual web service call in a try catch structure
// this will allow us to catch any exceptions that might be thrown
try { 
    $response = $client->addUser($objRequest); 
} catch ( SOAPFault $e ) {
    $response = ("Error ".$e->faultcode.": ".$e->faultstring); 
}

// now we display the response
echo $response;

Congratulations, thanks to you Jon Doe is now a proud new member of your clients website.

One final note, always read the full documentation when connecting to a web service, there are often little quirks and differences that you will want to be aware of.

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.

Tuesday, January 18, 2011

PHP array_map

One very useful function in PHP is array_map.

Today I am going to show you an example of how you can use this function to quickly filter possibly dangerous data in an array to prevent XSS attacks.

First you will need to create a function that will be used to clean the data:

// heres function that escapes html data to prevent xss attacks
function map_entities($str) {
    return htmlspecialchars($str, ENT_QUOTES);
} 

Next you need to apply that data to an array containing user input (in real life this could be from a $_POST or $_GET or even from a database:

// here $suspect_data is an array containing data needing to be cleaned
$safe_data = array_map('map_entities',$suspect_data);

And now our array is ready for use ... obviously there is more to filtering data then just stripping html characters, but hopefully this little tutorial is helpful in showing you how you can use array_map to solve some real life problems.

Monday, January 17, 2011

Using Smarty PHP Template Engine for Your Design Layer

Looking for a template engine for your latest web application? The good folks over at Smarty have got you covered.

I have been using Smarty for quite awhile now and it has been great. I won't go into all of the reasons I prefer it to some of the other options out there, but I will show you how to use it...

First, you need to download the source from the Smarty website: http://www.smarty.net/download

Now you are ready to get your hands dirty.

The PHP side will look something like this:

// first include the smarty library
include('Smarty.class.php');

// now we create the smarty object
$smarty = new Smarty;

// now we tell smarty where to look for template files
// and where to store compile/config/cache info
$smarty->template_dir = THEFULLPATH.'views/templates/';
$smarty->compile_dir  = THEFULLPATH.'views/templates_c/';
$smarty->config_dir   = THEFULLPATH.'views/configs/';
$smarty->cache_dir    = THEFULLPATH.'views/cache/';

// lets assign our data to template variables now
// in real life you would be getting this data
// from user input or a database, but here we
// are just using a static value
$smarty->assign('FullName', 'Jon Doe');

// display the template
$smarty->display('mytemplate.tpl');

Not bad so far ... now lets create the actual template:

<html>
   <head>
      <title>Hello World</title>
   </head>
   <body>
      Hello {$FullName}
   </body>
</html>

As you can see, Smarty is pretty simple to use. If you would like to become a Smarty expert, a good place to start is here: http://www.smarty.net/crash_course

Friday, January 14, 2011

Good Security Practice - Never Store Passwords in Plain Text

There are many many things to take into consideration when building a secure application.

Today I am going to be talking about storing passwords in a database.

It is all to easy to fall prey to thinking that just because you utilize an SSL certificate that your clients passwords are safe from prying eyes. But what if someone gets access to your database?

One of the most overlooked areas in an organizations security infrastructure is backups. Including backups of MySQL databases. All it takes is one disgruntled ex employee or clever hacker for all of your data to be out there for the world to see.

An easy way to protect passwords is a one way hash. Lets be honest here, there is no reason for you to ever be able to see your clients passwords.

Before you save a new clients password to the database simply run it through a one way hash. For added security you can also add a salt value to the hash like so.

// here we set a global salt value for our site
define('SITESALT', 'YAWRIFJW');

// this function prepares a password for insertion into the database
function getEncryptedPassword($password) {
   return sha1(SITESALT.$password);
}

// now we call our function
$secure_password = getEncryptedPassword($plain_password);

This same code can also be called when a client logs into the system for comparison. This way if anyone ever gets access to the data, they won't be able to just view all of your clients passwords.