HPCloud-PHP  1.2.0
PHP bindings for HPCloud and OpenStack services.
 All Classes Namespaces Files Functions Variables Pages
Tutorial: Using Stream Wrappers

This is an introduction to the HPCloud-PHP library. While the library is large and feature-rich, this tutorial focuses on the Stream Wrapper feature. (There is also a 00-tutorial "tutorial about the object-oriented library".)

TL;DR

With a few lines of setup code, you can fetch objects from HP Cloud's object storage using built-in PHP functions like this:

<?php
// Create a new file and write it to the object store.
$newfile = fopen('swift://Example/my_file.txt', 'w');
fwrite($newfile, "Good Morning!");
fclose($newfile);
// Check for an object:
if (file_exists('swift://Example/my_file.txt')) {
print "Found my_file.txt." . PHP_EOL;
}
// Get an entire object at once:
$file = file_get_contents('swift://Example/my_file.txt');
print 'File: ' . $file . PHP_EOL;
?>

In fact, the vast majority of file and stream functions work with HPCloud's swift:// URLs.

The rest of this tutorial explains how they work.

The Setup

The example above does not show the code necessary for initializing the HPCloud stream wrapper. In this section, we will look at the necessary setup code.

Loading Classes

The HPCloud PHP library is structured following SPR-0 recommendations. Practically speaking, what this means is that applications that use an SPR-0 autoloader may be able to automatically load the HPCloud library.

However, we'll assume that that is not the case. We'll assume that the library needs to be initialized manually.

What we will do is first load the HPCloud Bootstrap.php file, and then use the autoloader in that file to load the rest of the library:

<?php
require_once '/HPCloud/Bootstrap.php';
use \HPCloud\Bootstrap;
Bootstrap::useAutoloader();
Bootstrap::useStreamWrappers();
?>

The first thing the example above does is require the Bootstrap.php file, which contains code necessary for initializing the HPCloud library.

Next, we call two static methods on the HPCloud::Bootstrap object:

  • Bootstrap::useAutoLoader(): This tells HPCloud to load any other classes on demand. Since we use this, we don't need any more require or include statements.
  • Bootstrap::useStreamWrappers(): This tells HPCloud to register its stream wrapper classes.

In a nutshell, PHP allows libraries to map a particular URL pattern to a stream wrapper. HPCloud registers the swift:// URL prefix. So any request to a URL beginning with swift:// will be proxied through the HPCloud library.

Setting Up Authentication

When working with remote HPCloud Object Storage, you must authenticate to the remote system. Authentication requires the following four pieces of information:

All four of these pieces of information can be found in the API Keys section of your console account.

(Note: You can use your username and password instead of account and key, but you still must supply the tenant ID. Instead of supplying account and key, use username and password.)

We are going to look at two ways to set authentication information. The first is global. That means we supply it once, and all stream and file functions automatically use that information. The second is to pass authentication information into the stream context.

Global Configuration

Supplying global account information has two distinct advantages:

  1. It reduces the complexity of your code
  2. It allows context-less functions like file_exists and stat to work.

But it has a disadvantage: Only one account can be used at a time. Since that account's information is shared across all stream wrappers, they all share the same account, tenant Id, and service catalog.

If you are working on an application that needs to connect to more than one account in the same request, you may find this setup imperfect for your needs.

That said, here's how we set up a global configuration:

$settings = array(
'account' => YOUR_ACCOUNT_NUMBER,
'key' => YOUR_SECRET_KEY,
'tenantid' => YOUR_TENANT_ID,
'endpoint' => IDENTITY_SERVICES_URL,
// Instead of account/key you can use this:
// 'username' => YOUR_USERNAME,
// 'password' => YOUR_PASSWORD,
);
Bootstrap::setConfiguration($settings);

Basically, what we do above is declare an associative array of configuration parameters and then tell HPCloud::Bootstrap to set these as the default configuration.

