Tag Archives: Azure

Zend SimpleCloud and Azure

image I’ve been playing with Zend’s SimpleCloud API for the webcast that I’m doing with Zend today. I started with the Zend Framework Quickstart tutorial but changed out the backend to hit the Azure Tables and such (well kinda – I used Zend Studio 8 Beta 2 and didn’t use the ZF tool but I still created a little guestbook). I’m going to expand this example to include blob storage and queues as well in the near future but at the moment, I’m just going to hit the Azure Tables.

update – here are the slides for the presentation:

To get started, I downloaded and installed the Zend Framework CE 1.10 and Zend Studio 8 Beta 2. Then I downloaded and installed the Windows Azure SDK. imageThe last bit that I needed was the Windows Azure 4 Eclipse which will install inside of Zend Studio since it’s built on Eclipse. To install it, open up Zend Studio/Eclipse and select Help | Install New Software to open up the dialog. Then click Add… and fill in the location as http://www.windowsazure4e.org/update. Click OK, select the Windows Azure for Eclipse Toolkit and follow the rest of the wizard to install it. At this point, I’ve got all of the software installed that I need to install and am ready to start coding.

Creating the Project

Before I create the project, a quick tip is that it’s a lot easier to work with IIS if you move the your Eclipse Workspace to c:\users\public\ZendWorkspace (I’m on Windows 7 so that’s where my public documents are). One more quick step is that I give IUSER Read and Execute permissions on the workspace.

imageOnce I’ve moved my workspace, in Zend Studio, select File, New Zend Framework Project.

Name the project SimpleCloudDemo.

Select “Create new project in Workspace”. I tried creating the project on a local server to skip a few steps but that didn’t work so well as you have to be an administrator to write to the c:\inetpub\wwwroot location. Instead, we’ll just map a virtual directory in IIS in a few moments.

Make sure that Zend Framework default project structure is selected (should be the default).

Click Finish. This will create basic project structure that you’ll need to get started. The Zend Framework is a MVC style framework.

To finish setting up the project we need to include the framework bits and the API bits so that we have everything in a nice portable folder. Copy in the C:\Program Files\Zend\ZendServer\GUI\library\Zend directory to [project dir]\library.

Lastly, download the SimpleCloud Api from http://simplecloud.org/download and unzip it to the [project dir]\library directory.

Mapping the IIS Virtual Directory

Now we want to be able to test and make sure that everything is installed correctly and that the project works. To do this, we’re going to map a IIS virtual directory.

image Open Internet Information Services (IIS) Manager and expand the tree on the left hand side until you find the default web site.

Right Click on the Default Web Site and select Add Virtual Directory…

Fill out the Alias with something simple to remember such as simpleclouddemo and fill in the Physical path with the directory to [your project directory]\public. Since I moved my workspace up above, the full Physical path that I entered is c:\users\Public\ZendWorkspace\SimpleCloudDemo\public

image Now, browse to the virtual directory at  http://localhost/simpleclouddemo.

The one other thing that I’ll do that’s IIS specific is create a URL_Redirect rule that will make sure that the Zend Framework actually gets all of the calls rather than the calls just going into the IIS bit bucket. The easiest way to do that is to create a file called web.config in the public directory.

<?xml version="1.0"?>
<?configuration>
  <?system.webserver>
    <?rewrite>
      <?rules>
        <?rule name="Main URL Rewrite Rule" patternsyntax="Wildcard">
          <?match url="*" />
          <?conditions>
            <?add negate="true" input="{REQUEST_FILENAME}" matchtype="IsFile" />
            <?add negate="true" input="{REQUEST_FILENAME}" matchtype="IsDirectory" />
          <?/conditions>
          <?action url="index.php" type="Rewrite" />
        <?/rule>
      <?/rules>
    <?/rewrite>
  <?/system.webserver>
<?/configuration>

At this point you should have the project up and running. Now we’re ready to start slinging code.

Creating the Model and Azure Table

We’re going to dive right in and start creating the model and the Azure Table.

The first thing that we’re going to create is the Guestbook model class itself. Create a new PHP file named GuestBookModel.php in the /application/models directory as follows.

<?php
// application/models/GuestbookModel.php
 
class Application_Model_Guestbook extends Zend_Service_WindowsAzure_Storage_TableEntity
{
	/**
	* @azure comment Edm.String
	*/
	public $comment;	
	/**
	* @azure created Edm.String
	*/
	public $created;
	/**
	* @azure email Edm.String
	*/
	public $email;
}

Couple of things that are interesting here.

  1. Notice that the class extends (read inherits for those of you that don’t do PHP heavily) Zend_Service_WindowsAzure_Storage_TableEntity. This parent class gives us the other required fields such as a PartitionKey, RowKey, TimeStamp and the like.
  2. Next, notice the @azure comments in front of each of the variables. This gives typing information to the Azure Table storage engine for comparisons, sorting and storage optimization. The possible choices there are:
Property Type Details
Edm.Binary An array of bytes up to 64 KB in size.
Edm.Boolean A Boolean value.
Edm.DateTime A 64-bit value expressed as UTC time. The supported range of values is 1/1/1601 to 12/31/9999.
Edm.Double A 64-bit floating point value.
Edm.Guid A 128-bit globally unique identifier.
Edm.Int32 A 32-bit integer.
Edm.Int64 A 64-bit integer.
Edm.String A UTF-16-encoded value. String values may be up to 64 KB in size.

The next thing to do is create the GuestBookMapper in the application\models directory.

<?php
// application/models/GuestbookMapper.php
 
class Application_Model_GuestbookMapper
{
	protected $_cloudTable;
	protected $TABLE_NAME = "guestbook";
	protected $PARTITION_KEY = "guests";
    
