PageRenderTime 30ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/sdk.class.php

http://github.com/amazonwebservices/aws-sdk-for-php
PHP | 1517 lines | 759 code | 217 blank | 541 comment | 91 complexity | 33280643dbfff0c0cd292d5759b2205e MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause-No-Nuclear-License-2014, BSD-3-Clause
  1. <?php
  2. /*
  3. * Copyright 2010-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License").
  6. * You may not use this file except in compliance with the License.
  7. * A copy of the License is located at
  8. *
  9. * http://aws.amazon.com/apache2.0
  10. *
  11. * or in the "license" file accompanying this file. This file is distributed
  12. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  13. * express or implied. See the License for the specific language governing
  14. * permissions and limitations under the License.
  15. */
  16. /*%******************************************************************************************%*/
  17. // EXCEPTIONS
  18. /**
  19. * Default CFRuntime Exception.
  20. */
  21. class CFRuntime_Exception extends Exception {}
  22. /**
  23. * Parsing Exception.
  24. */
  25. class Parser_Exception extends Exception {}
  26. /*%******************************************************************************************%*/
  27. // INTERMEDIARY CONSTANTS
  28. define('CFRUNTIME_NAME', 'aws-sdk-php');
  29. define('CFRUNTIME_VERSION', '1.6.2');
  30. define('CFRUNTIME_BUILD', '20130314130000');
  31. $user_agent = sprintf('%s/%s PHP/%s', CFRUNTIME_NAME, CFRUNTIME_VERSION, PHP_VERSION);
  32. if (function_exists('curl_version'))
  33. {
  34. $curl_version = curl_version();
  35. $user_agent .= ' curl/' . $curl_version['version'];
  36. }
  37. if (defined('OPENSSL_VERSION_TEXT'))
  38. {
  39. $openssl_version = explode(' ', OPENSSL_VERSION_TEXT);
  40. $user_agent .= ' openssl/' . $openssl_version[1];
  41. }
  42. define('CFRUNTIME_USERAGENT', $user_agent);
  43. unset($user_agent);
  44. /*%******************************************************************************************%*/
  45. // CLASS
  46. /**
  47. * Core functionality and default settings shared across all SDK classes. All methods and properties in this
  48. * class are inherited by the service-specific classes.
  49. *
  50. * @version 2012.05.25
  51. * @license See the included NOTICE.md file for more information.
  52. * @copyright See the included NOTICE.md file for more information.
  53. * @link http://aws.amazon.com/php/ PHP Developer Center
  54. */
  55. class CFRuntime
  56. {
  57. /*%******************************************************************************************%*/
  58. // CONSTANTS
  59. /**
  60. * Name of the software.
  61. */
  62. const NAME = CFRUNTIME_NAME;
  63. /**
  64. * Version of the software.
  65. */
  66. const VERSION = CFRUNTIME_VERSION;
  67. /**
  68. * Build ID of the software.
  69. */
  70. const BUILD = CFRUNTIME_BUILD;
  71. /**
  72. * User agent string used to identify the software.
  73. */
  74. const USERAGENT = CFRUNTIME_USERAGENT;
  75. /*%******************************************************************************************%*/
  76. // PROPERTIES
  77. /**
  78. * The Amazon API Key.
  79. */
  80. public $key;
  81. /**
  82. * The Amazon API Secret Key.
  83. */
  84. public $secret_key;
  85. /**
  86. * The Amazon Authentication Token.
  87. */
  88. public $auth_token;
  89. /**
  90. * Handle for the utility functions.
  91. */
  92. public $util;
  93. /**
  94. * An identifier for the current AWS service.
  95. */
  96. public $service = null;
  97. /**
  98. * The supported API version.
  99. */
  100. public $api_version = null;
  101. /**
  102. * The state of whether auth should be handled as AWS Query.
  103. */
  104. public $use_aws_query = true;
  105. /**
  106. * The default class to use for utilities (defaults to <CFUtilities>).
  107. */
  108. public $utilities_class = 'CFUtilities';
  109. /**
  110. * The default class to use for HTTP requests (defaults to <CFRequest>).
  111. */
  112. public $request_class = 'CFRequest';
  113. /**
  114. * The default class to use for HTTP responses (defaults to <CFResponse>).
  115. */
  116. public $response_class = 'CFResponse';
  117. /**
  118. * The default class to use for parsing XML (defaults to <CFSimpleXML>).
  119. */
  120. public $parser_class = 'CFSimpleXML';
  121. /**
  122. * The default class to use for handling batch requests (defaults to <CFBatchRequest>).
  123. */
  124. public $batch_class = 'CFBatchRequest';
  125. /**
  126. * The state of SSL/HTTPS use.
  127. */
  128. public $use_ssl = true;
  129. /**
  130. * The state of SSL certificate verification.
  131. */
  132. public $ssl_verification = true;
  133. /**
  134. * The proxy to use for connecting.
  135. */
  136. public $proxy = null;
  137. /**
  138. * The alternate hostname to use, if any.
  139. */
  140. public $hostname = null;
  141. /**
  142. * The state of the capability to override the hostname with <set_hostname()>.
  143. */
  144. public $override_hostname = true;
  145. /**
  146. * The alternate port number to use, if any.
  147. */
  148. public $port_number = null;
  149. /**
  150. * The alternate resource prefix to use, if any.
  151. */
  152. public $resource_prefix = null;
  153. /**
  154. * The state of cache flow usage.
  155. */
  156. public $use_cache_flow = false;
  157. /**
  158. * The caching class to use.
  159. */
  160. public $cache_class = null;
  161. /**
  162. * The caching location to use.
  163. */
  164. public $cache_location = null;
  165. /**
  166. * When the cache should be considered stale.
  167. */
  168. public $cache_expires = null;
  169. /**
  170. * The state of cache compression.
  171. */
  172. public $cache_compress = null;
  173. /**
  174. * The current instantiated cache object.
  175. */
  176. public $cache_object = null;
  177. /**
  178. * The current instantiated batch request object.
  179. */
  180. public $batch_object = null;
  181. /**
  182. * The internally instantiated batch request object.
  183. */
  184. public $internal_batch_object = null;
  185. /**
  186. * The state of batch flow usage.
  187. */
  188. public $use_batch_flow = false;
  189. /**
  190. * The state of the cache deletion setting.
  191. */
  192. public $delete_cache = false;
  193. /**
  194. * The state of the debug mode setting.
  195. */
  196. public $debug_mode = false;
  197. /**
  198. * The number of times to retry failed requests.
  199. */
  200. public $max_retries = 3;
  201. /**
  202. * The user-defined callback function to call when a stream is read from.
  203. */
  204. public $registered_streaming_read_callback = null;
  205. /**
  206. * The user-defined callback function to call when a stream is written to.
  207. */
  208. public $registered_streaming_write_callback = null;
  209. /**
  210. * The credentials to use for authentication.
  211. */
  212. public $credentials = array();
  213. /**
  214. * The authentication class to use.
  215. */
  216. public $auth_class = null;
  217. /**
  218. * The operation to execute.
  219. */
  220. public $operation = null;
  221. /**
  222. * The payload to send.
  223. */
  224. public $payload = array();
  225. /**
  226. * The string prefix to prepend to the operation name.
  227. */
  228. public $operation_prefix = '';
  229. /**
  230. * The number of times a request has been retried.
  231. */
  232. public $redirects = 0;
  233. /**
  234. * The state of whether the response should be parsed or not.
  235. */
  236. public $parse_the_response = true;
  237. /*%******************************************************************************************%*/
  238. // CONSTRUCTOR
  239. /**
  240. * The constructor. This class should not be instantiated directly. Rather, a service-specific class
  241. * should be instantiated.
  242. *
  243. * @param array $options (Optional) An associative array of parameters that can have the following keys: <ul>
  244. * <li><code>certificate_authority</code> - <code>boolean</code> - Optional - Determines which Cerificate Authority file to use. A value of boolean <code>false</code> will use the Certificate Authority file available on the system. A value of boolean <code>true</code> will use the Certificate Authority provided by the SDK. Passing a file system path to a Certificate Authority file (chmodded to <code>0755</code>) will use that. Leave this set to <code>false</code> if you're not sure.</li>
  245. * <li><code>credentials</code> - <code>string</code> - Optional - The name of the credential set to use for authentication.</li>
  246. * <li><code>default_cache_config</code> - <code>string</code> - Optional - This option allows a preferred storage type to be configured for long-term caching. This can be changed later using the <set_cache_config()> method. Valid values are: <code>apc</code>, <code>xcache</code>, or a file system path such as <code>./cache</code> or <code>/tmp/cache/</code>.</li>
  247. * <li><code>key</code> - <code>string</code> - Optional - Your AWS key, or a session key. If blank, the default credential set will be used.</li>
  248. * <li><code>instance_profile_timeout</code> - <code>integer</code> - Optional - When retrieving IAM instance profile credentials, there is a hard connection timeout that defaults to 2 seconds to prevent unnecessary on non-EC2 systems. This setting allows you to change that timeout if needed.</li>
  249. * <li><code>secret</code> - <code>string</code> - Optional - Your AWS secret key, or a session secret key. If blank, the default credential set will be used.</li>
  250. * <li><code>token</code> - <code>string</code> - Optional - An AWS session token.</li>
  251. * <li><code>use_instance_profile_credentials</code> - <code>boolean</code> - Optional - Forces the use of IAM Instance Profile credentials, even when regular credentials are provided.</li></ul>
  252. * @return void
  253. */
  254. public function __construct(array $options = array())
  255. {
  256. // Instantiate the utilities class.
  257. $this->util = new $this->utilities_class();
  258. // Determine the current service.
  259. $this->service = get_class($this);
  260. // Create credentials based on the options
  261. $runtime_credentials = new CFCredential($options);
  262. $credentials_provided = false;
  263. // Retrieve a credential set from config.inc.php if it exists
  264. if (isset($options['credentials']))
  265. {
  266. // Use a specific credential set and merge with the runtime credentials
  267. $this->credentials = CFCredentials::get($options['credentials'])
  268. ->merge($runtime_credentials);
  269. }
  270. else
  271. {
  272. try
  273. {
  274. // Use the default credential set and merge with the runtime credentials
  275. $this->credentials = CFCredentials::get(CFCredentials::DEFAULT_KEY)
  276. ->merge($runtime_credentials);
  277. }
  278. catch (CFCredentials_Exception $e)
  279. {
  280. // Only the runtime credentials were provided
  281. $this->credentials = $runtime_credentials;
  282. }
  283. }
  284. // Check if keys were actually provided
  285. if (isset($this->credentials['key']) && isset($this->credentials['secret']))
  286. {
  287. $credentials_provided = true;
  288. }
  289. // Check for an instance profile credentials override
  290. if (isset($this->credentials['use_instance_profile_credentials']) && $this->credentials['use_instance_profile_credentials'])
  291. {
  292. $credentials_provided = false;
  293. }
  294. // Automatically enable whichever caching mechanism is set to default.
  295. $this->set_cache_config($this->credentials->default_cache_config);
  296. // If no credentials were provided, try to get them from the EC2 instance profile
  297. if (!$credentials_provided)
  298. {
  299. // Default caching mechanism is required
  300. if (!$this->credentials->default_cache_config)
  301. {
  302. // @codeCoverageIgnoreStart
  303. throw new CFCredentials_Exception('No credentials were provided. The SDK attempts to retrieve Instance '
  304. . 'Profile credentials from the EC2 Instance Metadata Service, but doing this requires the '
  305. . '"default_cache_config" option to be set in the config.inc.php file or constructor. In order to '
  306. . 'cache the retrieved credentials.');
  307. // @codeCoverageIgnoreEnd
  308. }
  309. // Instantiate and invoke the cache for instance profile credentials
  310. $cache = new $this->cache_class('instance_profile_credentials', $this->cache_location, 0, $this->cache_compress);
  311. if ($data = $cache->read())
  312. {
  313. $cache->expire_in((strtotime($data['expires']) - time()) * 0.85);
  314. }
  315. $instance_profile_credentials = $cache->response_manager(array($this, 'cache_instance_profile_credentials'), array($cache, $options));
  316. $this->credentials->key = $instance_profile_credentials['key'];
  317. $this->credentials->secret = $instance_profile_credentials['secret'];
  318. $this->credentials->token = $instance_profile_credentials['token'];
  319. }
  320. // Set internal credentials after they are resolved
  321. $this->key = $this->credentials->key;
  322. $this->secret_key = $this->credentials->secret;
  323. $this->auth_token = $this->credentials->token;
  324. }
  325. /**
  326. * Alternate approach to constructing a new instance. Supports chaining.
  327. *
  328. * @param array $options (Optional) An associative array of parameters that can have the following keys: <ul>
  329. * <li><code>certificate_authority</code> - <code>boolean</code> - Optional - Determines which Cerificate Authority file to use. A value of boolean <code>false</code> will use the Certificate Authority file available on the system. A value of boolean <code>true</code> will use the Certificate Authority provided by the SDK. Passing a file system path to a Certificate Authority file (chmodded to <code>0755</code>) will use that. Leave this set to <code>false</code> if you're not sure.</li>
  330. * <li><code>credentials</code> - <code>string</code> - Optional - The name of the credential set to use for authentication.</li>
  331. * <li><code>default_cache_config</code> - <code>string</code> - Optional - This option allows a preferred storage type to be configured for long-term caching. This can be changed later using the <set_cache_config()> method. Valid values are: <code>apc</code>, <code>xcache</code>, or a file system path such as <code>./cache</code> or <code>/tmp/cache/</code>.</li>
  332. * <li><code>key</code> - <code>string</code> - Optional - Your AWS key, or a session key. If blank, the default credential set will be used.</li>
  333. * <li><code>secret</code> - <code>string</code> - Optional - Your AWS secret key, or a session secret key. If blank, the default credential set will be used.</li>
  334. * <li><code>token</code> - <code>string</code> - Optional - An AWS session token.</li></ul>
  335. * @return void
  336. */
  337. public static function factory(array $options = array())
  338. {
  339. if (version_compare(PHP_VERSION, '5.3.0', '<'))
  340. {
  341. throw new Exception('PHP 5.3 or newer is required to instantiate a new class with CLASS::factory().');
  342. }
  343. $self = get_called_class();
  344. return new $self($options);
  345. }
  346. /*%******************************************************************************************%*/
  347. // MAGIC METHODS
  348. /**
  349. * A magic method that allows `camelCase` method names to be translated into `snake_case` names.
  350. *
  351. * @param string $name (Required) The name of the method.
  352. * @param array $arguments (Required) The arguments passed to the method.
  353. * @return mixed The results of the intended method.
  354. */
  355. public function __call($name, $arguments)
  356. {
  357. // Convert camelCase method calls to snake_case.
  358. $method_name = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $name));
  359. if (method_exists($this, $method_name))
  360. {
  361. return call_user_func_array(array($this, $method_name), $arguments);
  362. }
  363. throw new CFRuntime_Exception('The method ' . $name . '() is undefined. Attempted to map to ' . $method_name . '() which is also undefined. Error occurred');
  364. }
  365. /*%******************************************************************************************%*/
  366. // SET CUSTOM SETTINGS
  367. /**
  368. * Set the proxy settings to use.
  369. *
  370. * @param string $proxy (Required) Accepts proxy credentials in the following format: `proxy://user:pass@hostname:port`
  371. * @return $this A reference to the current instance.
  372. */
  373. public function set_proxy($proxy)
  374. {
  375. $this->proxy = $proxy;
  376. return $this;
  377. }
  378. /**
  379. * Set the hostname to connect to. This is useful for alternate services that are API-compatible with
  380. * AWS, but run from a different hostname.
  381. *
  382. * @param string $hostname (Required) The alternate hostname to use in place of the default one. Useful for mock or test applications living on different hostnames.
  383. * @param integer $port_number (Optional) The alternate port number to use in place of the default one. Useful for mock or test applications living on different port numbers.
  384. * @return $this A reference to the current instance.
  385. */
  386. public function set_hostname($hostname, $port_number = null)
  387. {
  388. if ($this->override_hostname)
  389. {
  390. $this->hostname = $hostname;
  391. if ($port_number)
  392. {
  393. $this->port_number = $port_number;
  394. $this->hostname .= ':' . (string) $this->port_number;
  395. }
  396. }
  397. return $this;
  398. }
  399. /**
  400. * Set the resource prefix to use. This method is useful for alternate services that are API-compatible
  401. * with AWS.
  402. *
  403. * @param string $prefix (Required) An alternate prefix to prepend to the resource path. Useful for mock or test applications.
  404. * @return $this A reference to the current instance.
  405. */
  406. public function set_resource_prefix($prefix)
  407. {
  408. $this->resource_prefix = $prefix;
  409. return $this;
  410. }
  411. /**
  412. * Disables any subsequent use of the <set_hostname()> method.
  413. *
  414. * @param boolean $override (Optional) Whether or not subsequent calls to <set_hostname()> should be obeyed. A `false` value disables the further effectiveness of <set_hostname()>. Defaults to `true`.
  415. * @return $this A reference to the current instance.
  416. */
  417. public function allow_hostname_override($override = true)
  418. {
  419. $this->override_hostname = $override;
  420. return $this;
  421. }
  422. /**
  423. * Disables SSL/HTTPS connections for hosts that don't support them. Some services, however, still
  424. * require SSL support.
  425. *
  426. * This method will throw a user warning when invoked, which can be hidden by changing your
  427. * <php:error_reporting()> settings.
  428. *
  429. * @return $this A reference to the current instance.
  430. */
  431. public function disable_ssl()
  432. {
  433. trigger_error('Disabling SSL connections is potentially unsafe and highly discouraged.', E_USER_WARNING);
  434. $this->use_ssl = false;
  435. return $this;
  436. }
  437. /**
  438. * Disables the verification of the SSL Certificate Authority. Doing so can enable an attacker to carry
  439. * out a man-in-the-middle attack.
  440. *
  441. * https://secure.wikimedia.org/wikipedia/en/wiki/Man-in-the-middle_attack
  442. *
  443. * This method will throw a user warning when invoked, which can be hidden by changing your
  444. * <php:error_reporting()> settings.
  445. *
  446. * @return $this A reference to the current instance.
  447. */
  448. public function disable_ssl_verification($ssl_verification = false)
  449. {
  450. trigger_error('Disabling the verification of SSL certificates can lead to man-in-the-middle attacks. It is potentially unsafe and highly discouraged.', E_USER_WARNING);
  451. $this->ssl_verification = $ssl_verification;
  452. return $this;
  453. }
  454. /**
  455. * Enables HTTP request/response header logging to `STDERR`.
  456. *
  457. * @param boolean $enabled (Optional) Whether or not to enable debug mode. Defaults to `true`.
  458. * @return $this A reference to the current instance.
  459. */
  460. public function enable_debug_mode($enabled = true)
  461. {
  462. $this->debug_mode = $enabled;
  463. return $this;
  464. }
  465. /**
  466. * Sets the maximum number of times to retry failed requests.
  467. *
  468. * @param integer $retries (Optional) The maximum number of times to retry failed requests. Defaults to `3`.
  469. * @return $this A reference to the current instance.
  470. */
  471. public function set_max_retries($retries = 3)
  472. {
  473. $this->max_retries = $retries;
  474. return $this;
  475. }
  476. /**
  477. * Set the caching configuration to use for response caching.
  478. *
  479. * @param string $location (Required) <p>The location to store the cache object in. This may vary by cache method.</p><ul><li>File - The local file system paths such as <code>./cache</code> (relative) or <code>/tmp/cache/</code> (absolute). The location must be server-writable.</li><li>APC - Pass in <code>apc</code> to use this lightweight cache. You must have the <a href="http://php.net/apc">APC extension</a> installed.</li><li>XCache - Pass in <code>xcache</code> to use this lightweight cache. You must have the <a href="http://xcache.lighttpd.net">XCache</a> extension installed.</li><li>Memcached - Pass in an indexed array of associative arrays. Each associative array should have a <code>host</code> and a <code>port</code> value representing a <a href="http://php.net/memcached">Memcached</a> server to connect to.</li><li>PDO - A URL-style string (e.g. <code>pdo.mysql://user:pass@localhost/cache</code>) or a standard DSN-style string (e.g. <code>pdo.sqlite:/sqlite/cache.db</code>). MUST be prefixed with <code>pdo.</code>. See <code>CachePDO</code> and <a href="http://php.net/pdo">PDO</a> for more details.</li></ul>
  480. * @param boolean $gzip (Optional) Whether or not data should be gzipped before being stored. A value of `true` will compress the contents before caching them. A value of `false` will leave the contents uncompressed. Defaults to `true`.
  481. * @return $this A reference to the current instance.
  482. */
  483. public function set_cache_config($location, $gzip = true)
  484. {
  485. // If location is empty, don't do anything.
  486. if (empty($location))
  487. {
  488. return $this;
  489. }
  490. // If we have an array, we're probably passing in Memcached servers and ports.
  491. if (is_array($location))
  492. {
  493. $this->cache_class = 'CacheMC';
  494. }
  495. else
  496. {
  497. // I would expect locations like `/tmp/cache`, `pdo.mysql://user:pass@hostname:port`, `pdo.sqlite:memory:`, and `apc`.
  498. $type = strtolower(substr($location, 0, 3));
  499. switch ($type)
  500. {
  501. case 'apc':
  502. $this->cache_class = 'CacheAPC';
  503. break;
  504. case 'xca': // First three letters of `xcache`
  505. $this->cache_class = 'CacheXCache';
  506. break;
  507. case 'pdo':
  508. $this->cache_class = 'CachePDO';
  509. $location = substr($location, 4);
  510. break;
  511. default:
  512. $this->cache_class = 'CacheFile';
  513. break;
  514. }
  515. }
  516. // Set the remaining cache information.
  517. $this->cache_location = $location;
  518. $this->cache_compress = $gzip;
  519. return $this;
  520. }
  521. /**
  522. * Register a callback function to execute whenever a data stream is read from using
  523. * <CFRequest::streaming_read_callback()>.
  524. *
  525. * The user-defined callback function should accept three arguments:
  526. *
  527. * <ul>
  528. * <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li>
  529. * <li><code>$file_handle</code> - <code>resource</code> - Required - The file handle resource that represents the file on the local file system.</li>
  530. * <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li>
  531. * </ul>
  532. *
  533. * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul>
  534. * <li>The name of a global function to execute, passed as a string.</li>
  535. * <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li>
  536. * <li>An anonymous function (PHP 5.3+).</li></ul>
  537. * @return $this A reference to the current instance.
  538. */
  539. public function register_streaming_read_callback($callback)
  540. {
  541. $this->registered_streaming_read_callback = $callback;
  542. return $this;
  543. }
  544. /**
  545. * Register a callback function to execute whenever a data stream is written to using
  546. * <CFRequest::streaming_write_callback()>.
  547. *
  548. * The user-defined callback function should accept two arguments:
  549. *
  550. * <ul>
  551. * <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li>
  552. * <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li>
  553. * </ul>
  554. *
  555. * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul>
  556. * <li>The name of a global function to execute, passed as a string.</li>
  557. * <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li>
  558. * <li>An anonymous function (PHP 5.3+).</li></ul>
  559. * @return $this A reference to the current instance.
  560. */
  561. public function register_streaming_write_callback($callback)
  562. {
  563. $this->registered_streaming_write_callback = $callback;
  564. return $this;
  565. }
  566. /**
  567. * Fetches and caches STS credentials. This is meant to be used by the constructor, and is not to be
  568. * manually invoked.
  569. *
  570. * @param CacheCore $cache (Required) The a reference to the cache object that is being used to handle the caching.
  571. * @param array $options (Required) The options that were passed into the constructor.
  572. * @return mixed The data to be cached, or NULL.
  573. */
  574. public function cache_sts_credentials($cache, $options)
  575. {
  576. $token = new AmazonSTS($options);
  577. $response = $token->get_session_token();
  578. if ($response->isOK())
  579. {
  580. // Update the expiration
  581. $expiration_time = strtotime((string) $response->body->GetSessionTokenResult->Credentials->Expiration);
  582. $expiration_duration = round(($expiration_time - time()) * 0.85);
  583. $cache->expire_in($expiration_duration);
  584. // Return the important data
  585. $credentials = $response->body->GetSessionTokenResult->Credentials;
  586. return array(
  587. 'key' => (string) $credentials->AccessKeyId,
  588. 'secret' => (string) $credentials->SecretAccessKey,
  589. 'token' => (string) $credentials->SessionToken,
  590. 'expires' => (string) $credentials->Expiration,
  591. );
  592. }
  593. // @codeCoverageIgnoreStart
  594. throw new STS_Exception('Temporary credentials from the AWS Security '
  595. . 'Token Service could not be retrieved using the provided long '
  596. . 'term credentials. It\'s possible that the provided long term '
  597. . 'credentials were invalid.');
  598. // @codeCoverageIgnoreEnd
  599. }
  600. /**
  601. * Fetches and caches EC2 instance profile credentials. This is meant to be used by the constructor, and is not to
  602. * be manually invoked.
  603. *
  604. * @param CacheCore $cache (Required) The a reference to the cache object that is being used to handle the caching.
  605. * @param array $options (Required) The options that were passed into the constructor.
  606. * @return mixed The data to be cached, or NULL.
  607. */
  608. public function cache_instance_profile_credentials($cache, $options)
  609. {
  610. $instance_profile_url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/';
  611. $connect_timeout = isset($options['instance_profile_timeout']) ? $options['instance_profile_timeout'] : 2;
  612. try
  613. {
  614. // Make a call to the EC2 Metadata Service to find the available instance profile
  615. $request = new RequestCore($instance_profile_url);
  616. $request->set_curlopts(array(CURLOPT_CONNECTTIMEOUT => $connect_timeout));
  617. $response = $request->send_request(true);
  618. if ($response->isOK())
  619. {
  620. // Get the instance profile name
  621. $profile = (string) $response->body;
  622. // Make a call to the EC2 Metadata Service to get the instance profile credentials
  623. $request = new RequestCore($instance_profile_url . $profile);
  624. $request->set_curlopts(array(CURLOPT_CONNECTTIMEOUT => $connect_timeout));
  625. $response = $request->send_request(true);
  626. if ($response->isOK())
  627. {
  628. // Get the credentials
  629. $credentials = json_decode($response->body, true);
  630. if ($credentials['Code'] === 'Success')
  631. {
  632. // Determine the expiration time
  633. $expiration_time = strtotime((string) $credentials['Expiration']);
  634. $expiration_duration = round(($expiration_time - time()) * 0.85);
  635. $cache->expire_in($expiration_duration);
  636. // Return the credential information
  637. return array(
  638. 'key' => $credentials['AccessKeyId'],
  639. 'secret' => $credentials['SecretAccessKey'],
  640. 'token' => $credentials['Token'],
  641. 'expires' => $credentials['Expiration'],
  642. );
  643. }
  644. }
  645. }
  646. }
  647. catch (cURL_Exception $e)
  648. {
  649. // The EC2 Metadata Service does not exist or had timed out.
  650. // An exception will be thrown on the next line.
  651. }
  652. // @codeCoverageIgnoreStart
  653. throw new CFCredentials_Exception('No credentials were provided. The SDK attempted to retrieve Instance '
  654. . 'Profile credentials from the EC2 Instance Metadata Service, but failed to do so. Instance profile '
  655. . 'credentials are only accessible on EC2 instances configured with a specific IAM role.');
  656. // @codeCoverageIgnoreEnd
  657. }
  658. /*%******************************************************************************************%*/
  659. // SET CUSTOM CLASSES
  660. /**
  661. * Set a custom class for this functionality. Use this method when extending/overriding existing classes
  662. * with new functionality.
  663. *
  664. * The replacement class must extend from <CFUtilities>.
  665. *
  666. * @param string $class (Optional) The name of the new class to use for this functionality.
  667. * @return $this A reference to the current instance.
  668. */
  669. public function set_utilities_class($class = 'CFUtilities')
  670. {
  671. $this->utilities_class = $class;
  672. $this->util = new $this->utilities_class();
  673. return $this;
  674. }
  675. /**
  676. * Set a custom class for this functionality. Use this method when extending/overriding existing classes
  677. * with new functionality.
  678. *
  679. * The replacement class must extend from <CFRequest>.
  680. *
  681. * @param string $class (Optional) The name of the new class to use for this functionality.
  682. * @param $this A reference to the current instance.
  683. */
  684. public function set_request_class($class = 'CFRequest')
  685. {
  686. $this->request_class = $class;
  687. return $this;
  688. }
  689. /**
  690. * Set a custom class for this functionality. Use this method when extending/overriding existing classes
  691. * with new functionality.
  692. *
  693. * The replacement class must extend from <CFResponse>.
  694. *
  695. * @param string $class (Optional) The name of the new class to use for this functionality.
  696. * @return $this A reference to the current instance.
  697. */
  698. public function set_response_class($class = 'CFResponse')
  699. {
  700. $this->response_class = $class;
  701. return $this;
  702. }
  703. /**
  704. * Set a custom class for this functionality. Use this method when extending/overriding existing classes
  705. * with new functionality.
  706. *
  707. * The replacement class must extend from <CFSimpleXML>.
  708. *
  709. * @param string $class (Optional) The name of the new class to use for this functionality.
  710. * @return $this A reference to the current instance.
  711. */
  712. public function set_parser_class($class = 'CFSimpleXML')
  713. {
  714. $this->parser_class = $class;
  715. return $this;
  716. }
  717. /**
  718. * Set a custom class for this functionality. Use this method when extending/overriding existing classes
  719. * with new functionality.
  720. *
  721. * The replacement class must extend from <CFBatchRequest>.
  722. *
  723. * @param string $class (Optional) The name of the new class to use for this functionality.
  724. * @return $this A reference to the current instance.
  725. */
  726. public function set_batch_class($class = 'CFBatchRequest')
  727. {
  728. $this->batch_class = $class;
  729. return $this;
  730. }
  731. /*%******************************************************************************************%*/
  732. // AUTHENTICATION
  733. /**
  734. * Default, shared method for authenticating a connection to AWS.
  735. *
  736. * @param string $operation (Required) Indicates the operation to perform.
  737. * @param array $payload (Required) An associative array of parameters for authenticating. See the individual methods for allowed keys.
  738. * @return CFResponse Object containing a parsed HTTP response.
  739. */
  740. public function authenticate($operation, $payload)
  741. {
  742. $original_payload = $payload;
  743. $method_arguments = func_get_args();
  744. $curlopts = array();
  745. $return_curl_handle = false;
  746. if (substr($operation, 0, strlen($this->operation_prefix)) !== $this->operation_prefix)
  747. {
  748. $operation = $this->operation_prefix . $operation;
  749. }
  750. // Extract the custom CURLOPT settings from the payload
  751. if (is_array($payload) && isset($payload['curlopts']))
  752. {
  753. $curlopts = $payload['curlopts'];
  754. unset($payload['curlopts']);
  755. }
  756. // Determine whether the response or curl handle should be returned
  757. if (is_array($payload) && isset($payload['returnCurlHandle']))
  758. {
  759. $return_curl_handle = isset($payload['returnCurlHandle']) ? $payload['returnCurlHandle'] : false;
  760. unset($payload['returnCurlHandle']);
  761. }
  762. // Use the caching flow to determine if we need to do a round-trip to the server.
  763. if ($this->use_cache_flow)
  764. {
  765. // Generate an identifier specific to this particular set of arguments.
  766. $cache_id = $this->key . '_' . get_class($this) . '_' . $operation . '_' . sha1(serialize($method_arguments));
  767. // Instantiate the appropriate caching object.
  768. $this->cache_object = new $this->cache_class($cache_id, $this->cache_location, $this->cache_expires, $this->cache_compress);
  769. if ($this->delete_cache)
  770. {
  771. $this->use_cache_flow = false;
  772. $this->delete_cache = false;
  773. return $this->cache_object->delete();
  774. }
  775. // Invoke the cache callback function to determine whether to pull data from the cache or make a fresh request.
  776. $data = $this->cache_object->response_manager(array($this, 'cache_callback'), $method_arguments);
  777. // Parse the XML body
  778. $data = $this->parse_callback($data);
  779. // End!
  780. return $data;
  781. }
  782. /*%******************************************************************************************%*/
  783. // Signer
  784. $signer = new $this->auth_class($this->hostname, $operation, $payload, $this->credentials);
  785. $signer->key = $this->key;
  786. $signer->secret_key = $this->secret_key;
  787. $signer->auth_token = $this->auth_token;
  788. $signer->api_version = $this->api_version;
  789. $signer->utilities_class = $this->utilities_class;
  790. $signer->request_class = $this->request_class;
  791. $signer->response_class = $this->response_class;
  792. $signer->use_ssl = $this->use_ssl;
  793. $signer->proxy = $this->proxy;
  794. $signer->util = $this->util;
  795. $signer->registered_streaming_read_callback = $this->registered_streaming_read_callback;
  796. $signer->registered_streaming_write_callback = $this->registered_streaming_write_callback;
  797. $request = $signer->authenticate();
  798. // Update RequestCore settings
  799. $request->request_class = $this->request_class;
  800. $request->response_class = $this->response_class;
  801. $request->ssl_verification = $this->ssl_verification;
  802. /*%******************************************************************************************%*/
  803. // Debug mode
  804. if ($this->debug_mode)
  805. {
  806. $request->debug_mode = $this->debug_mode;
  807. }
  808. // Set custom CURLOPT settings
  809. if (count($curlopts))
  810. {
  811. $request->set_curlopts($curlopts);
  812. }
  813. // Manage the (newer) batch request API or the (older) returnCurlHandle setting.
  814. if ($this->use_batch_flow)
  815. {
  816. $handle = $request->prep_request();
  817. $this->batch_object->add($handle);
  818. $this->use_batch_flow = false;
  819. return $handle;
  820. }
  821. elseif ($return_curl_handle)
  822. {
  823. return $request->prep_request();
  824. }
  825. // Send!
  826. $request->send_request();
  827. // Prepare the response.
  828. $headers = $request->get_response_header();
  829. $headers['x-aws-stringtosign'] = $signer->string_to_sign;
  830. if (isset($signer->canonical_request))
  831. {
  832. $headers['x-aws-canonicalrequest'] = $signer->canonical_request;
  833. }
  834. $headers['x-aws-request-headers'] = $request->request_headers;
  835. $headers['x-aws-body'] = $signer->querystring;
  836. $data = new $this->response_class($headers, ($this->parse_the_response === true) ? $this->parse_callback($request->get_response_body()) : $request->get_response_body(), $request->get_response_code());
  837. $response_body = (string) $request->get_response_body();
  838. // Was it Amazon's fault the request failed? Retry the request until we reach $max_retries.
  839. if (
  840. (integer) $request->get_response_code() === 500 || // Internal Error (presumably transient)
  841. (integer) $request->get_response_code() === 503) // Service Unavailable (presumably transient)
  842. {
  843. if ($this->redirects <= $this->max_retries)
  844. {
  845. // Exponential backoff
  846. $delay = (integer) (pow(4, $this->redirects) * 100000);
  847. usleep($delay);
  848. $this->redirects++;
  849. $data = $this->authenticate($operation, $original_payload);
  850. }
  851. }
  852. // DynamoDB has additional, custom logic for retrying requests
  853. else
  854. {
  855. // If the request to DynamoDB was throttled, we need to retry
  856. $need_to_retry_dynamodb_request = (
  857. (integer) $request->get_response_code() === 400 &&
  858. stripos($response_body, 'com.amazonaws.dynamodb.') !== false &&
  859. stripos($response_body, 'ProvisionedThroughputExceededException') !== false
  860. );
  861. // If the CRC32 of the response does not match the expected value, we need to retry
  862. $response_headers = $request->get_response_header();
  863. if (!$need_to_retry_dynamodb_request && isset($response_headers['x-amz-crc32']))
  864. {
  865. $crc32_expected = $response_headers['x-amz-crc32'];
  866. $crc32_actual = hexdec(hash('crc32b', $response_body));
  867. $need_to_retry_dynamodb_request = ($crc32_expected != $crc32_actual);
  868. }
  869. // Perform retry if necessary using a more aggressive exponential backoff
  870. if ($need_to_retry_dynamodb_request)
  871. {
  872. if ($this->redirects === 0)
  873. {
  874. $this->redirects++;
  875. $data = $this->authenticate($operation, $original_payload);
  876. }
  877. elseif ($this->redirects <= max($this->max_retries, 10))
  878. {
  879. // Exponential backoff
  880. $delay = (integer) (pow(2, ($this->redirects - 1)) * 50000);
  881. usleep($delay);
  882. $this->redirects++;
  883. $data = $this->authenticate($operation, $original_payload);
  884. }
  885. }
  886. }
  887. $this->redirects = 0;
  888. return $data;
  889. }
  890. /*%******************************************************************************************%*/
  891. // BATCH REQUEST LAYER
  892. /**
  893. * Specifies that the intended request should be queued for a later batch request.
  894. *
  895. * @param CFBatchRequest $queue (Optional) The <CFBatchRequest> instance to use for managing batch requests. If not available, it generates a new instance of <CFBatchRequest>.
  896. * @return $this A reference to the current instance.
  897. */
  898. public function batch(CFBatchRequest &$queue = null)
  899. {
  900. if ($queue)
  901. {
  902. $this->batch_object = $queue;
  903. }
  904. elseif ($this->internal_batch_object)
  905. {
  906. $this->batch_object = &$this->internal_batch_object;
  907. }
  908. else
  909. {
  910. $this->internal_batch_object = new $this->batch_class();
  911. $this->batch_object = &$this->internal_batch_object;
  912. }
  913. $this->use_batch_flow = true;
  914. return $this;
  915. }
  916. /**
  917. * Executes the batch request queue by sending all queued requests.
  918. *
  919. * @param boolean $clear_after_send (Optional) Whether or not to clear the batch queue after sending a request. Defaults to `true`. Set this to `false` if you are caching batch responses and want to retrieve results later.
  920. * @return array An array of <CFResponse> objects.
  921. */
  922. public function send($clear_after_send = true)
  923. {
  924. if ($this->use_batch_flow)
  925. {
  926. // When we send the request, disable batch flow.
  927. $this->use_batch_flow = false;
  928. // If we're not caching, simply send the request.
  929. if (!$this->use_cache_flow)
  930. {
  931. $response = $this->batch_object->send();
  932. $parsed_data = array_map(array($this, 'parse_callback'), $response);
  933. $parsed_data = new CFArray($parsed_data);
  934. // Clear the queue
  935. if ($clear_after_send)
  936. {
  937. $this->batch_object->queue = array();
  938. }
  939. return $parsed_data;
  940. }
  941. // Generate an identifier specific to this particular set of arguments.
  942. $cache_id = $this->key . '_' . get_class($this) . '_' . sha1(serialize($this->batch_object));
  943. // Instantiate the appropriate caching object.
  944. $this->cache_object = new $this->cache_class($cache_id, $this->cache_location, $this->cache_expires, $this->cache_compress);
  945. if ($this->delete_cache)
  946. {
  947. $this->use_cache_flow = false;
  948. $this->delete_cache = false;
  949. return $this->cache_object->delete();
  950. }
  951. // Invoke the cache callback function to determine whether to pull data from the cache or make a fresh request.
  952. $data_set = $this->cache_object->response_manager(array($this, 'cache_callback_batch'), array($this->batch_object));
  953. $parsed_data = array_map(array($this, 'parse_callback'), $data_set);
  954. $parsed_data = new CFArray($parsed_data);
  955. // Clear the queue
  956. if ($clear_after_send)
  957. {
  958. $this->batch_object->queue = array();
  959. }
  960. // End!
  961. return $parsed_data;
  962. }
  963. // Load the class
  964. $null = new CFBatchRequest();
  965. unset($null);
  966. throw new CFBatchRequest_Exception('You must use $object->batch()->send()');
  967. }
  968. /**
  969. * Parses a response body into a PHP object if appropriate.
  970. *
  971. * @param CFResponse|string $response (Required) The <CFResponse> object to parse, or an XML string that would otherwise be a response body.
  972. * @param string $content_type (Optional) The content-type to use when determining how to parse the content.
  973. * @return CFResponse|string A parsed <CFResponse> object, or parsed XML.
  974. */
  975. public function parse_callback($response, $headers = null)
  976. {
  977. // Bail out
  978. if (!$this->parse_the_response) return $response;
  979. // Shorten this so we have a (mostly) single code path
  980. if (isset($response->body))
  981. {
  982. if (is_string($response->body))
  983. {
  984. $body = $response->body;
  985. }
  986. else
  987. {
  988. return $response;
  989. }
  990. }
  991. elseif (is_string($response))
  992. {
  993. $body = $response;
  994. }
  995. else
  996. {
  997. return $response;
  998. }
  999. // Decompress gzipped content
  1000. if (isset($headers['content-encoding']))
  1001. {
  1002. switch (strtolower(trim($headers['content-encoding'], "\x09\x0A\x0D\x20")))
  1003. {
  1004. case 'gzip':
  1005. case 'x-gzip':
  1006. $decoder = new CFGzipDecode($body);
  1007. if ($decoder->parse())
  1008. {
  1009. $body = $decoder->data;
  1010. }
  1011. break;
  1012. case 'deflate':
  1013. if (($uncompressed = gzuncompress($body)) !== false)
  1014. {
  1015. $body = $uncompressed;
  1016. }
  1017. elseif (($uncompressed = gzinflate($body)) !== false)
  1018. {
  1019. $body = $uncompressed;
  1020. }
  1021. break;
  1022. }
  1023. }
  1024. // Look for XML cues
  1025. if (
  1026. (isset($headers['content-type']) && ($headers['content-type'] === 'text/xml' || $headers['content-type'] === 'application/xml')) || // We know it's XML
  1027. (!isset($headers['content-type']) && (stripos($body, '<?xml') === 0 || strpos($body, '<Error>') === 0) || preg_match('/^<(\w*) xmlns="http(s?):\/\/(\w*).amazon(aws)?.com/im', $body)) // Sniff for XML
  1028. )
  1029. {
  1030. // Strip the default XML namespace to simplify XPath expressions
  1031. $body = str_replace("xmlns=", "ns=", $body);
  1032. try {
  1033. // Parse the XML body
  1034. $body = new $this->parser_class($body);
  1035. }
  1036. catch (Exception $e)
  1037. {
  1038. throw new Parser_Exception($e->getMessage());
  1039. }
  1040. }
  1041. // Look for JSON cues
  1042. elseif (
  1043. (isset($headers['content-type']) && ($headers['content-type'] === 'application/json') || $headers['content-type'] === 'application/x-amz-json-1.0') || // We know it's JSON
  1044. (!isset($headers['content-type']) && $this->util->is_json($body)) // Sniff for JSON
  1045. )
  1046. {
  1047. // Normalize JSON to a CFSimpleXML object
  1048. $body = CFJSON::to_xml($body, $this->parser_class);
  1049. }
  1050. // Put the parsed data back where it goes
  1051. if (isset($response->body))
  1052. {
  1053. $response->body = $body;
  1054. }
  1055. else
  1056. {
  1057. $response = $body;
  1058. }
  1059. return $response;
  1060. }
  1061. /*%******************************************************************************************%*/
  1062. // CACHING LAYER
  1063. /**
  1064. * Specifies that the resulting <CFResponse> object should be cached according to the settings from
  1065. * <set_cache_config()>.
  1066. *
  1067. * @param string|integer $expires (Required) The time the cache is to expire. Accepts a number of seconds as an integer, or an amount of time, as a string, that is understood by <php:strtotime()> (e.g. "1 hour").
  1068. * @return $this A reference to the current instance.
  1069. */
  1070. public function cache($expires)
  1071. {
  1072. // Die if they haven't used set_cache_config().
  1073. if (!$this->cache_class)
  1074. {
  1075. throw new CFRuntime_Exception('Must call set_cache_config() before using cache()');
  1076. }
  1077. if (is_string($expires))
  1078. {
  1079. $expires = strtotime($expires);
  1080. $this->cache_expires = $expires - time();
  1081. }
  1082. elseif (is_int($expires))
  1083. {
  1084. $this->cache_expires = $expires;
  1085. }
  1086. $this->use_cache_flow = true;
  1087. return $this;
  1088. }
  1089. /**
  1090. * The callback function that is executed when the cache doesn't exist or has expired. The response of
  1091. * this method is cached. Accepts identical parameters as the <authenticate()> method. Never call this
  1092. * method directly -- it is used internally by the caching system.
  1093. *
  1094. * @param string $operation (Required) Indicates the operation to perform.
  1095. * @param array $payload (Required) An associative array of parameters for authenticating. See the individual methods for allowed keys.
  1096. * @return CFResponse A parsed HTTP response.
  1097. */
  1098. public function cache_callback($operation, $payload)
  1099. {
  1100. // Disable the cache flow since it's already been handled.
  1101. $this->use_cache_flow = false;
  1102. // Make the request
  1103. $response = $this->authenticate($operation, $payload);
  1104. // If this is an XML document, convert it back to a string.
  1105. if (isset($response->body) && ($response->body instanceof SimpleXMLElement))
  1106. {
  1107. $response->body = $response->body->asXML();
  1108. }
  1109. return $response;
  1110. }
  1111. /**
  1112. * Used for caching the results of a batch request. Never call this method directly; it is used
  1113. * internally by the caching system.
  1114. *
  1115. * @param CFBatchRequest $batch (Required) The batch request object to send.
  1116. * @return CFResponse A parsed HTTP response.
  1117. */
  1118. public function cache_callback_batch(CFBatchRequest $batch)
  1119. {
  1120. return $batch->send();
  1121. }
  1122. /**
  1123. * Deletes a cached <CFResponse> object using the specified cache storage type.
  1124. *
  1125. * @return boolean A value of `true` if cached object exists and is successfully deleted, otherwise `false`.
  1126. */
  1127. public function delete_cache()
  1128. {
  1129. $this->use_cache_flow = true;
  1130. $this->delete_cache = true;
  1131. return $this;
  1132. }
  1133. }
  1134. /**
  1135. * Contains the functionality for auto-loading service classes.
  1136. */
  1137. class CFLoader
  1138. {
  1139. /*%******************************************************************************************%*/
  1140. // AUTO-LOADER
  1141. /**
  1142. * Automatically load classes that aren't included.
  1143. *
  1144. * @param string $class (Required) The classname to load.
  1145. * @return boolean Whether or not the file was successfully loaded.
  1146. */
  1147. public static function autoloader($class)
  1148. {
  1149. $path = dirname(__FILE__) . DIRECTORY_SEPARATOR;
  1150. // Amazon SDK classes
  1151. if (strstr($class, 'Amazon'))
  1152. {
  1153. if (file_exists($require_this = $path . 'services' . DIRECTORY_SEPARATOR . str_ireplace('Amazon', '', strtolower($class)) . '.class.php'))
  1154. {
  1155. require_once $require_this;
  1156. return true;
  1157. }
  1158. return false;
  1159. }
  1160. // Utility classes
  1161. elseif (strstr($class, 'CF'))
  1162. {
  1163. if (file_exists($require_this = $path . 'utilities' . DIRECTORY_SEPARATOR . str_ireplace('CF', '', strtolower($class)) . '.class.php'))
  1164. {
  1165. require_once $require_this;
  1166. return true;
  1167. }
  1168. return false;
  1169. }
  1170. // Load CacheCore
  1171. elseif (strstr($class, 'Cache'))
  1172. {
  1173. if (file_exists($require_this = $path . 'lib' . DIRECTORY_SEPARATOR . 'cachecore' . DIRECTORY_SEPARATOR . strtolower($class) . '.class.php'))
  1174. {
  1175. require_once $require_this;
  1176. return true;
  1177. }
  1178. return false;
  1179. }
  1180. // Load RequestCore
  1181. elseif (strstr($class, 'RequestCore') || strstr($class, 'ResponseCore'))
  1182. {
  1183. if (file_exists($require_this = $path . 'lib' . DIRECTORY_SEPARATOR . 'requestcore' . DIRECTORY_SEPARATOR . 'requestcore.class.php'))
  1184. {
  1185. require_once $require_this;
  1186. return true;
  1187. }
  1188. return false;
  1189. }
  1190. // Load Transmogrifier
  1191. elseif (strstr($class, 'Transmogrifier'))
  1192. {
  1193. if (file_exists($require_this = $path . 'lib' . DIRECTORY_SEPARATOR . 'dom' . DIRECTORY_SEPARATOR . 'Transmogrifier.php'))
  1194. {
  1195. require_once $require_this;
  1196. return true;
  1197. }
  1198. return false;
  1199. }
  1200. // Load Authentication Signers
  1201. elseif (strstr($class, 'Auth'))
  1202. {
  1203. if (file_exists($require_this = $path . 'authentication' . DIRECTORY_SEPARATOR . str_replace('auth', 'signature_', strtolower($class)) . '.class.php'))
  1204. {
  1205. require_once $require_this;
  1206. return true;
  1207. }
  1208. return false;
  1209. }
  1210. // Load Signer interface
  1211. elseif ($class === 'Signer')
  1212. {
  1213. if (!interface_exists('Signable', false) &&
  1214. file_exists($require_this = $path . 'authentication' . DIRECTORY_SEPARATOR . 'signable.interface.php'))
  1215. {
  1216. require_once $require_this;
  1217. }
  1218. if (file_exists($require_this = $path . 'authentication' . DIRECTORY_SEPARATOR . 'signer.abstract.php'))
  1219. {
  1220. require_once $require_this;
  1221. return true;
  1222. }
  1223. return false;
  1224. }
  1225. // Load Symfony YAML classes
  1226. elseif (strstr($class, 'sfYaml'))
  1227. {
  1228. if (file_exists($require_this = $path . 'lib' . DIRECTORY_SEPARATOR . 'yaml' . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'sfYaml.php'))
  1229. {
  1230. require_once $require_this;
  1231. return true;
  1232. }
  1233. return false;
  1234. }
  1235. return false;
  1236. }
  1237. }
  1238. // Register the autoloader.
  1239. spl_autoload_register(array('CFLoader', 'autoloader'));
  1240. /*%******************************************************************************************%*/
  1241. // CONFIGURATION
  1242. // If config auto-discovery is explicitly disabled, stop here
  1243. if (defined('AWS_DISABLE_CONFIG_AUTO_DISCOVERY')) return;
  1244. // Look for include file in the same directory (e.g. `./config.inc.php`).
  1245. if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.inc.php'))
  1246. {
  1247. include_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.inc.php';
  1248. }
  1249. // Fallback to `~/.aws/sdk/config.inc.php`
  1250. else
  1251. {
  1252. if (!isset($_ENV['HOME']) && isset($_SERVER['HOME']))
  1253. {
  1254. $_ENV['HOME'] = $_SERVER['HOME'];
  1255. }
  1256. elseif (!isset($_ENV['HOME']) && !isset($_SERVER['HOME']))
  1257. {
  1258. $os = strtolower(PHP_OS);
  1259. if (in_array($os, array('windows', 'winnt', 'win32')))
  1260. {
  1261. $_ENV['HOME'] = false;
  1262. }
  1263. else
  1264. {
  1265. $dir = exec('(cd ~ && pwd) 2>&1', $out, $exit);
  1266. if ($exit === 0)
  1267. {
  1268. $_ENV['HOME'] = trim($dir);
  1269. }
  1270. else
  1271. {
  1272. error_log('Failed to determine HOME directory after trying "' . $dir . '" (exit code ' . $exit . ')');
  1273. $_ENV['HOME'] = false;
  1274. }
  1275. }
  1276. if (!$_ENV['HOME'])
  1277. {
  1278. switch ($os)
  1279. {
  1280. case 'darwin':
  1281. $_ENV['HOME'] = '/Users/' . get_current_user();
  1282. break;
  1283. case 'windows':
  1284. case 'winnt':
  1285. case 'win32':
  1286. $_ENV['HOME'] = 'c:' . DIRECTORY_SEPARATOR . 'Documents and Settings' . DIRECTORY_SEPARATOR . get_current_user();
  1287. break;
  1288. default:
  1289. $_ENV['HOME'] = '/home/' . get_current_user();
  1290. break;
  1291. }
  1292. }
  1293. }
  1294. $path = DIRECTORY_SEPARATOR . '.aws' . DIRECTORY_SEPARATOR . 'sdk' . DIRECTORY_SEPARATOR . 'config.inc.php';
  1295. if (isset($_ENV['HOME']) && file_exists($_ENV['HOME'] . $path))
  1296. {
  1297. include_once $_ENV['HOME'] . $path;
  1298. }
  1299. unset($os, $dir, $out, $exit, $path);
  1300. }