HPCloud-PHP  1.2.0
PHP bindings for HPCloud and OpenStack services.
 All Classes Namespaces Files Functions Variables Pages
Bootstrap.php
Go to the documentation of this file.
1 <?php
2 /* ============================================================================
3 (c) Copyright 2012 Hewlett-Packard Development Company, L.P.
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge,publish, distribute, sublicense, and/or sell copies of
8 the Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 ============================================================================ */
22 /**
23  * @file
24  * HP Cloud configuration.
25  *
26  * This file contains the HP Cloud autoloader. It also automatically
27  * register the HPCloud stream wrappers.
28  */
29 
30 namespace HPCloud;
31 
34 
35 /**
36  * Bootstrapping services.
37  *
38  * There is no requirement that this class be used. HPCloud is
39  * built to be flexible, and any individual component can be
40  * used directly, with one caveat: No explicit @c require or
41  * @c include calls are made. See the "autoloaders" discussion
42  * below.
43  *
44  * This class provides the following services:
45  *
46  * - <em>Configuration:</em> "global" settings are set here.
47  * See the setConfiguration() method to see how they
48  * can be set, and the config() and hasConfig() methods to see
49  * how configuration might be checked.
50  * - <em>Stream Wrappers:</em> This class can initialize a set of stream
51  * wrappers which will make certain HPCloud services available
52  * through the core PHP stream support.
53  * - <em>Autoloader:</em> It provides a special-purpose autoloader that can
54  * load the HPCloud classes, but which will not interfere with
55  * other autoloading facilities.
56  *
57  * <b>Configuration</b>
58  *
59  * Configuration directives can be merged into the existing confiuration
60  * using the setConfiguration method.
61  *
62  * @code
63  * <?php
64  * $config = array(
65  * // Use the faster and better CURL transport.
66  * 'transport' => '\HPCloud\Transport\CURLTransport',
67  * // Set the HTTP max wait time to 500.
68  * 'transport.timeout' => 500,
69  * );
70  * Bootstrap::setConfiguration($config);
71  *
72  * // Check and get params.
73  * if (Bootstrap::hasConf('transport.timeout') {
74  * $to = Bootstrap::conf('transport.timeout');
75  * }
76  *
77  * // Or get a param with a default value:
78  * $val = Bootstrap::conf('someval', 'default value');
79  *
80  * // $val will be set to 'default value' because there
81  * // is no 'someval' configuration param.
82  *
83  * ?>
84  * @endcode
85  *
86  * <b>AUTOLOADING</b>
87  *
88  * HPCloud comes with a built-in autoloader that can be called like this:
89  *
90  * @code
91  * Bootstrap::useAutoloader();
92  * @endcode
93  *
94  * @attention
95  * The structure of the HPCloud file hierarchy is PSR-0 compliant.
96  * This means that you can use any standard PSR-0 classloader to
97  * load all of the classes here.
98  *
99  * That said, many projects rely upon packages to handle their own
100  * class loading. To provide this, this package contains a custom
101  * classloader that will load JUST the HPCloud classes. See
102  * the Bootstrap::useAutoloader() static method.
103  *
104  * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
105  *
106  * <b>STREAM WRAPPERS</b>
107  *
108  * Stream wrappers allow you to use the built-in file manipulation
109  * functions in PHP to interact with other services. Specifically,
110  * the HPCloud stream wrappers allow you to use built-in file commands
111  * to access Object Storage (Swift) and other HPCloud services using
112  * commands like file_get_contents() and fopen().
113  *
114  * It's awesome. Trust me.
115  *
116  */
117 class Bootstrap {
118 
119  /**
120  * The directory where HPCloud is located.
121  */
122  public static $basedir = __DIR__;
123 
124  public static $config = array(
125  // The transport implementation. By default, we use the PHP stream
126  // wrapper's HTTP mechanism to process transactions.
127  //'transport' => '\HPCloud\Transport\PHPStreamTransport',
128 
129  // This is the default transport while a bug persists in the
130  // Identity Services REST service.
131  'transport' => '\HPCloud\Transport\CURLTransport',
132  );
133 
134  /**
135  * An identity services object created from the global settings.
136  * @var object HPCloud::Services::IdentityServices
137  */
138  public static $identity = NULL;
139 
140  /**
141  * Add the autoloader to PHP's autoloader list.
142  *
143  * This will add the internal special-purpose
144  * autoloader to the list of autoloaders that PHP will
145  * leverage to resolve class paths.
146  *
147  * Because HPCloud is PSR-0 compliant, any
148  * full PSR-0 classloader should be capable of loading
149  * these classes witout issue. You may prefer to use
150  * a standard PSR-0 loader instead of this one.
151  *
152  * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
153  */
154  public static function useAutoloader() {
155  spl_autoload_register(__NAMESPACE__ . '\Bootstrap::autoload');
156  }
157 
158  /**
159  * Register stream wrappers for HPCloud.
160  *
161  * This register the ObjectStorage stream wrappers, which allow you to access
162  * ObjectStorage through standard file access mechanisms.
163  *
164  * @code
165  * // Enable stream wrapper.
166  * Bootstrap::useStreamWrappers();
167  *
168  * // Create a context resource.
169  * $cxt = stream_context_create(array(
170  * 'tenantid' => '12de21',
171  * 'account' => '123454321',
172  * 'secret' => 'f78saf7hhlll',
173  * 'endpoint' => 'https://identity.hpcloud.com' // <-- not real URL!
174  * ));
175  *
176  * // Get the contents of a Swift object.
177  * $content = file_get_contents('swift://public/notes.txt', 'r', FALSE, $cxt);
178  * @endcode
179  */
180  public static function useStreamWrappers() {
181  $swift = stream_wrapper_register(
182  \HPCloud\Storage\ObjectStorage\StreamWrapper::DEFAULT_SCHEME,
183  '\HPCloud\Storage\ObjectStorage\StreamWrapper'
184  );
185 
186  $swiftfs = stream_wrapper_register(
187  \HPCloud\Storage\ObjectStorage\StreamWrapperFS::DEFAULT_SCHEME,
188  '\HPCloud\Storage\ObjectStorage\StreamWrapperFS'
189  );
190 
191  return ($swift && $swiftfs);
192  }
193 
194  /**
195  * Set configuration directives for HPCloud.
196  *
197  * This merges the provided associative array into the existing
198  * configuration parameters (Bootstrap::$config).
199  *
200  * All of the HPCloud classes share the same configuration. This
201  * ensures that a stable runtime environment is maintained.
202  *
203  * Common configuration directives:
204  *
205  * - 'transport': The namespaced classname for the transport that
206  * should be used. Example: @code \HPCloud\Transport\CURLTransport @endcode
207  * - 'transport.debug': The integer 1 for enabling debug, 0 for
208  * disabling. Enabling will turn on verbose debugging output
209  * for any transport that supports it.
210  * - 'transport.timeout': An integer value indicating how long
211  * the transport layer should wait for an HTTP request. A
212  * transport MAY ignore this parameter, but the ones included
213  * with the library honor it.
214  * - 'transport.ssl.verify': Set this to FALSE to turn off SSL certificate
215  * verification. This is NOT recommended, but is sometimes necessary for
216  * certain proxy configurations.
217  * - 'account' and 'secret'
218  * - 'username' and 'password'
219  * - 'tenantid'
220  * - 'endpoint': The full URL to identity services. This is used by stream
221  * wrappers.
222  *
223  * The CURL wrapper supports proxy settings:
224  *
225  * - proxy: the proxy server URL (CURLOPT_PROXY)
226  * - proxy.userpwd: the proxy username:password (CURLOPT_PROXYUSERPWD)
227  * - proxy.auth: See CURLOPT_PROXYAUTH
228  * - proxy.port: The proxy port. (CURLOPT_PROXYPORT)
229  * - proxy.type: see CURLOPT_PROXYTYPE
230  * - proxy.tunnel: If this is set to TRUE, attempt to tunnel through the
231  * proxy. This is recommended when using a proxy. (CURLOPT_HTTPPROXYTUNNEL)
232  *
233  * @param array $array
234  * An associative array of configuration directives.
235  */
236  public static function setConfiguration($array) {
237  self::$config = $array + self::$config;
238  }
239 
240  /**
241  * HPCloud autoloader.
242  *
243  * An implementation of a PHP autoload function. Use
244  * HPCloud::useAutoloader() if you want PHP to automatically
245  * load classes using this autoloader.
246  *
247  * @code
248  * // Enable the autoloader.
249  * Bootstrap::useAutoloader();
250  * @endcode
251  *
252  * This is a special-purpose autoloader for loading
253  * only the HPCloud classes. It will not attempt to
254  * autoload anything outside of the HPCloud namespace.
255  *
256  * Because this is a special-purpose autoloader, it
257  * should be safe to use with other special-purpose
258  * autoloaders (and also projects that don't
259  * rely upon autoloaders).
260  *
261  * @param string $klass
262  * The fully qualified name of the class to be autoloaded.
263  */
264  public static function autoload($klass) {
265  $components = explode('\\', $klass);
266  if (empty($components[0])) {
267  array_shift($components);
268  }
269 
270  // This class loader ONLY loads
271  // our classes. A general purpose
272  // classloader should be used for
273  // more sophisticated needs.
274  if ($components[0] != 'HPCloud') {
275  return;
276  }
277 
278  // We need the path up to, but not including, the root HPCloud dir:
279  $loc = DIRECTORY_SEPARATOR . 'HPCloud';
280  $local_path = substr(self::$basedir, 0, strrpos(self::$basedir, $loc));
281 
282  array_unshift($components, $local_path);
283  $path = implode(DIRECTORY_SEPARATOR, $components) . '.php';
284 
285  if (file_exists($path)) {
286  require $path;
287  return;
288  }
289  }
290 
291  /**
292  * Get a configuration option.
293  *
294  * Get a configuration option by name, with an optional default.
295  *
296  * @param string $name
297  * The name of the configuration option to get.
298  * @param mixed $default
299  * The default value to return if the name is not found.
300  * @retval mixed
301  * @return mixed
302  * The value, if found; or the default, if set; or NULL.
303  */
304  public static function config($name = NULL, $default = NULL) {
305 
306  // If no name is specified, return the entire config array.
307  if (empty($name)) {
308  return self::$config;
309  }
310 
311  // If the config value exists, return that.
312  if (isset(self::$config[$name])) {
313  return self::$config[$name];
314  }
315 
316  // Otherwise, just return the default value.
317  return $default;
318  }
319 
320  /**
321  * Check whether the given configuration option is set.
322  *
323  * @code
324  * if (Bootstrap::hasConfig('transport')) {
325  * syslog(LOG_INFO, 'An alternate transport is supplied.');
326  * }
327  * @endcode
328  *
329  * @param string $name
330  * The name of the item to check for.
331  * @retval boolean
332  * @return boolean
333  * TRUE if the named option is set, FALSE otherwise. Note that the value may
334  * be falsey (FALSE, 0, etc.), but if the value is NULL, this will return
335  * false.
336  */
337  public static function hasConfig($name) {
338  return isset(self::$config[$name]);
339  }
340 
341  /**
342  * Get a HPCloud::Services::IdentityService object from the bootstrap config.
343  *
344  * A factory helper function that uses the bootstrap configuration to create
345  * a ready to use HPCloud::Services::IdentityService object.
346  *
347  * @param bool $force
348  * Whether to force the generation of a new object even if one is already
349  * cached.
350  * @retval HPCloud::Services::IdentityService
351  * @return \HPCloud\Services\:IdentityService
352  * An authenticated ready to use HPCloud::Services::IdentityService object.
353  * @throws HPCloud::Exception
354  * When the needed configuration to authenticate is not available.
355  */
356  public static function identity($force = FALSE) {
357 
358  // If we already have an identity make sure the token is not expired.
359  if ($force || is_null(self::$identity) || self::$identity->isExpired()) {
360 
361  // Make sure we have an endpoint to use
362  if (!self::hasConfig('endpoint')) {
363  throw new Exception('Unable to authenticate. No endpoint supplied.');
364  }
365 
366  // Neither user nor account can be an empty string, so we need
367  // to do more checking than self::hasConfig(), which returns TRUE
368  // if an item exists and is an empty string.
369  $user = self::config('username', NULL);
370  $account = self::config('account', NULL);
371 
372  // Check if we have a username/password
373  if (!empty($user) && self::hasConfig('password')) {
374  $is = new IdentityServices(self::config('endpoint'));
375  $is->authenticateAsUser($user, self::config('password'), self::config('tenantid', NULL), self::config('tenantname', NULL));
376  self::$identity = $is;
377  }
378 
379  // Otherwise we go with access/secret keys
380  elseif (!empty($account) && self::hasConfig('secret')) {
381  $is = new IdentityServices(self::config('endpoint'));
382  $is->authenticateAsAccount($account, self::config('secret'), self::config('tenantid', NULL), self::config('tenantname', NULL));
383  self::$identity = $is;
384  }
385 
386  else {
387  throw new Exception('Unable to authenticate. No account credentials supplied.');
388  }
389  }
390 
391  return self::$identity;
392  }
393 }