    public function setCloudTable()
    {
    	//This constructor takes account parameters for the live azure account
    	//Goes to Dev Storage if you don't pass in any parameters. 
    	$tableStorageClient = new Zend_Service_WindowsAzure_Storage_Table();
		$this->_cloudTable = $tableStorageClient;
    	
        return $this;
    }
    
    public function getTableStorageClient()
    {
    	if (null == $this->_cloudTable) {
            $this->setCloudTable();
    	}
        return $this->_cloudTable;
    }
 
    public function fetchAll()
    {
    	$tableStorageClient = $this->getTableStorageClient();

        if ($tableStorageClient->tableExists($this->TABLE_NAME))
        {
    		return $tableStorageClient->retrieveEntities($this->TABLE_NAME, "", "Application_Model_Guestbook");
        }
    	return null;
    }
    
    public function save(Application_Model_Guestbook $guestbook)
    {
    	$tableStorageClient = $this->getTableStorageClient();
        if (!$tableStorageClient->tableExists($this->TABLE_NAME))
    	{
    		$tableStorageClient->createTable($this->TABLE_NAME);    		
    	}
    	
    	$guestbook->setPartitionKey($this->PARTITION_KEY);
    	if ($guestbook->getRowKey() == null) {
    		$guestbook->setRowKey(uniqid ());
    	}
    	
	$tableStorageClient->insertEntity($this->TABLE_NAME, $guestbook);
    }
  }

As you look at that code, there’s a couple of things to point out.

  1. I could pass in parameters to the constructor of the Zend_Service_WindowsAzure_Storage_Table constructor to give my account information for a Windows Azure storage account but if you don’t pass anything in it defaults to the dev storage account.
  2. In the fetchAll() function,  the second parameter being passed to the retrieveEntities function is a filter parameter. This is where you could pass in the search parameters and/or a partition to retrieve and so on. Regardless of what you pass in, the function attempts to match on those items and returns a collection of items that match.

The next thing is to create the GuestBookController.php in the application\controllers folder.

<?php
/**
 * GuestbookController
 * 
 * @author
 * @version 
 */
require_once 'Zend/Controller/Action.php';
class GuestbookController extends Zend_Controller_Action
{
    /**
     * The default action - show the home page
     */
    public function indexAction ()
    {
        $guestbook = new Application_Model_GuestbookMapper();
        $this->view->entries = $guestbook->fetchAll();
    }
    
    public function signAction()
    {
        $request = $this->getRequest();
        $form    = new Application_Form_Guestbook();
 
        if ($this->getRequest()->isPost()) {
            if ($form->isValid($request->getPost())) {
                $comment = new Application_Model_Guestbook();
                $comment->comment = $form->getValue("comment");
	       $comment->email = $form->getValue("email");
                
	       $mapper  = new Application_Model_GuestbookMapper();
                $mapper->save($comment);
                return $this->_helper->redirector('index');
            }
        }
 
        $this->view->form = $form;
    }
}

Couple of things to point out here as well.

  1. In the indexAction, the fetchAll() call returns the list of entries as a collection and  hands it off to the view.
  2. In the signAction, we’re using the Application_Form_Guestbook which we are about to create. It’s got a little bit of validation but I wouldn’t rely on just that for my business logic but I’m a belt and suspenders kind of guy when it comes to data validation.

The next step is to create the Guestbook.php in application\forms directory.

<?php
class Application_Form_Guestbook extends Zend_Form
{
    public function init()
    {
        // Set the method for the display form to POST
        $this->setMethod('post');
 
        // Add an email element
        $this->addElement('text', 'email', array(
            'label'      => 'Your email address:',
            'required'   => true,
            'filters'    => array('StringTrim'),
            'validators' => array(
                'EmailAddress',
            )
        ));
 
        // Add the comment element
        $this->addElement('textarea', 'comment', array(
            'label'      => 'Please Comment:',
            'required'   => true,
            'validators' => array(
                array('validator' => 'StringLength', 'options' => array(0, 1000))
                )
        ));
 
        // Add a captcha
        $this->addElement('captcha', 'captcha', array(
            'label'      => 'Please enter the 5 letters displayed below:',
            'required'   => true,
            'captcha'    => array(
                'captcha' => 'Figlet',
                'wordLen' => 5,
                'timeout' => 300
            )
        ));
 
        // Add the submit button
        $this->addElement('submit', 'submit', array(
            'ignore'   => true,
            'label'    => 'Sign Guestbook',
        ));
 
        // And finally add some CSRF protection
        $this->addElement('hash', 'csrf', array(
            'ignore' => true,
        ));
    }
}

The only thing to point out here is that this is a standard Zend Framework form.

The last thing that we absolutely need to do is create the two views, one for viewing and one for signing. The first one that we’ll create is index.phtml in application\views\scripts\Guestbook

<!-- application/views/scripts/guestbook/index.phtml -->
 
<p><a href="<?php echo $this->url(
array(
'controller' => 'guestbook',
'action' => 'sign' ),
'default',
true)
?>">Sign Our Guestbook</a></p> Guestbook Entries (<?php echo count($this->entries) ?>): <br /> <table>
<tbody>
<?php foreach ($this->entries as $entry): ?>
<tr>
<td><?php echo $this->escape($entry->email)?></td>
<td><?php echo $this->escape($entry->comment)?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>

And next we’ll create the sign.phtml in application\views\scripts\Guestbook.

<?!-- application/views/scripts/guestbook/sign.phtml -->
 
Please use the form below to sign our guestbook!
 
<?php
$this->form->setAction($this->url());
echo $this->form;

