openstack-sdk-php/src/HPCloud/Bootstrap.php
2012-06-13 15:37:13 -04:00

378 lines
12 KiB
PHP

<?php
/* ============================================================================
(c) Copyright 2012 Hewlett-Packard Development Company, L.P.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge,publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
============================================================================ */
/**
* @file
* HP Cloud configuration.
*
* This file contains the HP Cloud autoloader. It also automatically
* register the HPCloud stream wrappers.
*/
namespace HPCloud;
use HPCloud\Services\IdentityServices;
use HPCloud\Exception;
/**
* Bootstrapping services.
*
* There is no requirement that this class be used. HPCloud is
* built to be flexible, and any individual component can be
* used directly, with one caveat: No explicit @c require or
* @c include calls are made. See the "autoloaders" discussion
* below.
*
* This class provides the following services:
*
* - <em>Configuration:</em> "global" settings are set here.
* See the setConfiguration() method to see how they
* can be set, and the config() and hasConfig() methods to see
* how configuration might be checked.
* - <em>Stream Wrappers:</em> This class can initialize a set of stream
* wrappers which will make certain HPCloud services available
* through the core PHP stream support.
* - <em>Autoloader:</em> It provides a special-purpose autoloader that can
* load the HPCloud classes, but which will not interfere with
* other autoloading facilities.
*
* <b>Configuration</b>
*
* Configuration directives can be merged into the existing confiuration
* using the setConfiguration method.
*
* @code
* <?php
* $config = array(
* // Use the faster and better CURL transport.
* 'transport' => '\HPCloud\Transport\CURLTransport',
* // Set the HTTP max wait time to 500.
* 'transport.timeout' => 500,
* );
* Bootstrap::setConfiguration($config);
*
* // Check and get params.
* if (Bootstrap::hasConf('transport.timeout') {
* $to = Bootstrap::conf('transport.timeout');
* }
*
* // Or get a param with a default value:
* $val = Bootstrap::conf('someval', 'default value');
*
* // $val will be set to 'default value' because there
* // is no 'someval' configuration param.
*
* ?>
* @endcode
*
* <b>AUTOLOADING</b>
*
* HPCloud comes with a built-in autoloader that can be called like this:
*
* @code
* Bootstrap::useAutoloader();
* @endcode
*
* @attention
* The structure of the HPCloud file hierarchy is PSR-0 compliant.
* This means that you can use any standard PSR-0 classloader to
* load all of the classes here.
*
* That said, many projects rely upon packages to handle their own
* class loading. To provide this, this package contains a custom
* classloader that will load JUST the HPCloud classes. See
* the Bootstrap::useAutoloader() static method.
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
*
* <b>STREAM WRAPPERS</b>
*
* Stream wrappers allow you to use the built-in file manipulation
* functions in PHP to interact with other services. Specifically,
* the HPCloud stream wrappers allow you to use built-in file commands
* to access Object Storage (Swift) and other HPCloud services using
* commands like file_get_contents() and fopen().
*
* It's awesome. Trust me.
*
*/
class Bootstrap {
/**
* The directory where HPCloud is located.
*/
public static $basedir = __DIR__;
public static $config = array(
// The transport implementation. By default, we use the PHP stream
// wrapper's HTTP mechanism to process transactions.
//'transport' => '\HPCloud\Transport\PHPStreamTransport',
// This is the default transport while a bug persists in the
// Identity Services REST service.
'transport' => '\HPCloud\Transport\CURLTransport',
);
/**
* An identity services object created from the global settings.
* @var object HPCloud::Services::IdentityServices
*/
public static $identity = NULL;
/**
* Add the autoloader to PHP's autoloader list.
*
* This will add the internal special-purpose
* autoloader to the list of autoloaders that PHP will
* leverage to resolve class paths.
*
* Because HPCloud is PSR-0 compliant, any
* full PSR-0 classloader should be capable of loading
* these classes witout issue. You may prefer to use
* a standard PSR-0 loader instead of this one.
*
* @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
*/
public static function useAutoloader() {
spl_autoload_register(__NAMESPACE__ . '\Bootstrap::autoload');
}
/**
* Register stream wrappers for HPCloud.
*
* This register the ObjectStorage stream wrappers, which allow you to access
* ObjectStorage through standard file access mechanisms.
*
* @code
* // Enable stream wrapper.
* Bootstrap::useStreamWrappers();
*
* // Create a context resource.
* $cxt = stream_context_create(array(
* 'tenantid' => '12de21',
* 'account' => '123454321',
* 'secret' => 'f78saf7hhlll',
* 'endpoint' => 'https://identity.hpcloud.com' // <-- not real URL!
* ));
*
* // Get the contents of a Swift object.
* $content = file_get_contents('swift://public/notes.txt', 'r', FALSE, $cxt);
* @endcode
*/
public static function useStreamWrappers() {
$swift = stream_wrapper_register(
\HPCloud\Storage\ObjectStorage\StreamWrapper::DEFAULT_SCHEME,
'\HPCloud\Storage\ObjectStorage\StreamWrapper'
);
$swiftfs = stream_wrapper_register(
\HPCloud\Storage\ObjectStorage\StreamWrapperFS::DEFAULT_SCHEME,
'\HPCloud\Storage\ObjectStorage\StreamWrapperFS'
);
return ($swift && $swiftfs);
}
/**
* Set configuration directives for HPCloud.
*
* This merges the provided associative array into the existing
* configuration parameters (Bootstrap::$config).
*
* All of the HPCloud classes share the same configuration. This
* ensures that a stable runtime environment is maintained.
*
* Common configuration directives:
*
* - 'transport': The namespaced classname for the transport that
* should be used. Example: @code \HPCloud\Transport\CURLTransport @endcode
* - 'transport.debug': The integer 1 for enabling debug, 0 for
* disabling. Enabling will turn on verbose debugging output
* for any transport that supports it.
* - 'transport.timeout': An integer value indicating how long
* the transport layer should wait for an HTTP request. A
* transport MAY ignore this parameter, but the ones included
* with the library honor it.
* - 'account' and 'secret'
* - 'username' and 'password'
* - 'tenantid'
* - 'endpoint': The full URL to identity services. This is used by stream
* wrappers.
*
* @param array $array
* An associative array of configuration directives.
*/
public static function setConfiguration($array) {
self::$config = $array + self::$config;
}
/**
* HPCloud autoloader.
*
* An implementation of a PHP autoload function. Use
* HPCloud::useAutoloader() if you want PHP to automatically
* load classes using this autoloader.
*
* @code
* // Enable the autoloader.
* Bootstrap::useAutoloader();
* @endcode
*
* This is a special-purpose autoloader for loading
* only the HPCloud classes. It will not attempt to
* autoload anything outside of the HPCloud namespace.
*
* Because this is a special-purpose autoloader, it
* should be safe to use with other special-purpose
* autoloaders (and also projects that don't
* rely upon autoloaders).
*
* @param string $klass
* The fully qualified name of the class to be autoloaded.
*/
public static function autoload($klass) {
$components = explode('\\', $klass);
if (empty($components[0])) {
array_shift($components);
}
// This class loader ONLY loads
// our classes. A general purpose
// classloader should be used for
// more sophisticated needs.
if ($components[0] != 'HPCloud') {
return;
}
// We need the path up to, but not including, the root HPCloud dir:
$local_path = substr(self::$basedir, 0, strrpos(self::$basedir, '/HPCloud'));
array_unshift($components, $local_path);
$path = implode(DIRECTORY_SEPARATOR, $components) . '.php';
if (file_exists($path)) {
require $path;
return;
}
}
/**
* Get a configuration option.
*
* Get a configuration option by name, with an optional default.
*
* @param string $name
* The name of the configuration option to get.
* @param mixed $default
* The default value to return if the name is not found.
* @retval mixed
* The value, if found; or the default, if set; or NULL.
*/
public static function config($name = NULL, $default = NULL) {
// If no name is specified, return the entire config array.
if (empty($name)) {
return self::$config;
}
// If the config value exists, return that.
if (isset(self::$config[$name])) {
return self::$config[$name];
}
// Otherwise, just return the default value.
return $default;
}
/**
* Check whether the given configuration option is set.
*
* @code
* if (Bootstrap::hasConfig('transport')) {
* syslog(LOG_INFO, 'An alternate transport is supplied.');
* }
* @endcode
*
* @param string $name
* The name of the item to check for.
* @retval boolean
* TRUE if the named option is set, FALSE otherwise. Note that the value may
* be falsey (FALSE, 0, etc.), but if the value is NULL, this will return
* false.
*/
public static function hasConfig($name) {
return isset(self::$config[$name]);
}
/**
* Get a HPCloud::Services::IdentityService object from the bootstrap config.
*
* A factory helper function that uses the bootstrap configuration to create
* a ready to use HPCloud::Services::IdentityService object.
*
* @param bool $force
* Whether to force the generation of a new object even if one is already
* cached.
* @retval HPCloud::Services::IdentityService
* An authenticated ready to use HPCloud::Services::IdentityService object.
* @throws HPCloud::Exception
* When the needed configuration to authenticate is not available.
*/
public static function identity($force = FALSE) {
// If we already have an identity make sure the token is not expired.
if ($force || is_null(self::$identity) || self::$identity->isExpired()) {
// Make sure we have an endpoint to use
if (!self::hasConfig('endpoint')) {
throw new Exception('Unable to authenticate. No endpoint supplied.');
}
// Neither user nor account can be an empty string, so we need
// to do more checking than self::hasConfig(), which returns TRUE
// if an item exists and is an empty string.
$user = self::config('username', NULL);
$account = self::config('account', NULL);
// Check if we have a username/password
if (!empty($user) && self::hasConfig('password')) {
$is = new IdentityServices(self::config('endpoint'));
$is->authenticateAsUser($user, self::config('password'), self::config('tenantid', NULL), self::config('tenantname', NULL));
self::$identity = $is;
}
// Otherwise we go with access/secret keys
elseif (!empty($account) && self::hasConfig('secret')) {
$is = new IdentityServices(self::config('endpoint'));
$is->authenticateAsAccount($account, self::config('secret'), self::config('tenantid', NULL), self::config('tenantname', NULL));
self::$identity = $is;
}
else {
throw new Exception('Unable to authenticate. No account credentials supplied.');
}
}
return self::$identity;
}
}