PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/aws/sdk.class.php

https://bitbucket.org/ardydedase/web-build-optimizer
PHP | 1583 lines | 794 code | 227 blank | 562 comment | 113 complexity | 48d27356e2f5f0eeda2e77ae318bac66 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
  1. <?php
  2. /*
  3. * Copyright 2010-2011 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. // CORE DEPENDENCIES
  18. // Look for include file in the same directory (e.g. `./config.inc.php`).
  19. if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.inc.php'))
  20. {
  21. include_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.inc.php';
  22. }
  23. // Fallback to `~/.aws/sdk/config.inc.php`
  24. elseif (getenv('HOME') && file_exists(getenv('HOME') . DIRECTORY_SEPARATOR . '.aws' . DIRECTORY_SEPARATOR . 'sdk' . DIRECTORY_SEPARATOR . 'config.inc.php'))
  25. {
  26. include_once getenv('HOME') . DIRECTORY_SEPARATOR . '.aws' . DIRECTORY_SEPARATOR . 'sdk' . DIRECTORY_SEPARATOR . 'config.inc.php';
  27. }
  28. /*%******************************************************************************************%*/
  29. // EXCEPTIONS
  30. /**
  31. * Default CFRuntime Exception.
  32. */
  33. class CFRuntime_Exception extends Exception {}
  34. /*%******************************************************************************************%*/
  35. // DETERMINE WHAT ENVIRONMENT DATA TO ADD TO THE USERAGENT FOR METRIC TRACKING
  36. /*
  37. Define a temporary callback function for this calculation. Get the PHP version and any
  38. required/optional extensions that are leveraged.
  39. Tracking this data gives Amazon better metrics about what configurations are being used
  40. so that forward-looking plans for the code can be made with more certainty (e.g. What
  41. version of PHP are most people running? Do they tend to have the latest PCRE?).
  42. */
  43. function __aws_sdk_ua_callback()
  44. {
  45. $ua_append = '';
  46. $extensions = get_loaded_extensions();
  47. $sorted_extensions = array();
  48. if ($extensions)
  49. {
  50. foreach ($extensions as $extension)
  51. {
  52. if ($extension === 'curl' && function_exists('curl_version'))
  53. {
  54. $curl_version = curl_version();
  55. $sorted_extensions[strtolower($extension)] = $curl_version['version'];
  56. }
  57. elseif ($extension === 'pcre' && defined('PCRE_VERSION'))
  58. {
  59. $pcre_version = explode(' ', PCRE_VERSION);
  60. $sorted_extensions[strtolower($extension)] = $pcre_version[0];
  61. }
  62. elseif ($extension === 'openssl' && defined('OPENSSL_VERSION_TEXT'))
  63. {
  64. $openssl_version = explode(' ', OPENSSL_VERSION_TEXT);
  65. $sorted_extensions[strtolower($extension)] = $openssl_version[1];
  66. }
  67. else
  68. {
  69. $sorted_extensions[strtolower($extension)] = phpversion($extension);
  70. }
  71. }
  72. }
  73. foreach (array('simplexml', 'json', 'pcre', 'spl', 'curl', 'openssl', 'apc', 'xcache', 'memcache', 'memcached', 'pdo', 'pdo_sqlite', 'sqlite', 'sqlite3', 'zlib', 'xdebug') as $ua_ext)
  74. {
  75. if (isset($sorted_extensions[$ua_ext]) && $sorted_extensions[$ua_ext])
  76. {
  77. $ua_append .= ' ' . $ua_ext . '/' . $sorted_extensions[$ua_ext];
  78. }
  79. elseif (isset($sorted_extensions[$ua_ext]))
  80. {
  81. $ua_append .= ' ' . $ua_ext . '/0';
  82. }
  83. }
  84. foreach (array('memory_limit', 'date.timezone', 'open_basedir', 'safe_mode', 'zend.enable_gc') as $cfg)
  85. {
  86. $cfg_value = get_cfg_var($cfg);
  87. if (in_array($cfg, array('memory_limit', 'date.timezone'), true))
  88. {
  89. $ua_append .= ' ' . $cfg . '/' . str_replace('/', '.', $cfg_value);
  90. }
  91. elseif (in_array($cfg, array('open_basedir', 'safe_mode', 'zend.enable_gc'), true))
  92. {
  93. if ($cfg_value === false || $cfg_value === '' || $cfg_value === 0)
  94. {
  95. $cfg_value = 'off';
  96. }
  97. elseif ($cfg_value === true || $cfg_value === '1' || $cfg_value === 1)
  98. {
  99. $cfg_value = 'on';
  100. }
  101. $ua_append .= ' ' . $cfg . '/' . $cfg_value;
  102. }
  103. }
  104. return $ua_append;
  105. }
  106. /*%******************************************************************************************%*/
  107. // INTERMEDIARY CONSTANTS
  108. define('CFRUNTIME_NAME', 'aws-sdk-php');
  109. define('CFRUNTIME_VERSION', '1.4.8');
  110. // define('CFRUNTIME_BUILD', gmdate('YmdHis', filemtime(__FILE__))); // @todo: Hardcode for release.
  111. define('CFRUNTIME_BUILD', '20111207191027');
  112. define('CFRUNTIME_USERAGENT', CFRUNTIME_NAME . '/' . CFRUNTIME_VERSION . ' PHP/' . PHP_VERSION . ' ' . str_replace(' ', '_', php_uname('s')) . '/' . str_replace(' ', '_', php_uname('r')) . ' Arch/' . php_uname('m') . ' SAPI/' . php_sapi_name() . ' Integer/' . PHP_INT_MAX . ' Build/' . CFRUNTIME_BUILD . __aws_sdk_ua_callback());
  113. /*%******************************************************************************************%*/
  114. // CLASS
  115. /**
  116. * Core functionality and default settings shared across all SDK classes. All methods and properties in this
  117. * class are inherited by the service-specific classes.
  118. *
  119. * @version 2011.07.28
  120. * @license See the included NOTICE.md file for more information.
  121. * @copyright See the included NOTICE.md file for more information.
  122. * @link http://aws.amazon.com/php/ PHP Developer Center
  123. */
  124. class CFRuntime
  125. {
  126. /*%******************************************************************************************%*/
  127. // CONSTANTS
  128. /**
  129. * Name of the software.
  130. */
  131. const NAME = CFRUNTIME_NAME;
  132. /**
  133. * Version of the software.
  134. */
  135. const VERSION = CFRUNTIME_VERSION;
  136. /**
  137. * Build ID of the software.
  138. */
  139. const BUILD = CFRUNTIME_BUILD;
  140. /**
  141. * User agent string used to identify the software.
  142. */
  143. const USERAGENT = CFRUNTIME_USERAGENT;
  144. /*%******************************************************************************************%*/
  145. // PROPERTIES
  146. /**
  147. * The Amazon API Key.
  148. */
  149. public $key;
  150. /**
  151. * The Amazon API Secret Key.
  152. */
  153. public $secret_key;
  154. /**
  155. * The Amazon Authentication Token.
  156. */
  157. public $auth_token;
  158. /**
  159. * The Amazon Account ID, without hyphens.
  160. */
  161. public $account_id;
  162. /**
  163. * The Amazon Associates ID.
  164. */
  165. public $assoc_id;
  166. /**
  167. * Handle for the utility functions.
  168. */
  169. public $util;
  170. /**
  171. * An identifier for the current AWS service.
  172. */
  173. public $service = null;
  174. /**
  175. * The supported API version.
  176. */
  177. public $api_version = null;
  178. /**
  179. * The state of whether auth should be handled as AWS Query.
  180. */
  181. public $use_aws_query = true;
  182. /**
  183. * The default class to use for utilities (defaults to <CFUtilities>).
  184. */
  185. public $utilities_class = 'CFUtilities';
  186. /**
  187. * The default class to use for HTTP requests (defaults to <CFRequest>).
  188. */
  189. public $request_class = 'CFRequest';
  190. /**
  191. * The default class to use for HTTP responses (defaults to <CFResponse>).
  192. */
  193. public $response_class = 'CFResponse';
  194. /**
  195. * The default class to use for parsing XML (defaults to <CFSimpleXML>).
  196. */
  197. public $parser_class = 'CFSimpleXML';
  198. /**
  199. * The default class to use for handling batch requests (defaults to <CFBatchRequest>).
  200. */
  201. public $batch_class = 'CFBatchRequest';
  202. /**
  203. * The number of seconds to adjust the request timestamp by (defaults to 0).
  204. */
  205. public $adjust_offset = 0;
  206. /**
  207. * The state of SSL/HTTPS use.
  208. */
  209. public $use_ssl = true;
  210. /**
  211. * The state of SSL certificate verification.
  212. */
  213. public $ssl_verification = true;
  214. /**
  215. * The proxy to use for connecting.
  216. */
  217. public $proxy = null;
  218. /**
  219. * The alternate hostname to use, if any.
  220. */
  221. public $hostname = null;
  222. /**
  223. * The state of the capability to override the hostname with <set_hostname()>.
  224. */
  225. public $override_hostname = true;
  226. /**
  227. * The alternate port number to use, if any.
  228. */
  229. public $port_number = null;
  230. /**
  231. * The alternate resource prefix to use, if any.
  232. */
  233. public $resource_prefix = null;
  234. /**
  235. * The state of cache flow usage.
  236. */
  237. public $use_cache_flow = false;
  238. /**
  239. * The caching class to use.
  240. */
  241. public $cache_class = null;
  242. /**
  243. * The caching location to use.
  244. */
  245. public $cache_location = null;
  246. /**
  247. * When the cache should be considered stale.
  248. */
  249. public $cache_expires = null;
  250. /**
  251. * The state of cache compression.
  252. */
  253. public $cache_compress = null;
  254. /**
  255. * The current instantiated cache object.
  256. */
  257. public $cache_object = null;
  258. /**
  259. * The current instantiated batch request object.
  260. */
  261. public $batch_object = null;
  262. /**
  263. * The internally instantiated batch request object.
  264. */
  265. public $internal_batch_object = null;
  266. /**
  267. * The state of batch flow usage.
  268. */
  269. public $use_batch_flow = false;
  270. /**
  271. * The state of the cache deletion setting.
  272. */
  273. public $delete_cache = false;
  274. /**
  275. * The state of the debug mode setting.
  276. */
  277. public $debug_mode = false;
  278. /**
  279. * The number of times to retry failed requests.
  280. */
  281. public $max_retries = 3;
  282. /**
  283. * The user-defined callback function to call when a stream is read from.
  284. */
  285. public $registered_streaming_read_callback = null;
  286. /**
  287. * The user-defined callback function to call when a stream is written to.
  288. */
  289. public $registered_streaming_write_callback = null;
  290. /*%******************************************************************************************%*/
  291. // CONSTRUCTOR
  292. /**
  293. * The constructor. You would not normally instantiate this class directly. Rather, you would instantiate
  294. * a service-specific class.
  295. *
  296. * @param string $key (Optional) Your AWS key, or a session key. If blank, it will look for the <code>AWS_KEY</code> constant.
  297. * @param string $secret_key (Optional) Your AWS secret key, or a session secret key. If blank, it will look for the <code>AWS_SECRET_KEY</code> constant.
  298. * @param string $token (optional) An AWS session token. If blank, a request will be made to the AWS Secure Token Service to fetch a set of session credentials.
  299. * @return boolean A value of `false` if no valid values are set, otherwise `true`.
  300. */
  301. public function __construct($key = null, $secret_key = null, $token = null)
  302. {
  303. // Instantiate the utilities class.
  304. $this->util = new $this->utilities_class();
  305. // Determine the current service.
  306. $this->service = get_class($this);
  307. // Set default values
  308. $this->key = null;
  309. $this->secret_key = null;
  310. $this->auth_token = $token;
  311. // If both a key and secret key are passed in, use those.
  312. if ($key && $secret_key)
  313. {
  314. $this->key = $key;
  315. $this->secret_key = $secret_key;
  316. return true;
  317. }
  318. // If neither are passed in, look for the constants instead.
  319. elseif (defined('AWS_KEY') && defined('AWS_SECRET_KEY'))
  320. {
  321. $this->key = AWS_KEY;
  322. $this->secret_key = AWS_SECRET_KEY;
  323. return true;
  324. }
  325. // Otherwise set the values to blank and return false.
  326. else
  327. {
  328. throw new CFRuntime_Exception('No valid credentials were used to authenticate with AWS.');
  329. }
  330. }
  331. /**
  332. * Handle session-based authentication for services that support it.
  333. *
  334. * @param string $key (Optional) Your AWS key, or a session key. If blank, it will look for the <code>AWS_KEY</code> constant.
  335. * @param string $secret_key (Optional) Your AWS secret key, or a session secret key. If blank, it will look for the <code>AWS_SECRET_KEY</code> constant.
  336. * @param string $token (optional) An AWS session token. If blank, a request will be made to the AWS Secure Token Service to fetch a set of session credentials.
  337. * @return boolean A value of `false` if no valid values are set, otherwise `true`.
  338. */
  339. public function session_based_auth($key = null, $secret_key = null, $token = null)
  340. {
  341. // Instantiate the utilities class.
  342. $this->util = new $this->utilities_class();
  343. // Use 'em if we've got 'em
  344. if ($key && $secret_key && $token)
  345. {
  346. $this->key = $key;
  347. $this->secret_key = $secret_key;
  348. $this->auth_token = $token;
  349. return true;
  350. }
  351. else
  352. {
  353. if (!$key && !defined('AWS_KEY'))
  354. {
  355. // @codeCoverageIgnoreStart
  356. throw new CFRuntime_Exception('No account key was passed into the constructor, nor was it set in the AWS_KEY constant.');
  357. // @codeCoverageIgnoreEnd
  358. }
  359. if (!$secret_key && !defined('AWS_SECRET_KEY'))
  360. {
  361. // @codeCoverageIgnoreStart
  362. throw new CFRuntime_Exception('No account secret was passed into the constructor, nor was it set in the AWS_SECRET_KEY constant.');
  363. // @codeCoverageIgnoreEnd
  364. }
  365. // If both a key and secret key are passed in, use those.
  366. if ($key && $secret_key)
  367. {
  368. $this->key = $key;
  369. $this->secret_key = $secret_key;
  370. }
  371. // If neither are passed in, look for the constants instead.
  372. elseif (defined('AWS_KEY') && defined('AWS_SECRET_KEY'))
  373. {
  374. $this->key = AWS_KEY;
  375. $this->secret_key = AWS_SECRET_KEY;
  376. }
  377. // Determine storage type.
  378. $this->set_cache_config(AWS_DEFAULT_CACHE_CONFIG);
  379. $cache_class = $this->cache_class;
  380. $cache_object = new $cache_class('aws_active_session_credentials_' . get_class($this) . '_' . $this->key, AWS_DEFAULT_CACHE_CONFIG, 3600); // AWS_DEFAULT_CACHE_CONFIG only matters if it's a file system path.
  381. // Fetch session credentials
  382. $session_credentials = $cache_object->response_manager(array($this, 'cache_token'), array($this->key, $this->secret_key));
  383. $this->auth_token = $session_credentials['SessionToken'];
  384. // If both a key and secret key are passed in, use those.
  385. if (isset($session_credentials['AccessKeyId']) && isset($session_credentials['SecretAccessKey']))
  386. {
  387. $this->key = $session_credentials['AccessKeyId'];
  388. $this->secret_key = $session_credentials['SecretAccessKey'];
  389. return true;
  390. }
  391. // Otherwise set the values to blank and return false.
  392. else
  393. {
  394. throw new CFRuntime_Exception('No valid credentials were used to authenticate with AWS.');
  395. }
  396. }
  397. }
  398. /**
  399. * The callback function that is executed while caching the session credentials.
  400. *
  401. * @param string $key (Optional) Your AWS key, or a session key. If blank, it will look for the <code>AWS_KEY</code> constant.
  402. * @param string $secret_key (Optional) Your AWS secret key, or a session secret key. If blank, it will look for the <code>AWS_SECRET_KEY</code> constant.
  403. * @return mixed The data to be cached or null.
  404. */
  405. public function cache_token($key, $secret_key)
  406. {
  407. $token = new AmazonSTS($key, $secret_key);
  408. $response = $token->get_session_token();
  409. if ($response->isOK())
  410. {
  411. /*
  412. Array
  413. (
  414. [AccessKeyId] => ******
  415. [Expiration] => ******
  416. [SecretAccessKey] => ******
  417. [SessionToken] => ******
  418. )
  419. */
  420. return $response->body->GetSessionTokenResult->Credentials->to_array()->getArrayCopy();
  421. }
  422. return null;
  423. }
  424. /**
  425. * Alternate approach to constructing a new instance. Supports chaining.
  426. *
  427. * @param string $key (Optional) Your AWS key, or a session key. If blank, it will look for the <code>AWS_KEY</code> constant.
  428. * @param string $secret_key (Optional) Your AWS secret key, or a session secret key. If blank, it will look for the <code>AWS_SECRET_KEY</code> constant.
  429. * @param string $token (optional) An AWS session token. If blank, a request will be made to the AWS Secure Token Service to fetch a set of session credentials.
  430. * @return boolean A value of `false` if no valid values are set, otherwise `true`.
  431. */
  432. public static function init($key = null, $secret_key = null, $token = null)
  433. {
  434. if (version_compare(PHP_VERSION, '5.3.0', '<'))
  435. {
  436. throw new Exception('PHP 5.3 or newer is required to instantiate a new class with CLASS::init().');
  437. }
  438. $self = get_called_class();
  439. return new $self($key, $secret_key, $token);
  440. }
  441. /*%******************************************************************************************%*/
  442. // MAGIC METHODS
  443. /**
  444. * A magic method that allows `camelCase` method names to be translated into `snake_case` names.
  445. *
  446. * @param string $name (Required) The name of the method.
  447. * @param array $arguments (Required) The arguments passed to the method.
  448. * @return mixed The results of the intended method.
  449. */
  450. public function __call($name, $arguments)
  451. {
  452. // Convert camelCase method calls to snake_case.
  453. $method_name = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $name));
  454. if (method_exists($this, $method_name))
  455. {
  456. return call_user_func_array(array($this, $method_name), $arguments);
  457. }
  458. throw new CFRuntime_Exception('The method ' . $name . '() is undefined. Attempted to map to ' . $method_name . '() which is also undefined. Error occurred');
  459. }
  460. /*%******************************************************************************************%*/
  461. // SET CUSTOM SETTINGS
  462. /**
  463. * Adjusts the current time. Use this method for occasions when a server is out of sync with Amazon
  464. * servers.
  465. *
  466. * @param integer $seconds (Required) The number of seconds to adjust the sent timestamp by.
  467. * @return $this A reference to the current instance.
  468. */
  469. public function adjust_offset($seconds)
  470. {
  471. $this->adjust_offset = $seconds;
  472. return $this;
  473. }
  474. /**
  475. * Set the proxy settings to use.
  476. *
  477. * @param string $proxy (Required) Accepts proxy credentials in the following format: `proxy://user:pass@hostname:port`
  478. * @return $this A reference to the current instance.
  479. */
  480. public function set_proxy($proxy)
  481. {
  482. $this->proxy = $proxy;
  483. return $this;
  484. }
  485. /**
  486. * Set the hostname to connect to. This is useful for alternate services that are API-compatible with
  487. * AWS, but run from a different hostname.
  488. *
  489. * @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.
  490. * @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.
  491. * @return $this A reference to the current instance.
  492. */
  493. public function set_hostname($hostname, $port_number = null)
  494. {
  495. if ($this->override_hostname)
  496. {
  497. $this->hostname = $hostname;
  498. if ($port_number)
  499. {
  500. $this->port_number = $port_number;
  501. $this->hostname .= ':' . (string) $this->port_number;
  502. }
  503. }
  504. return $this;
  505. }
  506. /**
  507. * Set the resource prefix to use. This method is useful for alternate services that are API-compatible
  508. * with AWS.
  509. *
  510. * @param string $prefix (Required) An alternate prefix to prepend to the resource path. Useful for mock or test applications.
  511. * @return $this A reference to the current instance.
  512. */
  513. public function set_resource_prefix($prefix)
  514. {
  515. $this->resource_prefix = $prefix;
  516. return $this;
  517. }
  518. /**
  519. * Disables any subsequent use of the <set_hostname()> method.
  520. *
  521. * @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`.
  522. * @return $this A reference to the current instance.
  523. */
  524. public function allow_hostname_override($override = true)
  525. {
  526. $this->override_hostname = $override;
  527. return $this;
  528. }
  529. /**
  530. * Disables SSL/HTTPS connections for hosts that don't support them. Some services, however, still
  531. * require SSL support.
  532. *
  533. * This method will throw a user warning when invoked, which can be hidden by changing your
  534. * <php:error_reporting()> settings.
  535. *
  536. * @return $this A reference to the current instance.
  537. */
  538. public function disable_ssl()
  539. {
  540. trigger_error('Disabling SSL connections is potentially unsafe and highly discouraged.', E_USER_WARNING);
  541. $this->use_ssl = false;
  542. return $this;
  543. }
  544. /**
  545. * Disables the verification of the SSL Certificate Authority. Doing so can enable an attacker to carry
  546. * out a man-in-the-middle attack.
  547. *
  548. * https://secure.wikimedia.org/wikipedia/en/wiki/Man-in-the-middle_attack
  549. *
  550. * This method will throw a user warning when invoked, which can be hidden by changing your
  551. * <php:error_reporting()> settings.
  552. *
  553. * @return $this A reference to the current instance.
  554. */
  555. public function disable_ssl_verification($ssl_verification = false)
  556. {
  557. 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);
  558. $this->ssl_verification = $ssl_verification;
  559. return $this;
  560. }
  561. /**
  562. * Enables HTTP request/response header logging to `STDERR`.
  563. *
  564. * @param boolean $enabled (Optional) Whether or not to enable debug mode. Defaults to `true`.
  565. * @return $this A reference to the current instance.
  566. */
  567. public function enable_debug_mode($enabled = true)
  568. {
  569. $this->debug_mode = $enabled;
  570. return $this;
  571. }
  572. /**
  573. * Sets the maximum number of times to retry failed requests.
  574. *
  575. * @param integer $retries (Optional) The maximum number of times to retry failed requests. Defaults to `3`.
  576. * @return $this A reference to the current instance.
  577. */
  578. public function set_max_retries($retries = 3)
  579. {
  580. $this->max_retries = $retries;
  581. return $this;
  582. }
  583. /**
  584. * Set the caching configuration to use for response caching.
  585. *
  586. * @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>
  587. * @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`.
  588. * @return $this A reference to the current instance.
  589. */
  590. public function set_cache_config($location, $gzip = true)
  591. {
  592. // If we have an array, we're probably passing in Memcached servers and ports.
  593. if (is_array($location))
  594. {
  595. $this->cache_class = 'CacheMC';
  596. }
  597. else
  598. {
  599. // I would expect locations like `/tmp/cache`, `pdo.mysql://user:pass@hostname:port`, `pdo.sqlite:memory:`, and `apc`.
  600. $type = strtolower(substr($location, 0, 3));
  601. switch ($type)
  602. {
  603. case 'apc':
  604. $this->cache_class = 'CacheAPC';
  605. break;
  606. case 'xca': // First three letters of `xcache`
  607. $this->cache_class = 'CacheXCache';
  608. break;
  609. case 'pdo':
  610. $this->cache_class = 'CachePDO';
  611. $location = substr($location, 4);
  612. break;
  613. default:
  614. $this->cache_class = 'CacheFile';
  615. break;
  616. }
  617. }
  618. // Set the remaining cache information.
  619. $this->cache_location = $location;
  620. $this->cache_compress = $gzip;
  621. return $this;
  622. }
  623. /**
  624. * Register a callback function to execute whenever a data stream is read from using
  625. * <CFRequest::streaming_read_callback()>.
  626. *
  627. * The user-defined callback function should accept three arguments:
  628. *
  629. * <ul>
  630. * <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li>
  631. * <li><code>$file_handle</code> - <code>resource</code> - Required - The file handle resource that represents the file on the local file system.</li>
  632. * <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li>
  633. * </ul>
  634. *
  635. * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul>
  636. * <li>The name of a global function to execute, passed as a string.</li>
  637. * <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li>
  638. * <li>An anonymous function (PHP 5.3+).</li></ul>
  639. * @return $this A reference to the current instance.
  640. */
  641. public function register_streaming_read_callback($callback)
  642. {
  643. $this->registered_streaming_read_callback = $callback;
  644. return $this;
  645. }
  646. /**
  647. * Register a callback function to execute whenever a data stream is written to using
  648. * <CFRequest::streaming_write_callback()>.
  649. *
  650. * The user-defined callback function should accept two arguments:
  651. *
  652. * <ul>
  653. * <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li>
  654. * <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li>
  655. * </ul>
  656. *
  657. * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul>
  658. * <li>The name of a global function to execute, passed as a string.</li>
  659. * <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li>
  660. * <li>An anonymous function (PHP 5.3+).</li></ul>
  661. * @return $this A reference to the current instance.
  662. */
  663. public function register_streaming_write_callback($callback)
  664. {
  665. $this->registered_streaming_write_callback = $callback;
  666. return $this;
  667. }
  668. /*%******************************************************************************************%*/
  669. // SET CUSTOM CLASSES
  670. /**
  671. * Set a custom class for this functionality. Use this method when extending/overriding existing classes
  672. * with new functionality.
  673. *
  674. * The replacement class must extend from <CFUtilities>.
  675. *
  676. * @param string $class (Optional) The name of the new class to use for this functionality.
  677. * @return $this A reference to the current instance.
  678. */
  679. public function set_utilities_class($class = 'CFUtilities')
  680. {
  681. $this->utilities_class = $class;
  682. $this->util = new $this->utilities_class();
  683. return $this;
  684. }
  685. /**
  686. * Set a custom class for this functionality. Use this method when extending/overriding existing classes
  687. * with new functionality.
  688. *
  689. * The replacement class must extend from <CFRequest>.
  690. *
  691. * @param string $class (Optional) The name of the new class to use for this functionality.
  692. * @param $this A reference to the current instance.
  693. */
  694. public function set_request_class($class = 'CFRequest')
  695. {
  696. $this->request_class = $class;
  697. return $this;
  698. }
  699. /**
  700. * Set a custom class for this functionality. Use this method when extending/overriding existing classes
  701. * with new functionality.
  702. *
  703. * The replacement class must extend from <CFResponse>.
  704. *
  705. * @param string $class (Optional) The name of the new class to use for this functionality.
  706. * @return $this A reference to the current instance.
  707. */
  708. public function set_response_class($class = 'CFResponse')
  709. {
  710. $this->response_class = $class;
  711. return $this;
  712. }
  713. /**
  714. * Set a custom class for this functionality. Use this method when extending/overriding existing classes
  715. * with new functionality.
  716. *
  717. * The replacement class must extend from <CFSimpleXML>.
  718. *
  719. * @param string $class (Optional) The name of the new class to use for this functionality.
  720. * @return $this A reference to the current instance.
  721. */
  722. public function set_parser_class($class = 'CFSimpleXML')
  723. {
  724. $this->parser_class = $class;
  725. return $this;
  726. }
  727. /**
  728. * Set a custom class for this functionality. Use this method when extending/overriding existing classes
  729. * with new functionality.
  730. *
  731. * The replacement class must extend from <CFBatchRequest>.
  732. *
  733. * @param string $class (Optional) The name of the new class to use for this functionality.
  734. * @return $this A reference to the current instance.
  735. */
  736. public function set_batch_class($class = 'CFBatchRequest')
  737. {
  738. $this->batch_class = $class;
  739. return $this;
  740. }
  741. /*%******************************************************************************************%*/
  742. // AUTHENTICATION
  743. /**
  744. * Default, shared method for authenticating a connection to AWS. Overridden on a class-by-class basis
  745. * as necessary.
  746. *
  747. * @param string $action (Required) Indicates the action to perform.
  748. * @param array $opt (Optional) An associative array of parameters for authenticating. See the individual methods for allowed keys.
  749. * @param string $domain (Optional) The URL of the queue to perform the action on.
  750. * @param integer $signature_version (Optional) The signature version to use. Defaults to 2.
  751. * @param integer $redirects (Do Not Use) Used internally by this function on occasions when Amazon S3 returns a redirect code and it needs to call itself recursively.
  752. * @return CFResponse Object containing a parsed HTTP response.
  753. */
  754. public function authenticate($action, $opt = null, $domain = null, $signature_version = 2, $redirects = 0)
  755. {
  756. // Handle nulls
  757. if (is_null($signature_version))
  758. {
  759. $signature_version = 2;
  760. }
  761. $method_arguments = func_get_args();
  762. $headers = array();
  763. $signed_headers = array();
  764. // Use the caching flow to determine if we need to do a round-trip to the server.
  765. if ($this->use_cache_flow)
  766. {
  767. // Generate an identifier specific to this particular set of arguments.
  768. $cache_id = $this->key . '_' . get_class($this) . '_' . $action . '_' . sha1(serialize($method_arguments));
  769. // Instantiate the appropriate caching object.
  770. $this->cache_object = new $this->cache_class($cache_id, $this->cache_location, $this->cache_expires, $this->cache_compress);
  771. if ($this->delete_cache)
  772. {
  773. $this->use_cache_flow = false;
  774. $this->delete_cache = false;
  775. return $this->cache_object->delete();
  776. }
  777. // Invoke the cache callback function to determine whether to pull data from the cache or make a fresh request.
  778. $data = $this->cache_object->response_manager(array($this, 'cache_callback'), $method_arguments);
  779. // Parse the XML body
  780. $data = $this->parse_callback($data);
  781. // End!
  782. return $data;
  783. }
  784. $return_curl_handle = false;
  785. $x_amz_target = null;
  786. // Do we have a custom resource prefix?
  787. if ($this->resource_prefix)
  788. {
  789. $domain .= $this->resource_prefix;
  790. }
  791. // Determine signing values
  792. $current_time = time() + $this->adjust_offset;
  793. $date = gmdate(CFUtilities::DATE_FORMAT_RFC2616, $current_time);
  794. $timestamp = gmdate(CFUtilities::DATE_FORMAT_ISO8601, $current_time);
  795. $nonce = $this->util->generate_guid();
  796. // Do we have an authentication token?
  797. if ($this->auth_token)
  798. {
  799. $headers['X-Amz-Security-Token'] = $this->auth_token;
  800. $query['SecurityToken'] = $this->auth_token;
  801. }
  802. // Manage the key-value pairs that are used in the query.
  803. if (stripos($action, 'x-amz-target') !== false)
  804. {
  805. $x_amz_target = trim(str_ireplace('x-amz-target:', '', $action));
  806. }
  807. else
  808. {
  809. $query['Action'] = $action;
  810. }
  811. // Only add it if it exists.
  812. if ($this->api_version)
  813. {
  814. $query['Version'] = $this->api_version;
  815. }
  816. // Only Signature v2
  817. if ($signature_version === 2)
  818. {
  819. $query['AWSAccessKeyId'] = $this->key;
  820. $query['SignatureMethod'] = 'HmacSHA256';
  821. $query['SignatureVersion'] = 2;
  822. $query['Timestamp'] = $timestamp;
  823. }
  824. $curlopts = array();
  825. // Set custom CURLOPT settings
  826. if (is_array($opt) && isset($opt['curlopts']))
  827. {
  828. $curlopts = $opt['curlopts'];
  829. unset($opt['curlopts']);
  830. }
  831. // Merge in any options that were passed in
  832. if (is_array($opt))
  833. {
  834. $query = array_merge($query, $opt);
  835. }
  836. $return_curl_handle = isset($query['returnCurlHandle']) ? $query['returnCurlHandle'] : false;
  837. unset($query['returnCurlHandle']);
  838. // Do a case-sensitive, natural order sort on the array keys.
  839. uksort($query, 'strcmp');
  840. // Normalize JSON input
  841. if (isset($query['body']) && $query['body'] === '[]')
  842. {
  843. $query['body'] = '{}';
  844. }
  845. if ($this->use_aws_query)
  846. {
  847. // Create the string that needs to be hashed.
  848. $canonical_query_string = $this->util->to_signable_string($query);
  849. }
  850. else
  851. {
  852. // Create the string that needs to be hashed.
  853. $canonical_query_string = $this->util->encode_signature2($query['body']);
  854. }
  855. // Remove the default scheme from the domain.
  856. $domain = str_replace(array('http://', 'https://'), '', $domain);
  857. // Parse our request.
  858. $parsed_url = parse_url('http://' . $domain);
  859. // Set the proper host header.
  860. if (isset($parsed_url['port']) && (integer) $parsed_url['port'] !== 80 && (integer) $parsed_url['port'] !== 443)
  861. {
  862. $host_header = strtolower($parsed_url['host']) . ':' . $parsed_url['port'];
  863. }
  864. else
  865. {
  866. $host_header = strtolower($parsed_url['host']);
  867. }
  868. // Set the proper request URI.
  869. $request_uri = isset($parsed_url['path']) ? $parsed_url['path'] : '/';
  870. if ($signature_version === 2)
  871. {
  872. // Prepare the string to sign
  873. $string_to_sign = "POST\n$host_header\n$request_uri\n$canonical_query_string";
  874. // Hash the AWS secret key and generate a signature for the request.
  875. $query['Signature'] = base64_encode(hash_hmac('sha256', $string_to_sign, $this->secret_key, true));
  876. }
  877. // Generate the querystring from $query
  878. $querystring = $this->util->to_query_string($query);
  879. // Gather information to pass along to other classes.
  880. $helpers = array(
  881. 'utilities' => $this->utilities_class,
  882. 'request' => $this->request_class,
  883. 'response' => $this->response_class,
  884. );
  885. // Compose the request.
  886. $request_url = ($this->use_ssl ? 'https://' : 'http://') . $domain;
  887. $request_url .= !isset($parsed_url['path']) ? '/' : '';
  888. // Instantiate the request class
  889. $request = new $this->request_class($request_url, $this->proxy, $helpers);
  890. $request->set_method('POST');
  891. $request->set_body($querystring);
  892. $headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
  893. // Signing using X-Amz-Target is handled differently.
  894. if ($signature_version === 3 && $x_amz_target)
  895. {
  896. $headers['X-Amz-Target'] = $x_amz_target;
  897. $headers['Content-Type'] = 'application/json; amzn-1.0';
  898. $headers['Content-Encoding'] = 'amz-1.0';
  899. $request->set_body($query['body']);
  900. $querystring = $query['body'];
  901. }
  902. // Pass along registered stream callbacks
  903. if ($this->registered_streaming_read_callback)
  904. {
  905. $request->register_streaming_read_callback($this->registered_streaming_read_callback);
  906. }
  907. if ($this->registered_streaming_write_callback)
  908. {
  909. $request->register_streaming_write_callback($this->registered_streaming_write_callback);
  910. }
  911. // Add authentication headers
  912. if ($signature_version === 3)
  913. {
  914. $headers['X-Amz-Nonce'] = $nonce;
  915. $headers['Date'] = $date;
  916. $headers['Content-Length'] = strlen($querystring);
  917. $headers['Content-MD5'] = $this->util->hex_to_base64(md5($querystring));
  918. $headers['Host'] = $host_header;
  919. }
  920. // Sort headers
  921. uksort($headers, 'strnatcasecmp');
  922. if ($signature_version === 3 && $this->use_ssl)
  923. {
  924. // Prepare the string to sign (HTTPS)
  925. $string_to_sign = $date . $nonce;
  926. }
  927. elseif ($signature_version === 3 && !$this->use_ssl)
  928. {
  929. // Prepare the string to sign (HTTP)
  930. $string_to_sign = "POST\n$request_uri\n\n";
  931. }
  932. // Add headers to request and compute the string to sign
  933. foreach ($headers as $header_key => $header_value)
  934. {
  935. // Strip linebreaks from header values as they're illegal and can allow for security issues
  936. $header_value = str_replace(array("\r", "\n"), '', $header_value);
  937. // Add the header if it has a value
  938. if ($header_value !== '')
  939. {
  940. $request->add_header($header_key, $header_value);
  941. }
  942. // Signature v3 over HTTP
  943. if ($signature_version === 3 && !$this->use_ssl)
  944. {
  945. // Generate the string to sign
  946. if (
  947. substr(strtolower($header_key), 0, 8) === 'content-' ||
  948. strtolower($header_key) === 'date' ||
  949. strtolower($header_key) === 'expires' ||
  950. strtolower($header_key) === 'host' ||
  951. substr(strtolower($header_key), 0, 6) === 'x-amz-'
  952. )
  953. {
  954. $string_to_sign .= strtolower($header_key) . ':' . $header_value . "\n";
  955. $signed_headers[] = $header_key;
  956. }
  957. }
  958. }
  959. if ($signature_version === 3)
  960. {
  961. if (!$this->use_ssl)
  962. {
  963. $string_to_sign .= "\n";
  964. if (isset($query['body']) && $query['body'] !== '')
  965. {
  966. $string_to_sign .= $query['body'];
  967. }
  968. // Convert from string-to-sign to bytes-to-sign
  969. $bytes_to_sign = hash('sha256', $string_to_sign, true);
  970. // Hash the AWS secret key and generate a signature for the request.
  971. $signature = base64_encode(hash_hmac('sha256', $bytes_to_sign, $this->secret_key, true));
  972. }
  973. else
  974. {
  975. // Hash the AWS secret key and generate a signature for the request.
  976. $signature = base64_encode(hash_hmac('sha256', $string_to_sign, $this->secret_key, true));
  977. }
  978. $headers['X-Amzn-Authorization'] = 'AWS3' . ($this->use_ssl ? '-HTTPS' : '')
  979. . ' AWSAccessKeyId=' . $this->key
  980. . ',Algorithm=HmacSHA256'
  981. . ',SignedHeaders=' . implode(';', $signed_headers)
  982. . ',Signature=' . $signature;
  983. $request->add_header('X-Amzn-Authorization', $headers['X-Amzn-Authorization']);
  984. }
  985. // Update RequestCore settings
  986. $request->request_class = $this->request_class;
  987. $request->response_class = $this->response_class;
  988. $request->ssl_verification = $this->ssl_verification;
  989. // Debug mode
  990. if ($this->debug_mode)
  991. {
  992. $request->debug_mode = $this->debug_mode;
  993. }
  994. if (count($curlopts))
  995. {
  996. $request->set_curlopts($curlopts);
  997. }
  998. // Manage the (newer) batch request API or the (older) returnCurlHandle setting.
  999. if ($this->use_batch_flow)
  1000. {
  1001. $handle = $request->prep_request();
  1002. $this->batch_object->add($handle);
  1003. $this->use_batch_flow = false;
  1004. return $handle;
  1005. }
  1006. elseif ($return_curl_handle)
  1007. {
  1008. return $request->prep_request();
  1009. }
  1010. // Send!
  1011. $request->send_request();
  1012. $request_headers = $headers;
  1013. // Prepare the response.
  1014. $headers = $request->get_response_header();
  1015. $headers['x-aws-stringtosign'] = $string_to_sign;
  1016. $headers['x-aws-request-headers'] = $request_headers;
  1017. $headers['x-aws-body'] = $querystring;
  1018. $data = new $this->response_class($headers, $this->parse_callback($request->get_response_body(), $headers), $request->get_response_code());
  1019. // Was it Amazon's fault the request failed? Retry the request until we reach $max_retries.
  1020. if ((integer) $request->get_response_code() === 500 || (integer) $request->get_response_code() === 503)
  1021. {
  1022. if ($redirects <= $this->max_retries)
  1023. {
  1024. // Exponential backoff
  1025. $delay = (integer) (pow(4, $redirects) * 100000);
  1026. usleep($delay);
  1027. $data = $this->authenticate($action, $opt, $domain, $signature_version, ++$redirects);
  1028. }
  1029. }
  1030. return $data;
  1031. }
  1032. /*%******************************************************************************************%*/
  1033. // BATCH REQUEST LAYER
  1034. /**
  1035. * Specifies that the intended request should be queued for a later batch request.
  1036. *
  1037. * @param CFBatchRequest $queue (Optional) The <CFBatchRequest> instance to use for managing batch requests. If not available, it generates a new instance of <CFBatchRequest>.
  1038. * @return $this A reference to the current instance.
  1039. */
  1040. public function batch(CFBatchRequest &$queue = null)
  1041. {
  1042. if ($queue)
  1043. {
  1044. $this->batch_object = $queue;
  1045. }
  1046. elseif ($this->internal_batch_object)
  1047. {
  1048. $this->batch_object = &$this->internal_batch_object;
  1049. }
  1050. else
  1051. {
  1052. $this->internal_batch_object = new $this->batch_class();
  1053. $this->batch_object = &$this->internal_batch_object;
  1054. }
  1055. $this->use_batch_flow = true;
  1056. return $this;
  1057. }
  1058. /**
  1059. * Executes the batch request queue by sending all queued requests.
  1060. *
  1061. * @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.
  1062. * @return array An array of <CFResponse> objects.
  1063. */
  1064. public function send($clear_after_send = true)
  1065. {
  1066. if ($this->use_batch_flow)
  1067. {
  1068. // When we send the request, disable batch flow.
  1069. $this->use_batch_flow = false;
  1070. // If we're not caching, simply send the request.
  1071. if (!$this->use_cache_flow)
  1072. {
  1073. $response = $this->batch_object->send();
  1074. $parsed_data = array_map(array($this, 'parse_callback'), $response);
  1075. $parsed_data = new CFArray($parsed_data);
  1076. // Clear the queue
  1077. if ($clear_after_send)
  1078. {
  1079. $this->batch_object->queue = array();
  1080. }
  1081. return $parsed_data;
  1082. }
  1083. // Generate an identifier specific to this particular set of arguments.
  1084. $cache_id = $this->key . '_' . get_class($this) . '_' . sha1(serialize($this->batch_object));
  1085. // Instantiate the appropriate caching object.
  1086. $this->cache_object = new $this->cache_class($cache_id, $this->cache_location, $this->cache_expires, $this->cache_compress);
  1087. if ($this->delete_cache)
  1088. {
  1089. $this->use_cache_flow = false;
  1090. $this->delete_cache = false;
  1091. return $this->cache_object->delete();
  1092. }
  1093. // Invoke the cache callback function to determine whether to pull data from the cache or make a fresh request.
  1094. $data_set = $this->cache_object->response_manager(array($this, 'cache_callback_batch'), array($this->batch_object));
  1095. $parsed_data = array_map(array($this, 'parse_callback'), $data_set);
  1096. $parsed_data = new CFArray($parsed_data);
  1097. // Clear the queue
  1098. if ($clear_after_send)
  1099. {
  1100. $this->batch_object->queue = array();
  1101. }
  1102. // End!
  1103. return $parsed_data;
  1104. }
  1105. // Load the class
  1106. $null = new CFBatchRequest();
  1107. unset($null);
  1108. throw new CFBatchRequest_Exception('You must use $object->batch()->send()');
  1109. }
  1110. /**
  1111. * Parses a response body into a PHP object if appropriate.
  1112. *
  1113. * @param CFResponse|string $response (Required) The <CFResponse> object to parse, or an XML string that would otherwise be a response body.
  1114. * @param string $content_type (Optional) The content-type to use when determining how to parse the content.
  1115. * @return CFResponse|string A parsed <CFResponse> object, or parsed XML.
  1116. */
  1117. public function parse_callback($response, $headers = null)
  1118. {
  1119. // Shorten this so we have a (mostly) single code path
  1120. if (isset($response->body))
  1121. {
  1122. if (is_string($response->body))
  1123. {
  1124. $body = $response->body;
  1125. }
  1126. else
  1127. {
  1128. return $response;
  1129. }
  1130. }
  1131. elseif (is_string($response))
  1132. {
  1133. $body = $response;
  1134. }
  1135. else
  1136. {
  1137. return $response;
  1138. }
  1139. // Decompress gzipped content
  1140. if (isset($headers['content-encoding']))
  1141. {
  1142. switch (strtolower(trim($headers['content-encoding'], "\x09\x0A\x0D\x20")))
  1143. {
  1144. case 'gzip':
  1145. case 'x-gzip':
  1146. if (strpos($headers['_info']['url'], 'monitoring.') !== false)
  1147. {
  1148. // CloudWatch incorrectly uses the deflate algorithm when they say gzip.
  1149. if (($uncompressed = gzuncompress($body)) !== false)
  1150. {
  1151. $body = $uncompressed;
  1152. }
  1153. elseif (($uncompressed = gzinflate($body)) !== false)
  1154. {
  1155. $body = $uncompressed;
  1156. }
  1157. break;
  1158. }
  1159. else
  1160. {
  1161. // Everyone else uses gzip correctly.
  1162. $decoder = new CFGzipDecode($body);
  1163. if ($decoder->parse())
  1164. {
  1165. $body = $decoder->data;
  1166. }
  1167. break;
  1168. }
  1169. case 'deflate':
  1170. if (strpos($headers['_info']['url'], 'monitoring.') !== false)
  1171. {
  1172. // CloudWatchWatch incorrectly does nothing when they say deflate.
  1173. continue;
  1174. }
  1175. else
  1176. {
  1177. // Everyone else uses deflate correctly.
  1178. if (($uncompressed = gzuncompress($body)) !== false)
  1179. {
  1180. $body = $uncompressed;
  1181. }
  1182. elseif (($uncompressed = gzinflate($body)) !== false)
  1183. {
  1184. $body = $uncompressed;
  1185. }
  1186. }
  1187. break;
  1188. }
  1189. }
  1190. // Look for XML cues
  1191. if (
  1192. (isset($headers['content-type']) && ($headers['content-type'] === 'text/xml' || $headers['content-type'] === 'application/xml')) || // We know it's XML
  1193. (!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
  1194. )
  1195. {
  1196. // Strip the default XML namespace to simplify XPath expressions
  1197. $body = str_replace("xmlns=", "ns=", $body);
  1198. // Parse the XML body
  1199. $body = new $this->parser_class($body);
  1200. }
  1201. // Look for JSON cues
  1202. elseif (
  1203. (isset($headers['content-type']) && $headers['content-type'] === 'application/json') || // We know it's JSON
  1204. (!isset($headers['content-type']) && $this->util->is_json($body)) // Sniff for JSON
  1205. )
  1206. {
  1207. // Normalize JSON to a CFSimpleXML object
  1208. $body = CFJSON::to_xml($body);
  1209. }
  1210. // Put the parsed data back where it goes
  1211. if (isset($response->body))
  1212. {
  1213. $response->body = $body;
  1214. }
  1215. else
  1216. {
  1217. $response = $body;
  1218. }
  1219. return $response;
  1220. }
  1221. /*%******************************************************************************************%*/
  1222. // CACHING LAYER
  1223. /**
  1224. * Specifies that the resulting <CFResponse> object should be cached according to the settings from
  1225. * <set_cache_config()>.
  1226. *
  1227. * @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").
  1228. * @param $this A reference to the current instance.
  1229. * @return $this
  1230. */
  1231. public function cache($expires)
  1232. {
  1233. // Die if they haven't used set_cache_config().
  1234. if (!$this->cache_class)
  1235. {
  1236. throw new CFRuntime_Exception('Must call set_cache_config() before using cache()');
  1237. }
  1238. if (is_string($expires))
  1239. {
  1240. $expires = strtotime($expires);
  1241. $this->cache_expires = $expires - time();
  1242. }
  1243. elseif (is_int($expires))
  1244. {
  1245. $this->cache_expires = $expires;
  1246. }
  1247. $this->use_cache_flow = true;
  1248. return $this;
  1249. }
  1250. /**
  1251. * The callback function that is executed when the cache doesn't exist or has expired. The response of
  1252. * this method is cached. Accepts identical parameters as the <authenticate()> method. Never call this
  1253. * method directly -- it is used internally by the caching system.
  1254. *
  1255. * @param string $action (Required) Indicates the action to perform.
  1256. * @param array $opt (Optional) An associative array of parameters for authenticating. See the individual methods for allowed keys.
  1257. * @param string $domain (Optional) The URL of the queue to perform the action on.
  1258. * @param integer $signature_version (Optional) The signature version to use. Defaults to 2.
  1259. * @return CFResponse A parsed HTTP response.
  1260. */
  1261. public function cache_callback($action, $opt = null, $domain = null, $signature_version = 2)
  1262. {
  1263. // Disable the cache flow since it's already been handled.
  1264. $this->use_cache_flow = false;
  1265. // Make the request
  1266. $response = $this->authenticate($action, $opt, $domain, $signature_version);
  1267. // If this is an XML document, convert it back to a string.
  1268. if (isset($response->body) && ($response->body instanceof SimpleXMLElement))
  1269. {
  1270. $response->body = $response->body->asXML();
  1271. }
  1272. return $response;
  1273. }
  1274. /**
  1275. * Used for caching the results of a batch request. Never call this method directly; it is used
  1276. * internally by the caching system.
  1277. *
  1278. * @param CFBatchRequest $batch (Required) The batch request object to send.
  1279. * @return CFResponse A parsed HTTP response.
  1280. */
  1281. public function cache_callback_batch(CFBatchRequest $batch)
  1282. {
  1283. return $batch->send();
  1284. }
  1285. /**
  1286. * Deletes a cached <CFResponse> object using the specified cache storage type.
  1287. *
  1288. * @return boolean A value of `true` if cached object exists and is successfully deleted, otherwise `false`.
  1289. */
  1290. public function delete_cache()
  1291. {
  1292. $this->use_cache_flow = true;
  1293. $this->delete_cache = true;
  1294. return $this;
  1295. }
  1296. }
  1297. /**
  1298. * Contains the functionality for auto-loading service classes.
  1299. */
  1300. class CFLoader
  1301. {
  1302. /*%******************************************************************************************%*/
  1303. // AUTO-LOADER
  1304. /**
  1305. * Automatically load classes that aren't included.
  1306. *
  1307. * @param string $class (Required) The classname to load.
  1308. * @return void
  1309. */
  1310. public static function autoloader($class)
  1311. {
  1312. $path = dirname(__FILE__) . DIRECTORY_SEPARATOR;
  1313. // Amazon SDK classes
  1314. if (strstr($class, 'Amazon'))
  1315. {
  1316. $path .= 'services' . DIRECTORY_SEPARATOR . str_ireplace('Amazon', '', strtolower($class)) . '.class.php';
  1317. }
  1318. // Utility classes
  1319. elseif (strstr($class, 'CF'))
  1320. {
  1321. $path .= 'utilities' . DIRECTORY_SEPARATOR . str_ireplace('CF', '', strtolower($class)) . '.class.php';
  1322. }
  1323. // Load CacheCore
  1324. elseif (strstr($class, 'Cache'))
  1325. {
  1326. if (file_exists($ipath = 'lib' . DIRECTORY_SEPARATOR . 'cachecore' . DIRECTORY_SEPARATOR . 'icachecore.interface.php'))
  1327. {
  1328. require_once($ipath);
  1329. }
  1330. $path .= 'lib' . DIRECTORY_SEPARATOR . 'cachecore' . DIRECTORY_SEPARATOR . strtolower($class) . '.class.php';
  1331. }
  1332. // Load RequestCore
  1333. elseif (strstr($class, 'RequestCore') || strstr($class, 'ResponseCore'))
  1334. {
  1335. $path .= 'lib' . DIRECTORY_SEPARATOR . 'requestcore' . DIRECTORY_SEPARATOR . 'requestcore.class.php';
  1336. }
  1337. // Load Symfony YAML classes
  1338. elseif (strstr($class, 'sfYaml'))
  1339. {
  1340. $path .= 'lib' . DIRECTORY_SEPARATOR . 'yaml' . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'sfYaml.php';
  1341. }
  1342. // Fall back to the 'extensions' directory.
  1343. elseif (defined('AWS_ENABLE_EXTENSIONS') && AWS_ENABLE_EXTENSIONS)
  1344. {
  1345. $path .= 'extensions' . DIRECTORY_SEPARATOR . strtolower($class) . '.class.php';
  1346. }
  1347. if (file_exists($path) && !is_dir($path))
  1348. {
  1349. require_once($path);
  1350. }
  1351. return true;
  1352. }
  1353. }
  1354. // Register the autoloader.
  1355. spl_autoload_register(array('CFLoader', 'autoloader'));