There are other things that we could do but that all that we need to do for the moment. I’ll extend this example in the future.

Now, if you run the application and browse to http://localhost/simpleclouddemo/guestbook

If you get the error “Application errorexception ‘Zend_Http_Client_Adapter_Exception’ with message ‘Unable to Connect to tcp://127.0.0.1:10002. Error #10060: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.” – it’s because you need to launch the Development Fabric and specifically start the storage bit.

Once that’s done, you should see the guestbook as follows:

Empty

Then you can sign the guestbook as follows:

sign

And then it will redirect you back the guestbook which will look as follows:

firstentry

This is the bulk of what I demoed during the webinar. I’m going to continue to expand this demo as time goes on

Webinar on Oct 20, 2010 with Microsoft/Zend

imageI’m looking forward to starting this new webinar series that I’m launching in partnership with Zend about running PHP in general and Zend in particular on Microsoft Azure.

My goal, as I’m writing the demos today after posting this, is to go through the Zend Guestbook quick start and then port that to run in Azure and leverage that platform. I’ll be posting the full technical write-up here once I get done.

From the Zend web site:

Join a webinar on Cloud Computing with Zend Framework and Windows Azure. In this session, we’ll take a technical overview of Windows Azure Data Storage which can be used both inside and outside of your cloud application and the Windows Azure computing which can be leveraged to scale your application horizontally. We’ll write a small application with the Zend Framework and get it up and running in Azure so that we can dive deep into the individual parts in future webinars.
Join this webinar to learn how to take your application to the next level.

Register

It’s important to note that this is the first of a series so we’re going to do an overview across the board this time and then we’ll dive deep into things such as the data access layers or architecting for scaling horizontally across multiple instances in the future.

Resolving PHP Version Conflicts while Developing for Azure

A little while back I wrote a blog post titled Easy Setup for PHP On Azure Development. One of the things that I touched on is the PHP version conflicts. I had a much better idea which I’ve tried and have working so I thought I’d blog that here. What I had you doing in the Easy Setup for PHP On Azure Development is renaming the directory for PHP from something like C:\PHP or C:\Program Files\PHP to something else so that it wasn’t in the %PATH% so there wasn’t a conflict.

The Fix

Reality is that we don’t have to do that. Instead, we can all co-exist happily on the same box. In short, what we’re going to do is load the local version of PHP from our box into the dev fabric rather than using the one that’s bundled with the Eclipse plug-in. The way that we’re going to do that is by using the web.config to specify the location on the local disk where our PHP install is.

That web.config looks something like this:

<?xml version="1.0"?>
<configuration>
  <system.webServer>
  
    <!-- DO NOT REMOVE: PHP FastCGI Module Handler -->
    <handlers>
      <clear />
      <add name="PHP via FastCGI"
           path="*.php"
           verb="*"
           modules="FastCgiModule"
           scriptProcessor="c:\program files\php\php-cgi.exe"
           resourceType="Unspecified" />
      <!--add name="PHP via FastCGI"
           path="*.php"
           verb="*"
           modules="FastCgiModule"
           scriptProcessor="%RoleRoot%\approot\php\php-cgi.exe"
           resourceType="Unspecified" /-->
      <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
    </handlers>
    
    <!-- Example WebRole IIS 7 Configation -->
    <defaultDocument>
      <files>
        <clear />
        <add value="index.php" />
      </files>
    </defaultDocument>
    
  </system.webServer>
</configuration>

Notice that I’ve commented out the original handler that setup the processer with the %RoleRoot%\approot\… We’ll need that when we go live but for now, we’ll use the one that’s actually using the hard path on my local disk.

The exciting part about it is that we’ll be able to use our own version of PHP with all of the extensions that we normally use and configured exactly to taste.

Testing Local

The other exciting thing is that you can actually test any of your WebRole code against your local IIS rather than having to deploy it to the DevFabric every time you want to test. Deploying to the DevFabric takes time and so I’ve found myself taking more time and slinging just a little more code than I should before doing my testing. Against my local IIS box, I’m able to just refresh the browser and see instant results. I still definitely recommend running in the DevFabric because it’s as close to the real environment as you’re going to get at the moment.

image To test against your local IIS with the same exact source code and folders, simply set up the directory as a Virtual Directory. To do that, you need to do one of two things. You can open up the IIS manager and add it that way or you can use Powershell to do it.