Once the above is done, all of those PHP stream and file functions will just work. All you need to do is pass them swift:// URLs, and they will do the rest.

The Format of Swift URLs

Early in the tutorial we saw some swift URLs like this: swift://Example/my_file.txt . What is this URL referencing?

The URL above has three important parts, in the form swift://CONTAINER/OBJECT_NAME.

  • swift://: This is the schema. This part of the URL tells PHP to pass the request to the HPCloud stream wrapper. (Swift, by the way, is the OpenStack name for object storage.
  • Example: This is the container name. In Object Storage parlance, a container is a place to store documents. One account can have lots of containers, and each container can have lots of objects.
  • my_file.txt: This is the object name. An object is basically the same as a file.

Swift does not support directories, but it does allow slashes in object names. So `swift://Example/this/is/my/file.png' checks the container Example for the object named this/is/my/file.png.

(For power users, there are some fancy operations you can do to treat Swift filename parts as if they were directories. Check out HPCloud::Storage::ObjectStorage::Container.)

Using Stream Contexts for Authentication

Sometimes it is better to pass authentication information directly to the stream or file function, instead of relying upon a global configuration. PHP provides for this with stream contexts.

Stream contexts have one major downside: Not all PHP functions accept stream contexts. Here are some notable examples:

  • file_exists()
  • is_readable()
  • stat()

(Basically, anything that calls the underlying stat(3).)

The advantage, though, is that each call can have its own authentication data. This is good for supporting multiple accounts, and can also be used to optimize long-term performance (e.g. by saving authentication tokens in a database and re-using them).

Here's how a stream context is used:

<?php
require_once __DIR__ . '/../src/HPCloud/Bootstrap.php';
use \HPCloud\Bootstrap;
Bootstrap::useAutoloader();
Bootstrap::useStreamWrappers();
$cxt = stream_context_create(array(
'swift' => array(
'account' => YOUR_ACCOUNT_NUMBER,
'key' => YOUR_SECRET_KEY,
'tenantid' => YOUR_TENANT_ID,
'endpoint' => IDENTITY_SERVICES_URL,
// Instead of account/key you can use this:
// 'username' => YOUR_USERNAME,
// 'password' => YOUR_PASSWORD,
),
));
print file_get_contents('swift://Example/my_file.txt', FALSE, $cxt);
?>

The main difference is the creation of $cxt using PHP's stream_context_create(). To fully understand this, you may want to take a look at the PHP documentation for streams.

Stream Wrapper As A File System

As it was noted earlier in this tutorial, swift does not support directories. Instead the names of a file can be path like with a separator. For example, swiftfs://Example/path/to/my_file.txt has a name of path/to/my_file.txt.

To enable applications to use swift in a more directory like manner there is a second stream wrapper with a prefix swiftfs://. swiftfs stands for swift file system. It works in a similar manner to to the standard stream wrappers with a few key differences:

  • mkdir will return TRUE is no objects start with the directory you are trying to crate. Otherwise it will return FALSE.
  • rmdir will return FALSE if any objects start with the directory prefix you are trying to remove. rmdir does not allow you to remove directories with files in them.
  • Running stat on a directory that is a prefix for some objects (e.g., swiftfs://Example/path/to/) will see this is a prefix for a file and treat it as if it were a directory.

To use this stream wrapper instead of the standard swift one simple replace the usage of swift:// with swiftfs://.

Summary

This tutorial is focused on using stream wrappers to interact with your HPCloud Object Storage service. We focused on configuring the environment for transparently using PHP functions like fopen() and file_get_contents() to work with objects in HPCloud's object storage.

This is just one way of interoperating with the HPCloud library. For more detail-oriented work, you may find the Object Oriented facilities better suited. You can read the OO tutorial to learn more about that.

Addidtionally, you may wish to learn more about the internals of the stream wrapper, the main class, HPCloud::Storage::ObjectStorage::StreamWrapper, is well-documented.