June 7, 2012 update: The Microsoft Windows Azure team has released a new Windows Azure SDK for PHP. This release is part of an effort to keep PHP client libraries up to date with new Windows Azure features and to make PHP a first-class citizen in Windows Azure. The latest client libraries are on GitHub: https://github.com/WindowsAzure/azure-sdk-for-php. While the SDK hosted on CodePlex will continue to work for the foreseeable future, it is strongly recommended that new PHP/Windows Azure application use the SDK hosted on GitHub.

The work done by Maarten Balliauw and other contributors in building the SDK hosted on CodePlex was critical in unifying the PHP developer experience for Windows Azure. The Windows Azure team is grateful to these contributors for their pioneering work and looks forward to their continued support (and yours!) in adding to the new SDK on GitHub.

Thanks,

      
The Windows Azure Team


One of the most interesting presentations I attended at the Dutch PHP Conference was a presentation about NoSQL by Matthew Weier O’Phinney. (The slides for his presentation are the same ones he used at TEK-X and are available here:http://is.gd/cQ82f.)  I walked away from the presentation with two questions: 1) Under what conditions is it advantageous to use a non-relational data store?, and 2) Is Windows Azure Table Storage a NoSQL data store? I still have some homework to do in answering the first question and to answer the second question I really needed to learn more about Windows Azure Table Storage, which is what I’ll cover in this post. Specifically, I’ll look at what Windows Azure Table Storage is, how to create a Windows Azure Table Storage account, and how to access the service from PHP.

 

What is Windows Azure Table Storage?

An overly-simplified answer: Windows Azure Table Storage is structured storage in the cloud provided by the Windows Azure platform. It allows you to create any number of tables, which can each contain any number of entities. Each entity can in turn contain any number of properties. A picture is worth a thousand words here:

    image

Although entities are analogous to rows and properties are analogous to columns (in a relational database), note here that the structure of each entity within a table does not need to be the same (each entity can have different properties and a different number of properties). However, each entity must have a partition key and a row key, which together make up a unique key for an entity within a table. (Each entity also has a timestamp associated with it, which is automatically added for you). Also note that size of all properties combined for a single entity cannot exceed 1 MB.

For a more detailed look at what Windows Azure Table Storage is, read the Windows Azure Table – Programming Table Storage whitepaper here: http://www.microsoft.com/windowsazure/whitepapers/.

 

How do I create a storage account?

To get started you need a Windows Azure subscription, which you can create here: http://www.microsoft.com/windowsazure/offers/. (You’ll need a Windows Live ID to sign up.) I signed up for the Introductory Special, which allows me to get started for free as long as keep my usage limited. (This is a limited offer. For complete pricing details, see http://www.microsoft.com/windowsazure/pricing/.) After you purchase your subscription, you will have to activate it before you can begin using it (activation instructions will be provided in an e-mail after signing up).

After creating and activating your subscription, go to the Windows Azure Developer Portal, click on your Project Name, then on New Service, and select Storage Account:

image

Next, provide a Service Label and Description and click Next. Now you will need to provide a globally unique name for your storage account. (Ignore that fact that the UI suggests you are creating a blob store here…you actually get a blob store, a table store, and a queue.) Make note of this name as you will need it when we start writing PHP code.

image

Next, select the region in which you want your data hosted (if you are interested in Affinity Groups, you can read more here):

image 

Now when you click Create you will get three Endpoints (one each for blob, table, and queue storage), a Primary Access Key, and a Secondary Access Key. You will need your Primary Access Key in the next section.

 

How do I access Windows Azure Table Storage from PHP?

OK, now for the fun part. Accessing Table Storage via PHP is easy thanks to the Windows Azure SDK for PHP. Start by downloading the SDK, unzipping the package, adding the unzipped folder to your PHP libraries, and adding the library directory to your include_path in your php.ini file. (I put the folder in my PHPLibraries directory and updated my include_path to include C:\PHPLibraries\PHPAzure-1.0.1\library.) Now we are ready to start writing code.

The documentation here will give you a good idea about how to use the SDK, but I thought it would be helpful to build a simple, proof-of-concept application (script attached to this post). I’ll walk you through the relevant parts of that application here. (The application stores information about personal and business contacts, and allows you to update, delete, and filter contacts.)

Creating a Table

Creating a table is a simple as creating a new Microsoft_WindowsAzure_Storage_Table object and calling the createTable method. Note that here is where you need your storage account name and Primary Access Key. Also note that I needed to include the Table.php file (I’ll explain the entities.php file below):

require 'Microsoft\WindowsAzure\Storage\Table.php';
require 'entities.php';

$storageClient = new Microsoft_WindowsAzure_Storage_Table('table.core.windows.net',
                                                          'Your_Storage_Account_Name',
                                                          'Your_Primary_Access_Key');
if(!$storageClient->tableExists("ContactsTable"))
    $storageClient->createTable("ContactsTable");

Creating and Inserting an Entity

Here is where the entities.php file that I mentioned earlier comes in. A schema is enforced on entities that are of a type that inherits from the Microsoft_WindowsAzure_Storage_TableEntity class and uses “docblock” style comments for properties. (If you want to create entities that do not have an enforced schema, you should use the Microsoft_WindowsAzure_Storage_DynamicTableEntity class. This will allow you to create entities on the fly that each have different structures - see examples here). So, a class called Contact that inherits from the Microsoft_WindowsAzure_Storage_TableEntity class is defined in the entities.php file :

class Contact extends Microsoft_WindowsAzure_Storage_TableEntity
{
    /**
     * @azure Name
     */
    public $Name;
    /**
     * @azure Address
     */
    public $Address;
    /**
     * @azure Phone
     */
    public $Phone;
}

This allows class properties to be mapped to Windows Azure Table properties. The properties inherited from Microsoft_WindowsAzure_Storage_TableEntity include the required partitionKey and rowKey. So, to create and insert and entity, I create a new Contact object (with the partitionKey and rowKey as parameters), set the custom properties, and call the insertEntity method:

$contact = new Contact ($_POST['contacttype'], $_POST['email']);
$contact->Name = $_POST['name'];
$contact->Address = $_POST['address'];
$contact->Phone = $_POST['phone'];
$result = $storageClient->insertEntity('ContactsTable', $contact);

Note that the partitionKey is either ‘business’ or ‘personal’ and the rowKey is the person’s e-mail address.

Deleting an Entity

Deleting an entity requires first retrieving the entity and then calling the deleteEntity method:

$contact = $storageClient->retrieveEntityById('ContactsTable', $_GET['contacttype'], $_GET['email']);
$storageClient->deleteEntity('ContactsTable', $contact);

Note that the retrieveEntityById method takes the partitionKey and rowKey, which together define the key for an entity.

Updating an Entity

Updating an entity is straightforward if you are only updating custom properties: you simply retrieve the entity (as above), update the properties, and call the updateEntity method. However, there is no way to update the partitionKey and rowKey for an entity – once an entity has been inserted, these are set. So, practically speaking, if you want to update a partitionKey or rowKey, you have to create a new entity and delete the old one. Here’s what my code looks like for my simple application:

// Partition keys and row keys cannot be updated, so delete the old entity and create a new one.
if($_POST['oldcontacttype'] != $_POST['contacttype'] || $_POST['oldemail'] != $_POST['email'])
{
    // Delete the old entity.
    $oldContact = $storageClient->retrieveEntityById('ContactsTable',
                                                      $_POST['oldcontacttype'],
                                                      $_POST['oldemail']);
    $storageClient->deleteEntity('ContactsTable', $oldContact);
    // Create a new entity.
    $contact = new Contact ($_POST['contacttype'], $_POST['email']);
    $contact->Name = $_POST['name'];
    $contact->Address = $_POST['address'];
    $contact->Phone = $_POST['phone'];
    $result = $storageClient->insertEntity('ContactsTable', $contact);
}
else //If only custom properties are changed, the entity can be updated.
{
    $contact = $storageClient->retrieveEntityById('ContactsTable', $_POST['contacttype'], $_POST['email']);
    $contact->Name = $_POST['name'];
    $contact->Address = $_POST['address'];
    $contact->Phone = $_POST['phone'];
    $storageClient->updateEntity('ContactsTable', $contact);
}

Filtering Entities

Filtering entities requires creating a query and passing it to the retrieveEntities method. The query can use the gt, lt, eq, ne, ge, or le operators (for ‘greater than’, ‘less than’, ‘equal to’, ‘not equal to’, ‘greater than’ or equal to’, or ‘less than or equal to’ respectively) to compare property values with a string. Expressions can also use and and or to create more complex queries. Here’s what my code looks like for filtering contact types:

$query = "PartitionKey eq '".$_POST['contacttype']."'";

$contacts = $storageClient->retrieveEntities("ContactsTable", $query, "Contact");
foreach($contacts as $contact)
{
    //Display info in a table.
    //See attachment for complete code.   
}

Note that specifying "Contact" as the third parameter in retrieveEntities materializes the returned entities as objects of type Contact.

That’s it for today. As I mentioned earlier, the complete code for my example application is attached to this post. Once you create a storage account, you should only need to replace Your_Storage_Account_Name and Your_Primary_Access_Key in the tablestorage.php file and have a working application to play with and (hopefully) learn from. Enjoy!

Thanks.

-Brian

Share this on Twitter