In IIS manager, expand the navigation tree down to find the web site that you want to deploy your virtual directory on (typically this is “Default Web Site”) and right click. Then select Add Virtual Directory and fill out the wizard with the alias (e.g. myproject will end up with http://localhost/myproject) and the physical path that you want to use.

If you decide to go with the PowerShell option and do it from the command line, there’s a great cmdlet (Powershell script) called New-WebVirtualDirectory that you can leverage. Make sure that you read the instructions on how to Import All Modules.

The Catch

Now, the issue that you’ll have with this is that when you do actually go to deploy to the cloud, you’ll need to either retest with the version of PHP that’s bundled by default by the Eclipse tooling or make your deployment package by hand with the command line tools.

My recommendation is rolling your own package with the command line tools. Really all you need to do is use CSPack (and possibly CSRun to test locally) from my blog post at Windows Azure Command Line Tools.

Additionally, The great news there is that there’s some great tools available for you at http://azurephptools.codeplex.com/.

Wrap up

I’m much happier with this solution than I was with the whole renaming the directory hack. It worked but it was a pain when switching between regular and Azure development. This way, regular and Azure development are seamless.

Creating a Simple PHP Blog in Azure

In this post, I want to walk through creating a simple Azure application that will show a few pages, leverage Blob storage, Table storage and generally get you started doing PHP on Azure development. In short, we are going to write a very simple PHP Blog engine for Azure.

To be very clear, this is not a pro blog engine and I don’t recommend using it in production. It’s a lab for you to try some things out and play with PHP on Azure development.

If you feel like cheating, all of the source code is available in the zip file at http://www.joshholmes.com/downloads/pablogengine001.zip.

0. Before you get started, you need to make sure that you have the PHP on Azure development environment setup. If you don’t, please follow the instructions at Easy Setup for PHP On Azure Development.

image

Create a Windows Azure Web Project

1. To accomplish this, click on File | New | Project.

2. In the New PHP Azure Web Project page, name the project PABlogEngine (for PHP on Azure Blog Engine).

3. Next you need to select Windows Azure Data Storage. Notice that we’re not selecting SQL Storage. We are going to be using Table and Blob Storage for this project.

4. Click Finish

Creating a Table Entity in PHP

The next step is to get a little setup stuff done. We are going to be using Entities to put into our Table.

1. Create a file called PABlogPost.php. This is going to contain our Entity that we are going to put into our Azure Table storage.

2. Fill out the PABlogPost.php as follows:

<?php
/*
 * Include the Windows Azure Table Storage helper class from the 
 * Windows Azure for PHP SDK
 */
require_once 'Microsoft/WindowsAzure/Storage/Table.php';

class PABlogPost extends Microsoft_WindowsAzure_Storage_TableEntity
{
    /*
     * Notice the Doctrine style comments, some of which, 
     * such as $ImageType, have typing information. 
     * Anything that doesn't have a type is stored as a string. 
     */
    
    /**
     * @azure Title
     */
    public $Title;
    
    /**
     * @azure Description
     */
    public $Description;
    
    /**
     * @azure Author
     */
    public $Author;
    
    /**
     * @azure pubDate
     */
    public $pubDate;
    
    /**
     * @azure Image
     */
    public $Image;
    
    /**
     * @azure ImageUrlOriginal
     */
    public $ImageUrlOriginal;
    
    /**
     * @azure Type
     */
    public $ImageType;
    
    /**
     * @azure Size Edm.Int64
     */
    public $ImageSize;
    
    /**
     * @azure Visible Edm.Boolean
     */
    public $Visible = false;
}
?>

Setting up the utilities

The next step is to get a couple more utilities in place prior to actually writing our application. Specifically, we have two utility functions that we need to hit on and some system wide values.

1. Create a file called utility.php

2. Add the following two values to it.

$BLOG_TABLE = "blogposts";
$BLOG_POSTS_PARTITION = "posts";

We will use these whenever we are going to be accessing the table and or partition. This will let us quickly change them in one place if we ever need to.

The next thing that we need to do is have a consistent way to create our Table Storage Client as we’re using it on more than one page.

3. Add a function called createTableStorageClient as follows:

/**
 * Create Table Storage Client for table operations using account defined in ServiceConfiguration file
 *
 * @return Microsoft_WindowsAzure_Storage_Table New storageclient for Azure Storage Table
 */ 
function createTableStorageClient()
{
  if (isset($_SERVER['USERDOMAIN']) && $_SERVER['USERDOMAIN'] == 'CIS')
  {
    $host = Microsoft_WindowsAzure_Storage::URL_CLOUD_TABLE;
    $accountName = azure_getconfig('AzureCloudStorageAccountName');
    $accountKey = azure_getconfig('AzureCloudStorageAccountKey');
    $usePathStyleUri = true;
    
    $retryPolicy = Microsoft_WindowsAzure_RetryPolicy::retryN(10, 250);
    
    $tableStorageClient = new Microsoft_WindowsAzure_Storage_Table(
                              $host,
                              $accountName,
                              $accountKey,
                              $usePathStyleUri,
                              $retryPolicy
                              );
  }
  else
  {
    $tableStorageClient = new Microsoft_WindowsAzure_Storage_Table();
  }
        
	return $tableStorageClient;
}

4. Lastly, we will need a unique identifier. I’m going to follow Maarten’s lead from the sample code that he’s produced and create a UUID with the following function.

// Generate UUID
function generateUuid($prefix = '')
{
	$chars = md5(uniqid(mt_rand(), true));
	$uuid  = substr($chars,0,8) . '-';
	$uuid .= substr($chars,8,4) . '-';
	$uuid .= substr($chars,12,4) . '-';
	$uuid .= substr($chars,16,4) . '-';
	$uuid .= substr($chars,20,12);
	return $prefix . $uuid;
}

Saving to Windows Azure Table Storage and Windows Azure Blob Storage

There are actually several steps to creating a new post. The first is gathering the information. Next is inserting the post into the table. After that, inserting any images et all into the blob storage, then updating the table if needed with that new information.

1. Create a file called CreateNewPost.php.

2. Insert any template/html code that you want to make it look decent but the primary thing that you need in this page is a form that will accept the correct data do a post back to a file called newpost.php as follows:

<form enctype="multipart/form-data" method="post" action="NewPost.php">
<input value="1048576" type="hidden" name="MAX_FILE_SIZE" />
Title:
<input name="posttitle" /><br />
Description:
<textarea rows="5" name="postdescription" type="text"></textarea><br />
Author:
<input name="postauthor" /><br />
Choose an image to upload:
<input type="file" name="imageUpload" /><br />
<br />
<input value="Create Post" type="submit" />
</form>

3. Create a new file called newpost.php

<?php
// Note that this code is NOT safe against various attacks and should be
// used for demonstrating the concepts of the application only.
// NEVER deploy to production without building correct checks!

// 1. Specify include path and include Windows Azure SDK for PHP
set_include_path( get_include_path() . PATH_SEPARATOR . $_SERVER["RoleRoot"]);
require_once 'utility.php';
require_once 'PABlogPost.php';

require_once 'Microsoft/WindowsAzure/Storage/Table.php';
require_once 'Microsoft/WindowsAzure/Storage/Blob.php';

// 2. Instantiate services and make sure table and blob container exist
$tableStorageClient = new Microsoft_WindowsAzure_Storage_Table();
if (!$tableStorageClient->tableExists($BLOG_TABLE))
{
	$tableStorageClient->createTable($BLOG_TABLE);
}

$blobStorageClient = new Microsoft_WindowsAzure_Storage_Blob();
if (!$blobStorageClient->containerExists($BLOG_TABLE))
{
	$blobStorageClient->createContainer($BLOG_TABLE);
	$blobStorageClient->setContainerAcl($BLOG_TABLE, Microsoft_WindowsAzure_Storage_Blob::ACL_PUBLIC);
}

// 3. Add a record in Windows Azure Table Storage
$newpost = new PABlogPost($BLOG_POSTS_PARTITION, generateUuid());
$newpost->Title = $_POST["posttitle"]; 
$newpost->Description = $_POST["postdescription"]; 
$newpost->Author = $_POST["postauthor"]; 
$newpost->Image = $_FILES['imageUpload']['name'];
$newpost->ImageType = $_FILES['imageUpload']['type'];
$newpost->ImageSize = $_FILES['imageUpload']['size'];
$newpost->UrlOriginal = '';
$newpost = $tableStorageClient->insertEntity($BLOG_TABLE, $newpost);

// 4. Upload the image to blob storage
$blob = $blobStorageClient->putBlob($BLOG_TABLE, $newpost->getRowKey(), $_FILES['imageUpload']['tmp_name']);

// 5. Update the post to reflect the new image URL in the table
$newpost->ImageUrlOriginal = $blob->Url;
$newpost= $tableStorageClient->updateEntity($BLOG_TABLE, $newpost);

?>
<h1>New Post up!</h1>
    
<p>
	Your post has been created. Navigate to
	<!-- 6. Show the results -->
	<a href="post.php?id=<?php echo $newpost->getRowKey(); ?>"><?php echo $newpost->Title; ?></a>
	to see your new post.
</p>

Reading from Windows Azure Table Storage

We are almost done. The last thing that we need to do is to show the results for a specific post and to modify the index.php to show all of the posts.

1. Create a new file called post.php. We already referred to this page in the newpost.php file.

2. Fill out this post.php as follows:

<?php
set_include_path( get_include_path() . PATH_SEPARATOR . $_SERVER["RoleRoot"]);
require_once 'utility.php';
require_once 'PABlogPost.php';
// 1. Include the table storage information

require_once 'Microsoft/WindowsAzure/Storage/Table.php'; // 2. Instantiate services $tableStorageClient = new Microsoft_WindowsAzure_Storage_Table(); // 3. Fetch post details $Id = $_REQUEST['id']; $post = $tableStorageClient->retrieveEntityById($BLOG_TABLE, $BLOG_POSTS_PARTITION, $Id); ?> <h1><?php echo $post->Title; ?></h1> <table border="0" cellspacing="0" cellpadding="2"> <tr> <td rowspan="2"> <img src="<?php echo $post->ImageUrlOriginal; ?>" alt="<?php echo $post->Title; ?>" /> </td> <td> <?php echo ' - Title: <b>' . $post->Title . "</b><br/>"; echo ' - Description: ' . $post->Description . "<br/>"; echo ' - Author: ' . $post->Author . "<br/>"; echo ' - Author: ' . $post->Author . "<br/>"; echo ' - pubDate ' - $post->pubDate . "<br/>"; ?> </td> </tr> </table> <a href='/'>Home</a>

There’s a couple of things to notice about this code.

First, notice that we’re not talking to blob storage in the PHP code. All we are doing is putting in a link to the blob with the $post->ImageUrlOriginal. This is because the blob storage is giving us a restful endpoint that we need.

Another thing to notice is that it’s not doing any checks for exceptions. You will want to do that in your code.

3. The last thing that we need to do is the index.php. Fill it out as follows:

<?php
set_include_path(get_include_path() . PATH_SEPARATOR . $_SERVER["RoleRoot"] . "\\approot\\");

require_once 'utility.php';
require_once 'PABlogPost.php';
/**
 * Refer PHP Azure SDK library files for Azure Storage Services Operations
 */
require_once 'Microsoft/WindowsAzure/Storage.php';
require_once 'Microsoft/WindowsAzure/Storage/Table.php';

$tableStorageClient = createTableStorageClient();

if ($tableStorageClient->tableExists($BLOG_TABLE))
{
	/**
	 * Performing queries. Notice that we are not using a filter. 
	 */
	$posts = $tableStorageClient->retrieveEntities(
		$BLOG_TABLE,
		'',
		'PABlogPost'
	);

	echo "Blog posts:<br />";
	foreach ($posts as $post)
	{
		echo '<p>';
		echo '<b><a href="post.php?id=' . $post->getRowKey() . 
			'">' .$post->Title . '</a></b>';
		echo ' - Description: ' . $post->Description . "<br/>";
		echo ' - Author: ' . $post->Author . "<br/>";
		echo ' - Author: ' . $post->Author . "<br/>";
		echo '</p>';
	}
}
?>

imageConclusion

At this point, we have a very rudimentary blog written in PHP on the Azure platform that is using Table Storage and Blob Storage for all of it’s data. Couple of key points to hit on are that this is not using a traditional database.

I will very likely continue to enhance this little toy application over time as I try showing off more and more things in PHP on Azure.

Again, all of the source code is available in the zip file at http://www.joshholmes.com/downloads/pablogengine001.zip.

*Update* Someone was having issues with this one and emailed me. The error that they were getting was:

Fatal error: Uncaught exception ‘Microsoft_Http_Transport_Exception’ with message ‘cURL error occured during request for http://127.0.0.1:10002/devstoreaccount1/Tables?NextTableName=test: 7 – couldn’t connect to host’

Turns out that they had not started the Development Storage service so there was nothing for cURL to connect to in the first place. To start it, start the Development Fabric (the computation engine). Once the Development Fabric is up and running, you will need to right click on the Dev Fabric icon in the system tray and select Start Development Storage Service.

clip_image001

At this point you should be good to go.

BTW – if you actually play with this code, I’d love to hear about your experiences with it either in email at josh (dot) holmes (at) microsoft (dot) com or in the comments below.

Easy Setup for PHP On Azure Development

I just got back from the JumpIn Camp in fantastic Zurich, Switzerland. I’ll blog about that whole experience shortly. In the meantime, however, I thought I’d get some resources out here that would have been useful last week. 🙂 Specifically in this post, I thought I’d tackle the Windows Azure 4 Eclipse tooling setup.

There are two major things that we need to do. First is to get the Windows Azure SDK installed. The reality is that this is all that you *really* need to do Windows Azure development and testing. However, we want to do our PHP development with the Eclipse toolset for Azure. This gives us debugging support and a lot of great helpers.

Installing the Windows Azure 1.1 February 2010 SDK

First, we need to get the requirements for the Windows Azure 1.1 February SDK itself installed.

To get started, we need to have Windows Vista with Service Pack 1 or later. Really, I recommend that you go with Windows 7 if you have to upgrade.

Enabling ASP.NET and CGI in Windows Features The next thing that you need is to enable IIS with ASP.NET and CGI support. This is easier than it might seem. In the Control Panel, find “Turn Windows Features on or off”. On Vista, you might have to open Add/Remove Programs to find that option. Here, you need to navigate down the tree and find Internet Information Services | World Wide Web Service | Application Development Features and enable ASP.NET and CGI. That will auto select the other dependencies such as .NET Extensibility and ISAPI Extensions and Filters.

Once you complete that, you need to install some version of SQL Server 2005 or later. The one that I recommend, if you don’t have SQL Server already installed is Microsoft SQL Server 2008 Express.

Those are all of requirements the Windows Azure 1.1 February 2010 SDK. At this point we can download and install it.

Installing Eclipse with the Windows Azure for Eclipse tooling

The next step is to install Eclipse itself. Eclipse is written in Java so you will need the Java JRE 5 or later. 5 is no longer supported so I recommend that you go with Java JRE Standard Edition Version 6.

Once that’s installed, it’s a simple matter of downloading the PDT 2.1 All In Ones / Eclipse PHP Package and unzipping it into a folder. The PDT version of Eclipse comes with a lot of tools for PHP including perspectives for PHP, the Zend debugger, XDebug, syntax highlighting and more. The Windows Azure 4 Eclipse tooling builds on this.

Now, you need to install the Windows Azure 4 Eclipse tooling. To do that, open Eclipse and select Help | Install New Software. Click “Add” and put in Windows Azure For Eclipse for the title and http://www.windowsazure4e.org/update for the location. In the tree below, select all three pieces and follow the rest of the wizard.

image

This installs the Windows Azure for PHP SDK and a lot of tooling inside of Eclipse to get you set up.

At this point, you are technically ready to go but I recommend doing a few more things.

Quick Tips to Make Things Smoother

There are a number of little things that we discovered throughout the week that will make things easier for you.

PHP Version Conflicts

The first thing to do is to check to see if you’re going to have any conflicts between the version of PHP on your disk and the version of PHP that comes with the Eclipse tooling. The conflict is that even if both versions are PHP 5.2.13, the version that Eclipse uses is the thread-safe version and the one that everyone else in the world uses is the non-thread-safe version because most people don’t do threading in PHP anyways (I know you do Liz Smith but you’re not most people…). This happens if you’ve used the PHP Installer or the Web Platform Installer to get PHP on your box because both of them put PHP in the %Path% which is the right thing to do. The issue comes in when the Azure DevFabric starts PHP-CGI.exe from your Azure install but that executable looks in the path for it’s dependencies. It finds the non-thread-safe libraries and throws an exception. Oops.

*update* I had a much better idea than the below – check out my new post on resolving the PHP Version conflicts at Resolving PHP Version Conflicts While Developing For Azure”

There are a couple of fixes that you could leverage, none of which are ideal. One is to just install the thread-safe version on your box. There are two issues here. First is that you are now using the thread-safe version of PHP on your own box and it might not be that one in the cloud. The second issue is that you are using your php.ini file from the c:\Program Files (x86)\PHP\ folder. This is not really an issue if you remember this fact and make sure that you deploy that PHP.ini file and set of extensions that you want to deploy.

The other fix, the one that I’ve chosen to do most of the time, is to simply rename the PHP directory on my disk (typically at c:\Program Files\PHP or c:\Program Files (x86)\PHP) when I’m doing Azure development and rename it back when I want to do local development. This is a little bit of a pain sometimes but it’s easier to find these issues than the subtle ones that could be introduced by the other technique.

Resolving the mystery 500 Error

Unfortunately, there’s not a great way to divine what is causing the 500 error in some cases. The one that I see most often is the PHP version conflict. Others include database connection errors, file permissions issues, uncaught exceptions and the like. There are two ways to handle this.

The first is to make heavy use of the logging facilities to write out to the dev fabric manager’s UI the exception.

The second way is to attach either the Zend debugger or XDebug to the Dev Fabric and step through the issue. The way to do that is to

Zend Debugger and Windows Azure DevFabric Storage

Changing the Zend Debugging PortThe first thing is that the Windows Azure DevFabric Storage uses port 10000. This is not a bad thing except that the Zend Debugger, by default, also uses port 10000. The end result is if you launch Eclipse and then try to start the development fabric storage engine, you’ll get a conflict.

Specifically, the error is from the Development Storage engine – “The process cannot access the file because it is being used by another process”. This is a bizarre error that doesn’t actually give you correct information. The way to fix this is in Eclipse, go to Windows | Preferences, find the Zend Debugger settings and edit the port.

Download Windows Azure for PHP Contrib Project

There are a couple of things that are not in the Windows Azure for PHP SDK. A couple of specific examples are Azure Drives, editing the PHP.ini and more. That’s all found in the Windows Azure for PHP Contrib project by Maarten Balliauw. Fun story on this is that at JumpIn Camp Maarten looked over at me and asked me if there was a way to mount Azure drives in PHP. I said that I didn’t think so. 20 minutes later, he called me over to show me that he had gotten it working. He spent another 20 minutes cleaning it up and committed his patch to the Windows Azure for PHP Contrib

Creating a Hello World Azure Application with Eclipse

Select Windows Azure Web Project This has walked you through the setup of the Windows Azure 4 Eclipse tooling and now you’re ready to get started with your first Azure application to test the install and all.

To test the install, click File | New | Project. In the New Project Wizard, expand the tree to find PHP | Windows Azure Web Project.

Click Next.

PHP Azure Project WizardIn the PHP Azure Project, name the project Hello World and select the Windows Azure Data Storage option.

Click Finish.

This will create the project and give you some starter code that you can work with. To do that, select the project in the PHP Explorer and select from the menu Windows Azure | Run in Development Fabric. This will package the application and then launch it in the DevFabric. If it’s not running, it will give you the user access control admin permissions screen twice, once for the DevFabric Compute and once for the DevFabric Storage.

PHP InfoNext will launch the browser and navigate to your application running in the DevFabric. The simple Hello World show PHPInfo().

Soon, I’ll post about writing a slightly more complex application.

Please use the comments on this post to let me know if you were successful or not in getting the PHPInfo() to show…

PHP On Azure Resources

I’m at JumpIn Camp in Zurich and we’ve been diving deep into PHP on Azure. One of the things that we’ve done is talk about a ton of resources that are available out there on the web to learn more about PHP on Azure. To that end, I thought I’d collect a few of them here on my blog.

In the morning, I talked at a high level about what Azure is, how the various roles work and how to run PHP on Azure. My deck that I used was the first half of the same deck that I used on the PHP On Azure World Tour.

Another great starting point and set of resources is Maarten Balliauw’s Blog itself. He’s been helping out here at JumpIn Camp from a technical perspective on Azure and running PHP on Windows in the first place. He did the next part of the session diving deep into the PHP on Azure SDK.

You’ll notice some overlap between our desk because we’re largely talking about the same SDK and leveraging the same code examples.

Maarten’s first deck that he used to talk about Blog, Queue and Table storage is:

The second one that Maarten used to talk about SQL Azure is:

Maarten also did a demo of an app called ImageCloud leverages both a Web and Worker role to do front end uploading of an image and backend processing of that image. That code can be found at ImageCloud Azure Demo Application.

For some great resources on architecture guidance, take a look at Windows Azure Architecture Guidance. This is put out by the Patterns and Practices group at Microsoft.

 

Another great resource is Benchmarking and Guidance for Windows Azure. This was created and launched by the Extreme Computing Group (aka XCG).

 

More resources:

Microsoft Windows Azure Interop

Microsoft Interop Bridges

Windows Azure 4 Eclipse

PHP Azure SDK

Windows Azure MySQL PHP Solution Accelerator

 

I’ll be adding to these resources over the course of the week so check back for lots more.

PHP on Azure World Tour

IMG_2837I have the privilege and honor of doing a tour of across Europe talking to PHP developers about running on Azure and on IIS. The countries that I ended up in are Ireland, Portugal, Austria, UK, Norway, The Netherlands, Belgium and then I went back to Ireland. That included 2 conferences and 6 Microsoft run events.

The way that the trip came about is that I was invited to keynote PHPUK 2010 and since I was going to be in Europe already, Beat Schwegler organized for me to visit the other countries. Big thanks out to him for organizing the whole trip.

The topic in at the Microsoft run events was “Scaling Big While Sleeping Well” which is a talk about PHP on Azure.

Dublin, Ireland (First time around)

Ireland was the first place that I did my Azure session. There were roughly 20 people in the audience.

Lisbon, Portugal

IMG_1966One of my regrets about the whole trip was that I didn’t get to spend as much time in each of the countries as I would like to have. Portugal was definitely one of them that I was disappointed that I didn’t get to spend more time in. I was on the ground for about 18 hours from 10:30 on Monday night to about 2:00 on Tuesday.

On the plus side, we had quite a few people in the audience and they were engaged. I had a ton of good questions and hopefully I answered them all. Also, it was a fantastic venue. It was in the new library building for one of the local colleges – Faculdade Nova de Lisbon. The venue was a real tribute to the college as it was a gorgeous facility and the room was almost acoustically perfect.

Vienna, Austria

IMG_2000This was my first time in Austria. My brother and sister both have done college studies in Austria so told me lots of different things to do while I was there. I was a little disappointed in the turn out at this event as it was only about 7 people there including Rolf Mistelbacher and Gerhard Goeschl from Microsoft.

Another cool thing in Vienna was that I got to catch up with an old friend Andreas Erlacher who showed me around downtown Vienna.

PHPUK 2010 in London, UK

IMG_2098

One of the extremely cool things that I got to do is keynote at PHPUK 2010. I did my Lost Art of Simplicity talk as an uncon session at ZendCon. Scott MacVicor heard about it and was kind enough to pitch it to the board of the conference. The session went over really well and got a lot of great feedback on Joind.in – in fact it’s currently the most reviewed talk on Joind.in. 🙂 Considering that there were roughly 450 people in the audience and 500 at the overall event, it makes a lot of sense.

I want to thank Johanna Cherry, Matt Raines and the rest of the organizing committee for their organization and hospitality.

image Since I was doing the keynote, it didn’t really make sense for me to do another session as well. Rob Allen, however, stepped up big and did a session on Azure. Turns out that he had not looked at Azure prior to Will Coleman and I asking him if he’d be interested in doing the talk. Not only did he say yes, he did a fantastic job as well. I was also pleasantly surprised that there 52 people in the room to hear about Azure.

You can download Rob Allen’s Azure Slides.

Oslo, Norway

IMG_2825This was the first time that I had been to Norway. I got really lucky with the weather. Evidently the week before I was there it was –18 Celsius but it was –4 (roughly 25 Fahrenheit) which is actually a lot like how I left Michigan.

There were 12 people in the audience + Rune Zakariassen who was gracious enough to host me for the day. I also had a chance to meet with Petter Merok, the Developer and Platform Evangelism lead for Norway.

Amsterdam, Netherlands

IMG_2873I’ve been through Schiphol in Amsterdam a lot of times but not really gotten to spend much time outside of the airport itself. Also, it was fantastic to have a great guide around Amsterdam in Juliette Folmer.

The session itself was a joint meeting hosted by Microsoft and PHP Benelux. PHP Benelux is a cooperation of the Netherlands, Belgium and Luxemburg PHP user groups. Big thanks to Stefan Koopmanschap aka @skoop and Bram Veenhof for organizing in the Netherlands. There were two presentations. First was Jan-Willem Eshuis from NOS. NOS is a public broadcast network in the Netherlands that manages all of the sports broadcasting in the country. He talked about Service Oriented Architecture and how NOS has been able to reach the scale that they have. It was a lot of fun talking with him about how they were managing and broadcasting the Olympic coverage. The second presentation was mine. It was a small group, 5 people, but they were very engaged and I almost didn’t make it through the materials…

Brussels, Belgium

IMG_2999I met with the Belgium branch of the PHP Benelux user group the next day in Brussels. This was another small but great meeting.

As with the previous meeting, there were two sessions. The first session was by Michelangelo van Dam aka @dragonbe. He took one of the Zend Framework sample applications and ported it from Linux to Windows showing how easy this process can be. This was cool because it gave between the two of us we were able to point out the power of the web.config from showing off simple configuration and setting up the FastCGI handler to showing the URL Redirect bits.

Next I talked about Azure. Here I got my my personal favorite compliment of the whole trip. It came from a hoster who came in hoping that he wouldn’t like Azure as it’s in direct competition with his business. He begrudgingly told me after the meeting that he was impressed and liked what he had seen. 🙂

Big thanks to Katrien de Grave for hosting me all day and organizing the meeting. It was also great to get to finally meet her after thousands of emails back and forth on various topics.

WordCamp Ireland in Kilkenny, Ireland

I wrapped up my tour by hitting WordCamp Ireland in Kilkenny, Ireland. Read all about that in my post about WordCamp Ireland.

Conclusion

I had a ton of fun on my tour even though it exhausted me completely.

Windows Azure SDK 1.1

There’s an update to the Windows Azure SDK, version 1.1. The SDK extends Visual Studio 2008 and the upcoming Visual Studio 2010 RC making it easy to develop, debug, package and deploy Windows Azure Applications.

There’s a number of new things and a handful of bug fixes from the 1.0.

From the download page:

  • Windows Azure Drive: Enable a Windows Azure application to use existing NTFS APIs to access a durable drive. This allows the Windows Azure application to mount a page blob as a drive letter, such as X:, and enables easy migration of existing NTFS applications to the cloud.
  • OS Version Support: Allows a Windows Azure application to choose the appropriate Guest OS to run on in the cloud.
  • Bug Fixes
    • StorageClient: Expose account key from storage credentials, expose continuation tokens for pagination, and reduce maximum buffer size for parallel uploads.
    • Windows Azure Diagnostics: Fix path corruption for crash dumps, OnDemandTransfer now respects LogLevelFilter.
    • VS 2010: Improved packaging performance.
    • VS 2010: Support for linked files in Web projects.
    • VS 2010: Support for ASP.NET web project web.config transformations.
    • Certificate selection lists certificates from LocalMachine\My instead of CurrentUser\My.
    • Right click on Role under Roles folder to select whether to launch the browser against HTTP, HTTPS or not at all.

Windows Azure Tools for Microsoft Visual Studio includes:

  • C# and VB Project creation support for creating a Windows Azure Cloud Service solution with multiple roles.
  • Tools to add and remove roles from the Cloud Service.
  • Tools to configure each Role.
  • Integrated local development via the Development Fabric and Development Storage services.
  • Running and Debugging a Cloud Service in the Development Fabric.
  • Building and packaging of Cloud Service Packages.
  • Browsing to the Windows Azure Developer Portal.

Download details: Windows Azure Tools for Microsoft Visual Studio 1.1 (February 2010)