PageRenderTime 77ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/plugins/backwpup/libs/aws/services/s3.class.php

https://bitbucket.org/ssellek/saywhatnation.bitbucket
PHP | 4491 lines | 2227 code | 593 blank | 1671 comment | 352 complexity | bdbd19960bd66fdf07f0bad18816b127 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, GPL-2.0, GPL-3.0
  1. <?php
  2. /*
  3. * Copyright 2010-2012 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 S3 Exception.
  20. */
  21. class S3_Exception extends Exception {}
  22. /*%******************************************************************************************%*/
  23. // MAIN CLASS
  24. /**
  25. * Amazon S3 is a web service that enables you to store data in the cloud. You can then download the data
  26. * or use the data with other AWS services, such as Amazon Elastic Cloud Computer (EC2).
  27. *
  28. * Amazon Simple Storage Service (Amazon S3) is storage for the Internet. You can use Amazon S3 to store
  29. * and retrieve any amount of data at any time, from anywhere on the web. You can accomplish these tasks
  30. * using the AWS Management Console, which is a simple and intuitive web interface.
  31. *
  32. * To get the most out of Amazon S3, you need to understand a few simple concepts. Amazon S3 stores data
  33. * as objects in buckets. An object is comprised of a file and optionally any metadata that describes
  34. * that file.
  35. *
  36. * To store an object in Amazon S3, you upload the file you want to store to a bucket. When you upload a
  37. * file, you can set permissions on the object as well as any metadata.
  38. *
  39. * Buckets are the containers for objects. You can have one or more buckets. For each bucket, you can control
  40. * access to the bucket (who can create, delete, and list objects in the bucket), view access logs for the
  41. * bucket and its objects, and choose the geographical region where Amazon S3 will store the bucket and its
  42. * contents.
  43. *
  44. * Visit <http://aws.amazon.com/s3/> for more information.
  45. *
  46. * @version 2012.10.02
  47. * @license See the included NOTICE.md file for more information.
  48. * @copyright See the included NOTICE.md file for more information.
  49. * @link http://aws.amazon.com/s3/ Amazon Simple Storage Service
  50. * @link http://aws.amazon.com/documentation/s3/ Amazon Simple Storage Service documentation
  51. */
  52. class AmazonS3 extends CFRuntime
  53. {
  54. /*%******************************************************************************************%*/
  55. // REGIONAL ENDPOINTS
  56. /**
  57. * Specify the queue URL for the US-Standard (Northern Virginia & Washington State) Region.
  58. */
  59. const REGION_US_E1 = 's3.amazonaws.com';
  60. /**
  61. * Specify the queue URL for the US-Standard (Northern Virginia & Washington State) Region.
  62. */
  63. const REGION_VIRGINIA = self::REGION_US_E1;
  64. /**
  65. * Specify the queue URL for the US-Standard (Northern Virginia & Washington State) Region.
  66. */
  67. const REGION_US_STANDARD = self::REGION_US_E1;
  68. /**
  69. * Specify the queue URL for the US-West 1 (Northern California) Region.
  70. */
  71. const REGION_US_W1 = 's3-us-west-1.amazonaws.com';
  72. /**
  73. * Specify the queue URL for the US-West 1 (Northern California) Region.
  74. */
  75. const REGION_CALIFORNIA = self::REGION_US_W1;
  76. /**
  77. * Specify the queue URL for the US-West 2 (Oregon) Region.
  78. */
  79. const REGION_US_W2 = 's3-us-west-2.amazonaws.com';
  80. /**
  81. * Specify the queue URL for the US-West 2 (Oregon) Region.
  82. */
  83. const REGION_OREGON = self::REGION_US_W2;
  84. /**
  85. * Specify the queue URL for the EU (Ireland) Region.
  86. */
  87. const REGION_EU_W1 = 's3-eu-west-1.amazonaws.com';
  88. /**
  89. * Specify the queue URL for the EU (Ireland) Region.
  90. */
  91. const REGION_IRELAND = self::REGION_EU_W1;
  92. /**
  93. * Specify the queue URL for the Asia Pacific (Singapore) Region.
  94. */
  95. const REGION_APAC_SE1 = 's3-ap-southeast-1.amazonaws.com';
  96. /**
  97. * Specify the queue URL for the Asia Pacific (Singapore) Region.
  98. */
  99. const REGION_SINGAPORE = self::REGION_APAC_SE1;
  100. /**
  101. * Specify the queue URL for the Asia Pacific (Sydney) Region.
  102. */
  103. const REGION_APAC_SE2 = 's3-ap-southeast-2.amazonaws.com';
  104. /**
  105. * Specify the queue URL for the Asia Pacific (Sydney) Region.
  106. */
  107. const REGION_SYDNEY = self::REGION_APAC_SE2;
  108. /**
  109. * Specify the queue URL for the Asia Pacific (Japan) Region.
  110. */
  111. const REGION_APAC_NE1 = 's3-ap-northeast-1.amazonaws.com';
  112. /**
  113. * Specify the queue URL for the Asia Pacific (Japan) Region.
  114. */
  115. const REGION_TOKYO = self::REGION_APAC_NE1;
  116. /**
  117. * Specify the queue URL for the South America (Sao Paulo) Region.
  118. */
  119. const REGION_SA_E1 = 's3-sa-east-1.amazonaws.com';
  120. /**
  121. * Specify the queue URL for the South America (Sao Paulo) Region.
  122. */
  123. const REGION_SAO_PAULO = self::REGION_SA_E1;
  124. /**
  125. * Specify the queue URL for the United States GovCloud Region.
  126. */
  127. const REGION_US_GOV1 = 's3-us-gov-west-1.amazonaws.com';
  128. /**
  129. * Specify the queue URL for the United States GovCloud FIPS 140-2 Region.
  130. */
  131. const REGION_US_GOV1_FIPS = 's3-fips-us-gov-west-1.amazonaws.com';
  132. /**
  133. * The default endpoint.
  134. */
  135. const DEFAULT_URL = self::REGION_US_E1;
  136. /*%******************************************************************************************%*/
  137. // REGIONAL WEBSITE ENDPOINTS
  138. /**
  139. * Specify the queue URL for the US-Standard (Northern Virginia & Washington State) Website Region.
  140. */
  141. const REGION_US_E1_WEBSITE = 's3-website-us-east-1.amazonaws.com';
  142. /**
  143. * Specify the queue URL for the US-Standard (Northern Virginia & Washington State) Website Region.
  144. */
  145. const REGION_VIRGINIA_WEBSITE = self::REGION_US_E1_WEBSITE;
  146. /**
  147. * Specify the queue URL for the US-Standard (Northern Virginia & Washington State) Website Region.
  148. */
  149. const REGION_US_STANDARD_WEBSITE = self::REGION_US_E1_WEBSITE;
  150. /**
  151. * Specify the queue URL for the US-West 1 (Northern California) Website Region.
  152. */
  153. const REGION_US_W1_WEBSITE = 's3-website-us-west-1.amazonaws.com';
  154. /**
  155. * Specify the queue URL for the US-West 1 (Northern California) Website Region.
  156. */
  157. const REGION_CALIFORNIA_WEBSITE = self::REGION_US_W1_WEBSITE;
  158. /**
  159. * Specify the queue URL for the US-West 2 (Oregon) Website Region.
  160. */
  161. const REGION_US_W2_WEBSITE = 's3-website-us-west-2.amazonaws.com';
  162. /**
  163. * Specify the queue URL for the US-West 2 (Oregon) Website Region.
  164. */
  165. const REGION_OREGON_WEBSITE = self::REGION_US_W2_WEBSITE;
  166. /**
  167. * Specify the queue URL for the EU (Ireland) Website Region.
  168. */
  169. const REGION_EU_W1_WEBSITE = 's3-website-eu-west-1.amazonaws.com';
  170. /**
  171. * Specify the queue URL for the EU (Ireland) Website Region.
  172. */
  173. const REGION_IRELAND_WEBSITE = self::REGION_EU_W1_WEBSITE;
  174. /**
  175. * Specify the queue URL for the Asia Pacific (Singapore) Website Region.
  176. */
  177. const REGION_APAC_SE1_WEBSITE = 's3-website-ap-southeast-1.amazonaws.com';
  178. /**
  179. * Specify the queue URL for the Asia Pacific (Singapore) Website Region.
  180. */
  181. const REGION_SINGAPORE_WEBSITE = self::REGION_APAC_SE1_WEBSITE;
  182. /**
  183. * Specify the queue URL for the Asia Pacific (Sydney) Website Region.
  184. */
  185. const REGION_APAC_SE2_WEBSITE = 's3-website-ap-southeast-2.amazonaws.com';
  186. /**
  187. * Specify the queue URL for the Asia Pacific (Sydney) Website Region.
  188. */
  189. const REGION_SYDNEY_WEBSITE = self::REGION_APAC_SE2_WEBSITE;
  190. /**
  191. * Specify the queue URL for the Asia Pacific (Japan) Website Region.
  192. */
  193. const REGION_APAC_NE1_WEBSITE = 's3-website-ap-northeast-1.amazonaws.com';
  194. /**
  195. * Specify the queue URL for the Asia Pacific (Japan) Website Region.
  196. */
  197. const REGION_TOKYO_WEBSITE = self::REGION_APAC_NE1_WEBSITE;
  198. /**
  199. * Specify the queue URL for the South America (Sao Paulo) Website Region.
  200. */
  201. const REGION_SA_E1_WEBSITE = 's3-website-sa-east-1.amazonaws.com';
  202. /**
  203. * Specify the queue URL for the South America (Sao Paulo) Website Region.
  204. */
  205. const REGION_SAO_PAULO_WEBSITE = self::REGION_SA_E1_WEBSITE;
  206. /**
  207. * Specify the queue URL for the United States GovCloud Website Region.
  208. */
  209. const REGION_US_GOV1_WEBSITE = 's3-website-us-gov-west-1.amazonaws.com';
  210. /*%******************************************************************************************%*/
  211. // ACL
  212. /**
  213. * ACL: Owner-only read/write.
  214. */
  215. const ACL_PRIVATE = 'private';
  216. /**
  217. * ACL: Owner read/write, public read.
  218. */
  219. const ACL_PUBLIC = 'public-read';
  220. /**
  221. * ACL: Public read/write.
  222. */
  223. const ACL_OPEN = 'public-read-write';
  224. /**
  225. * ACL: Owner read/write, authenticated read.
  226. */
  227. const ACL_AUTH_READ = 'authenticated-read';
  228. /**
  229. * ACL: Bucket owner read.
  230. */
  231. const ACL_OWNER_READ = 'bucket-owner-read';
  232. /**
  233. * ACL: Bucket owner full control.
  234. */
  235. const ACL_OWNER_FULL_CONTROL = 'bucket-owner-full-control';
  236. /*%******************************************************************************************%*/
  237. // GRANTS
  238. /**
  239. * When applied to a bucket, grants permission to list the bucket. When applied to an object, this
  240. * grants permission to read the object data and/or metadata.
  241. */
  242. const GRANT_READ = 'READ';
  243. /**
  244. * When applied to a bucket, grants permission to create, overwrite, and delete any object in the
  245. * bucket. This permission is not supported for objects.
  246. */
  247. const GRANT_WRITE = 'WRITE';
  248. /**
  249. * Grants permission to read the ACL for the applicable bucket or object. The owner of a bucket or
  250. * object always has this permission implicitly.
  251. */
  252. const GRANT_READ_ACP = 'READ_ACP';
  253. /**
  254. * Gives permission to overwrite the ACP for the applicable bucket or object. The owner of a bucket
  255. * or object always has this permission implicitly. Granting this permission is equivalent to granting
  256. * FULL_CONTROL because the grant recipient can make any changes to the ACP.
  257. */
  258. const GRANT_WRITE_ACP = 'WRITE_ACP';
  259. /**
  260. * Provides READ, WRITE, READ_ACP, and WRITE_ACP permissions. It does not convey additional rights and
  261. * is provided only for convenience.
  262. */
  263. const GRANT_FULL_CONTROL = 'FULL_CONTROL';
  264. /*%******************************************************************************************%*/
  265. // USERS
  266. /**
  267. * The "AuthenticatedUsers" group for access control policies.
  268. */
  269. const USERS_AUTH = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers';
  270. /**
  271. * The "AllUsers" group for access control policies.
  272. */
  273. const USERS_ALL = 'http://acs.amazonaws.com/groups/global/AllUsers';
  274. /**
  275. * The "LogDelivery" group for access control policies.
  276. */
  277. const USERS_LOGGING = 'http://acs.amazonaws.com/groups/s3/LogDelivery';
  278. /*%******************************************************************************************%*/
  279. // PATTERNS
  280. /**
  281. * PCRE: Match all items
  282. */
  283. const PCRE_ALL = '/.*/i';
  284. /*%******************************************************************************************%*/
  285. // STORAGE
  286. /**
  287. * Standard storage redundancy.
  288. */
  289. const STORAGE_STANDARD = 'STANDARD';
  290. /**
  291. * Reduced storage redundancy.
  292. */
  293. const STORAGE_REDUCED = 'REDUCED_REDUNDANCY';
  294. /**
  295. * Storage in Glacier.
  296. */
  297. const STORAGE_GLACIER = 'GLACIER';
  298. /*%******************************************************************************************%*/
  299. // PROPERTIES
  300. /**
  301. * The request URL.
  302. */
  303. public $request_url;
  304. /**
  305. * The virtual host setting.
  306. */
  307. public $vhost;
  308. /**
  309. * The base XML elements to use for access control policy methods.
  310. */
  311. public $base_acp_xml;
  312. /**
  313. * The base XML elements to use for creating buckets in regions.
  314. */
  315. public $base_location_constraint;
  316. /**
  317. * The base XML elements to use for logging methods.
  318. */
  319. public $base_logging_xml;
  320. /**
  321. * The base XML elements to use for notifications.
  322. */
  323. public $base_notification_xml;
  324. /**
  325. * The base XML elements to use for versioning.
  326. */
  327. public $base_versioning_xml;
  328. /**
  329. * The base XML elements to use for completing a multipart upload.
  330. */
  331. public $complete_mpu_xml;
  332. /**
  333. * The base XML elements to use for website support.
  334. */
  335. public $website_config_xml;
  336. /**
  337. * The base XML elements to use for multi-object delete support.
  338. */
  339. public $multi_object_delete_xml;
  340. /**
  341. * The base XML elements to use for object expiration support.
  342. */
  343. public $object_expiration_xml;
  344. /**
  345. * The base XML elements to use for bucket tagging.
  346. */
  347. public $bucket_tagging_xml;
  348. /**
  349. * The base XML elements to use for CORS support.
  350. */
  351. public $cors_config_xml;
  352. /**
  353. * The base XML elements to use for restoration requests.
  354. */
  355. public $restore_request_xml;
  356. /**
  357. * The DNS vs. Path-style setting.
  358. */
  359. public $path_style = false;
  360. /**
  361. * The state of whether the prefix change is temporary or permanent.
  362. */
  363. public $temporary_prefix = false;
  364. /*%******************************************************************************************%*/
  365. // CONSTRUCTOR
  366. /**
  367. * Constructs a new instance of <AmazonS3>.
  368. *
  369. * @param array $options (Optional) An associative array of parameters that can have the following keys: <ul>
  370. * <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>
  371. * <li><code>credentials</code> - <code>string</code> - Optional - The name of the credential set to use for authentication.</li>
  372. * <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>
  373. * <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>
  374. * <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>
  375. * <li><code>token</code> - <code>string</code> - Optional - An AWS session token.</li></ul>
  376. * @return void
  377. */
  378. public function __construct(array $options = array())
  379. {
  380. $this->vhost = null;
  381. $this->api_version = '2006-03-01';
  382. $this->hostname = self::DEFAULT_URL;
  383. $this->base_acp_xml = '<?xml version="1.0" encoding="UTF-8"?><AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/latest/"/>';
  384. $this->base_location_constraint = '<?xml version="1.0" encoding="UTF-8"?><CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/' . $this->api_version . '/"><LocationConstraint/></CreateBucketConfiguration>';
  385. $this->base_logging_xml = '<?xml version="1.0" encoding="utf-8"?><BucketLoggingStatus xmlns="http://doc.s3.amazonaws.com/' . $this->api_version . '"/>';
  386. $this->base_notification_xml = '<?xml version="1.0" encoding="utf-8"?><NotificationConfiguration/>';
  387. $this->base_versioning_xml = '<?xml version="1.0" encoding="utf-8"?><VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/' . $this->api_version . '/"/>';
  388. $this->complete_mpu_xml = '<?xml version="1.0" encoding="utf-8"?><CompleteMultipartUpload/>';
  389. $this->website_config_xml = '<?xml version="1.0" encoding="utf-8"?><WebsiteConfiguration xmlns="http://s3.amazonaws.com/doc/' . $this->api_version . '/"><IndexDocument><Suffix>index.html</Suffix></IndexDocument><ErrorDocument><Key>error.html</Key></ErrorDocument></WebsiteConfiguration>';
  390. $this->multi_object_delete_xml = '<?xml version="1.0" encoding="utf-8"?><Delete/>';
  391. $this->object_expiration_xml = '<?xml version="1.0" encoding="utf-8"?><LifecycleConfiguration/>';
  392. $this->bucket_tagging_xml = '<?xml version="1.0" encoding="utf-8"?><Tagging><TagSet/></Tagging>';
  393. $this->cors_config_xml = '<?xml version="1.0" encoding="utf-8"?><CORSConfiguration />';
  394. $this->restore_request_xml = '<?xml version="1.0" encoding="utf-8"?><RestoreRequest xmlns="http://s3.amazonaws.com/doc/' . $this->api_version . '"/>';
  395. parent::__construct($options);
  396. }
  397. /*%******************************************************************************************%*/
  398. // AUTHENTICATION
  399. /**
  400. * Authenticates a connection to Amazon S3. Do not use directly unless implementing custom methods for
  401. * this class.
  402. *
  403. * @param string $operation (Required) The name of the bucket to operate on (S3 Only).
  404. * @param array $payload (Required) An associative array of parameters for authenticating. See inline comments for allowed keys.
  405. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  406. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/S3_Authentication.html REST authentication
  407. */
  408. public function authenticate($operation, $payload)
  409. {
  410. /*
  411. * Overriding or extending this class? You can pass the following "magic" keys into $opt.
  412. *
  413. * ## verb, resource, sub_resource and query_string ##
  414. * <verb> /<resource>?<sub_resource>&<query_string>
  415. * GET /filename.txt?versions&prefix=abc&max-items=1
  416. *
  417. * ## versionId, uploadId, partNumber, response-* ##
  418. * These don't follow the same rules as above, in that the they needs to be signed, while
  419. * other query_string values do not.
  420. *
  421. * ## curlopts ##
  422. * These values get passed directly to the cURL methods in RequestCore.
  423. *
  424. * ## fileUpload, fileDownload, seekTo ##
  425. * These are slightly modified and then passed to the cURL methods in RequestCore.
  426. *
  427. * ## headers ##
  428. * $opt['headers'] is an array, whose keys are HTTP headers to be sent.
  429. *
  430. * ## body ##
  431. * This is the request body that is sent to the server via PUT/POST.
  432. *
  433. * ## preauth ##
  434. * This is a hook that tells authenticate() to generate a pre-authenticated URL.
  435. *
  436. * ## returnCurlHandle ##
  437. * Tells authenticate() to return the cURL handle for the request instead of executing it.
  438. */
  439. // Rename variables (to overcome inheritence issues)
  440. $bucket = $operation;
  441. $opt = $payload;
  442. // Validate the S3 bucket name
  443. if (!$this->validate_bucketname_support($bucket))
  444. {
  445. // @codeCoverageIgnoreStart
  446. throw new S3_Exception('S3 does not support "' . $bucket . '" as a valid bucket name. Review "Bucket Restrictions and Limitations" in the S3 Developer Guide for more information.');
  447. // @codeCoverageIgnoreEnd
  448. }
  449. // Die if $opt isn't set.
  450. if (!$opt) return false;
  451. $method_arguments = func_get_args();
  452. // Use the caching flow to determine if we need to do a round-trip to the server.
  453. if ($this->use_cache_flow)
  454. {
  455. // Generate an identifier specific to this particular set of arguments.
  456. $cache_id = $this->key . '_' . get_class($this) . '_' . $bucket . '_' . sha1(serialize($method_arguments));
  457. // Instantiate the appropriate caching object.
  458. $this->cache_object = new $this->cache_class($cache_id, $this->cache_location, $this->cache_expires, $this->cache_compress);
  459. if ($this->delete_cache)
  460. {
  461. $this->use_cache_flow = false;
  462. $this->delete_cache = false;
  463. return $this->cache_object->delete();
  464. }
  465. // Invoke the cache callback function to determine whether to pull data from the cache or make a fresh request.
  466. $data = $this->cache_object->response_manager(array($this, 'cache_callback'), $method_arguments);
  467. if ($this->parse_the_response)
  468. {
  469. // Parse the XML body
  470. $data = $this->parse_callback($data);
  471. }
  472. // End!
  473. return $data;
  474. }
  475. // If we haven't already set a resource prefix and the bucket name isn't DNS-valid...
  476. if ((!$this->resource_prefix && !$this->validate_bucketname_create($bucket)) || $this->path_style)
  477. {
  478. // Fall back to the older path-style URI
  479. $this->set_resource_prefix('/' . $bucket);
  480. $this->temporary_prefix = true;
  481. }
  482. // If the bucket name has periods and we are using SSL, we need to switch to path style URLs
  483. $bucket_name_may_cause_ssl_wildcard_failures = false;
  484. if ($this->use_ssl && strpos($bucket, '.') !== false)
  485. {
  486. $bucket_name_may_cause_ssl_wildcard_failures = true;
  487. }
  488. // Determine hostname
  489. $scheme = $this->use_ssl ? 'https://' : 'http://';
  490. if ($bucket_name_may_cause_ssl_wildcard_failures || $this->resource_prefix || $this->path_style)
  491. {
  492. // Use bucket-in-path method
  493. $hostname = $this->hostname . $this->resource_prefix . (($bucket === '' || $this->resource_prefix === '/' . $bucket) ? '' : ('/' . $bucket));
  494. }
  495. else
  496. {
  497. $hostname = $this->vhost ? $this->vhost : (($bucket === '') ? $this->hostname : ($bucket . '.') . $this->hostname);
  498. }
  499. // Get the UTC timestamp in RFC 2616 format
  500. $date = gmdate(CFUtilities::DATE_FORMAT_RFC2616, time());
  501. // Storage for request parameters.
  502. $resource = '';
  503. $sub_resource = '';
  504. $querystringparams = array();
  505. $signable_querystringparams = array();
  506. $string_to_sign = '';
  507. $headers = array(
  508. 'Content-MD5' => '',
  509. 'Content-Type' => 'application/x-www-form-urlencoded',
  510. 'Date' => $date
  511. );
  512. /*%******************************************************************************************%*/
  513. // Do we have an authentication token?
  514. if ($this->auth_token)
  515. {
  516. $headers['X-Amz-Security-Token'] = $this->auth_token;
  517. }
  518. // Handle specific resources
  519. if (isset($opt['resource']))
  520. {
  521. $resource .= $opt['resource'];
  522. }
  523. // Merge query string values
  524. if (isset($opt['query_string']))
  525. {
  526. $querystringparams = array_merge($querystringparams, $opt['query_string']);
  527. }
  528. $query_string = $this->util->to_query_string($querystringparams);
  529. // Merge the signable query string values. Must be alphabetical.
  530. $signable_list = array(
  531. 'partNumber',
  532. 'response-cache-control',
  533. 'response-content-disposition',
  534. 'response-content-encoding',
  535. 'response-content-language',
  536. 'response-content-type',
  537. 'response-expires',
  538. 'uploadId',
  539. 'versionId'
  540. );
  541. foreach ($signable_list as $item)
  542. {
  543. if (isset($opt[$item]))
  544. {
  545. $signable_querystringparams[$item] = $opt[$item];
  546. }
  547. }
  548. $signable_query_string = $this->util->to_query_string($signable_querystringparams);
  549. // Merge the HTTP headers
  550. if (isset($opt['headers']))
  551. {
  552. $headers = array_merge($headers, $opt['headers']);
  553. }
  554. // Compile the URI to request
  555. $conjunction = '?';
  556. $signable_resource = '/' . str_replace('%2F', '/', rawurlencode($resource));
  557. $non_signable_resource = '';
  558. if (isset($opt['sub_resource']))
  559. {
  560. $signable_resource .= $conjunction . rawurlencode($opt['sub_resource']);
  561. $conjunction = '&';
  562. }
  563. if ($signable_query_string !== '')
  564. {
  565. $signable_query_string = $conjunction . $signable_query_string;
  566. $conjunction = '&';
  567. }
  568. if ($query_string !== '')
  569. {
  570. $non_signable_resource .= $conjunction . $query_string;
  571. $conjunction = '&';
  572. }
  573. if (substr($hostname, -1) === substr($signable_resource, 0, 1))
  574. {
  575. $signable_resource = ltrim($signable_resource, '/');
  576. }
  577. $this->request_url = $scheme . $hostname . $signable_resource . $signable_query_string . $non_signable_resource;
  578. if (isset($opt['location']))
  579. {
  580. $this->request_url = $opt['location'];
  581. }
  582. // Gather information to pass along to other classes.
  583. $helpers = array(
  584. 'utilities' => $this->utilities_class,
  585. 'request' => $this->request_class,
  586. 'response' => $this->response_class,
  587. );
  588. // Instantiate the request class
  589. $request = new $this->request_class($this->request_url, $this->proxy, $helpers, $this->credentials);
  590. // Update RequestCore settings
  591. $request->request_class = $this->request_class;
  592. $request->response_class = $this->response_class;
  593. $request->ssl_verification = $this->ssl_verification;
  594. // Pass along registered stream callbacks
  595. if ($this->registered_streaming_read_callback)
  596. {
  597. $request->register_streaming_read_callback($this->registered_streaming_read_callback);
  598. }
  599. if ($this->registered_streaming_write_callback)
  600. {
  601. $request->register_streaming_write_callback($this->registered_streaming_write_callback);
  602. }
  603. // Streaming uploads
  604. if (isset($opt['fileUpload']))
  605. {
  606. if (is_resource($opt['fileUpload']))
  607. {
  608. // Determine the length to read from the stream
  609. $length = null; // From current position until EOF by default, size determined by set_read_stream()
  610. if (isset($headers['Content-Length']))
  611. {
  612. $length = $headers['Content-Length'];
  613. }
  614. elseif (isset($opt['seekTo']))
  615. {
  616. // Read from seekTo until EOF by default
  617. $stats = fstat($opt['fileUpload']);
  618. if ($stats && $stats['size'] >= 0)
  619. {
  620. $length = $stats['size'] - (integer) $opt['seekTo'];
  621. }
  622. }
  623. $request->set_read_stream($opt['fileUpload'], $length);
  624. if ($headers['Content-Type'] === 'application/x-www-form-urlencoded')
  625. {
  626. $headers['Content-Type'] = 'application/octet-stream';
  627. }
  628. }
  629. else
  630. {
  631. $request->set_read_file($opt['fileUpload']);
  632. // Determine the length to read from the file
  633. $length = $request->read_stream_size; // The file size by default
  634. if (isset($headers['Content-Length']))
  635. {
  636. $length = $headers['Content-Length'];
  637. }
  638. elseif (isset($opt['seekTo']) && isset($length))
  639. {
  640. // Read from seekTo until EOF by default
  641. $length -= (integer) $opt['seekTo'];
  642. }
  643. $request->set_read_stream_size($length);
  644. // Attempt to guess the correct mime-type
  645. if ($headers['Content-Type'] === 'application/x-www-form-urlencoded')
  646. {
  647. $extension = explode('.', $opt['fileUpload']);
  648. $extension = array_pop($extension);
  649. $mime_type = CFMimeTypes::get_mimetype($extension);
  650. $headers['Content-Type'] = $mime_type;
  651. }
  652. }
  653. $headers['Content-Length'] = $request->read_stream_size;
  654. $headers['Content-MD5'] = '';
  655. }
  656. // Handle streaming file offsets
  657. if (isset($opt['seekTo']))
  658. {
  659. // Pass the seek position to RequestCore
  660. $request->set_seek_position((integer) $opt['seekTo']);
  661. }
  662. // Streaming downloads
  663. if (isset($opt['fileDownload']))
  664. {
  665. if (is_resource($opt['fileDownload']))
  666. {
  667. $request->set_write_stream($opt['fileDownload']);
  668. }
  669. else
  670. {
  671. $request->set_write_file($opt['fileDownload']);
  672. }
  673. }
  674. $curlopts = array();
  675. // Set custom CURLOPT settings
  676. if (isset($opt['curlopts']))
  677. {
  678. $curlopts = $opt['curlopts'];
  679. }
  680. // Debug mode
  681. if ($this->debug_mode)
  682. {
  683. $curlopts[CURLOPT_VERBOSE] = true;
  684. }
  685. // Set the curl options.
  686. if (count($curlopts))
  687. {
  688. $request->set_curlopts($curlopts);
  689. }
  690. // Do we have a verb?
  691. if (isset($opt['verb']))
  692. {
  693. $request->set_method($opt['verb']);
  694. $string_to_sign .= $opt['verb'] . "\n";
  695. }
  696. // Add headers and content when we have a body
  697. if (isset($opt['body']))
  698. {
  699. $request->set_body($opt['body']);
  700. $headers['Content-Length'] = strlen($opt['body']);
  701. if ($headers['Content-Type'] === 'application/x-www-form-urlencoded')
  702. {
  703. $headers['Content-Type'] = 'application/octet-stream';
  704. }
  705. if (!isset($opt['NoContentMD5']) || $opt['NoContentMD5'] !== true)
  706. {
  707. $headers['Content-MD5'] = $this->util->hex_to_base64(md5($opt['body']));
  708. }
  709. }
  710. // Handle query-string authentication
  711. if (isset($opt['preauth']) && (integer) $opt['preauth'] > 0)
  712. {
  713. unset($headers['Date']);
  714. $headers['Content-Type'] = '';
  715. $headers['Expires'] = is_int($opt['preauth']) ? $opt['preauth'] : strtotime($opt['preauth']);
  716. }
  717. // Sort headers
  718. uksort($headers, 'strnatcasecmp');
  719. // Add headers to request and compute the string to sign
  720. foreach ($headers as $header_key => $header_value)
  721. {
  722. // Strip linebreaks from header values as they're illegal and can allow for security issues
  723. $header_value = str_replace(array("\r", "\n"), '', $header_value);
  724. // Add the header if it has a value
  725. if ($header_value !== '')
  726. {
  727. $request->add_header($header_key, $header_value);
  728. }
  729. // Generate the string to sign
  730. if (
  731. strtolower($header_key) === 'content-md5' ||
  732. strtolower($header_key) === 'content-type' ||
  733. strtolower($header_key) === 'date' ||
  734. (strtolower($header_key) === 'expires' && isset($opt['preauth']) && (integer) $opt['preauth'] > 0)
  735. )
  736. {
  737. $string_to_sign .= $header_value . "\n";
  738. }
  739. elseif (substr(strtolower($header_key), 0, 6) === 'x-amz-')
  740. {
  741. $string_to_sign .= strtolower($header_key) . ':' . $header_value . "\n";
  742. }
  743. }
  744. // Add the signable resource location
  745. $string_to_sign .= ($this->resource_prefix ? $this->resource_prefix : '');
  746. $string_to_sign .= (($bucket === '' || $this->resource_prefix === '/' . $bucket) ? '' : ('/' . $bucket)) . $signable_resource . urldecode($signable_query_string);
  747. // Hash the AWS secret key and generate a signature for the request.
  748. $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $this->secret_key, true));
  749. $request->add_header('Authorization', 'AWS ' . $this->key . ':' . $signature);
  750. // If we're generating a URL, return the URL to the calling method.
  751. if (isset($opt['preauth']) && (integer) $opt['preauth'] > 0)
  752. {
  753. $query_params = array(
  754. 'AWSAccessKeyId' => $this->key,
  755. 'Expires' => $headers['Expires'],
  756. 'Signature' => $signature,
  757. );
  758. // If using short-term credentials, add the token to the query string
  759. if ($this->auth_token)
  760. {
  761. $query_params['x-amz-security-token'] = $this->auth_token;
  762. }
  763. return $this->request_url . $conjunction . http_build_query($query_params, '', '&');
  764. }
  765. elseif (isset($opt['preauth']))
  766. {
  767. return $this->request_url;
  768. }
  769. /*%******************************************************************************************%*/
  770. // If our changes were temporary, reset them.
  771. if ($this->temporary_prefix)
  772. {
  773. $this->temporary_prefix = false;
  774. $this->resource_prefix = null;
  775. }
  776. // Manage the (newer) batch request API or the (older) returnCurlHandle setting.
  777. if ($this->use_batch_flow)
  778. {
  779. $handle = $request->prep_request();
  780. $this->batch_object->add($handle);
  781. $this->use_batch_flow = false;
  782. return $handle;
  783. }
  784. elseif (isset($opt['returnCurlHandle']) && $opt['returnCurlHandle'] === true)
  785. {
  786. return $request->prep_request();
  787. }
  788. // Send!
  789. $request->send_request();
  790. // Prepare the response
  791. $headers = $request->get_response_header();
  792. $headers['x-aws-request-url'] = $this->request_url;
  793. $headers['x-aws-redirects'] = $this->redirects;
  794. $headers['x-aws-stringtosign'] = $string_to_sign;
  795. $headers['x-aws-requestheaders'] = $request->request_headers;
  796. // Did we have a request body?
  797. if (isset($opt['body']))
  798. {
  799. $headers['x-aws-requestbody'] = $opt['body'];
  800. }
  801. $data = new $this->response_class($headers, $this->parse_callback($request->get_response_body()), $request->get_response_code());
  802. // Did Amazon tell us to redirect? Typically happens for multiple rapid requests EU datacenters.
  803. // @see: http://docs.amazonwebservices.com/AmazonS3/latest/dev/Redirects.html
  804. // @codeCoverageIgnoreStart
  805. if ((integer) $request->get_response_code() === 307) // Temporary redirect to new endpoint.
  806. {
  807. $this->redirects++;
  808. $opt['location'] = $headers['location'];
  809. $data = $this->authenticate($bucket, $opt);
  810. }
  811. // Was it Amazon's fault the request failed? Retry the request until we reach $max_retries.
  812. elseif ((integer) $request->get_response_code() === 500 || (integer) $request->get_response_code() === 503)
  813. {
  814. if ($this->redirects <= $this->max_retries)
  815. {
  816. // Exponential backoff
  817. $delay = (integer) (pow(4, $this->redirects) * 100000);
  818. usleep($delay);
  819. $this->redirects++;
  820. $data = $this->authenticate($bucket, $opt);
  821. }
  822. }
  823. // @codeCoverageIgnoreEnd
  824. // Return!
  825. $this->redirects = 0;
  826. return $data;
  827. }
  828. /**
  829. * Validates whether or not the specified Amazon S3 bucket name is valid for DNS-style access. This
  830. * method is leveraged by any method that creates buckets.
  831. *
  832. * @param string $bucket (Required) The name of the bucket to validate.
  833. * @return boolean Whether or not the specified Amazon S3 bucket name is valid for DNS-style access. A value of <code>true</code> means that the bucket name is valid. A value of <code>false</code> means that the bucket name is invalid.
  834. */
  835. public function validate_bucketname_create($bucket)
  836. {
  837. // list_buckets() uses this. Let it pass.
  838. if ($bucket === '') return true;
  839. if (
  840. ($bucket === null || $bucket === false) || // Must not be null or false
  841. preg_match('/[^(a-z0-9\-\.)]/', $bucket) || // Must be in the lowercase Roman alphabet, period or hyphen
  842. !preg_match('/^([a-z]|\d)/', $bucket) || // Must start with a number or letter
  843. !(strlen($bucket) >= 3 && strlen($bucket) <= 63) || // Must be between 3 and 63 characters long
  844. (strpos($bucket, '..') !== false) || // Bucket names cannot contain two, adjacent periods
  845. (strpos($bucket, '-.') !== false) || // Bucket names cannot contain dashes next to periods
  846. (strpos($bucket, '.-') !== false) || // Bucket names cannot contain dashes next to periods
  847. preg_match('/(-|\.)$/', $bucket) || // Bucket names should not end with a dash or period
  848. preg_match('/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/', $bucket) // Must not be formatted as an IP address
  849. ) return false;
  850. return true;
  851. }
  852. /**
  853. * Validates whether or not the specified Amazon S3 bucket name is valid for path-style access. This
  854. * method is leveraged by any method that reads from buckets.
  855. *
  856. * @param string $bucket (Required) The name of the bucket to validate.
  857. * @return boolean Whether or not the bucket name is valid. A value of <code>true</code> means that the bucket name is valid. A value of <code>false</code> means that the bucket name is invalid.
  858. */
  859. public function validate_bucketname_support($bucket)
  860. {
  861. // list_buckets() uses this. Let it pass.
  862. if ($bucket === '') return true;
  863. // Validate
  864. if (
  865. ($bucket === null || $bucket === false) || // Must not be null or false
  866. preg_match('/[^(a-z0-9_\-\.)]/i', $bucket) || // Must be in the Roman alphabet, period, hyphen or underscore
  867. !preg_match('/^([a-z]|\d)/i', $bucket) || // Must start with a number or letter
  868. !(strlen($bucket) >= 3 && strlen($bucket) <= 255) || // Must be between 3 and 255 characters long
  869. preg_match('/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/', $bucket) // Must not be formatted as an IP address
  870. ) return false;
  871. return true;
  872. }
  873. /*%******************************************************************************************%*/
  874. // SETTERS
  875. /**
  876. * Sets the region to use for subsequent Amazon S3 operations. This will also reset any prior use of
  877. * <enable_path_style()>.
  878. *
  879. * @param string $region (Required) The region to use for subsequent Amazon S3 operations. For a complete list of REGION constants, see the <code>AmazonS3</code> Constants page in the API reference.
  880. * @return $this A reference to the current instance.
  881. */
  882. public function set_region($region)
  883. {
  884. // @codeCoverageIgnoreStart
  885. $this->set_hostname($region);
  886. switch ($region)
  887. {
  888. case self::REGION_US_E1: // Northern Virginia
  889. $this->enable_path_style(false);
  890. break;
  891. case self::REGION_EU_W1: // Ireland
  892. $this->enable_path_style(); // Always use path-style access for EU endpoint.
  893. break;
  894. default:
  895. $this->enable_path_style(false);
  896. break;
  897. }
  898. // @codeCoverageIgnoreEnd
  899. return $this;
  900. }
  901. /**
  902. * Sets the virtual host to use in place of the default `bucket.s3.amazonaws.com` domain.
  903. *
  904. * @param string $vhost (Required) The virtual host to use in place of the default `bucket.s3.amazonaws.com` domain.
  905. * @return $this A reference to the current instance.
  906. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/VirtualHosting.html Virtual Hosting of Buckets
  907. */
  908. public function set_vhost($vhost)
  909. {
  910. $this->vhost = $vhost;
  911. return $this;
  912. }
  913. /**
  914. * Enables the use of the older path-style URI access for all requests.
  915. *
  916. * @param string $style (Optional) Whether or not to enable path-style URI access for all requests. The default value is <code>true</code>.
  917. * @return $this A reference to the current instance.
  918. */
  919. public function enable_path_style($style = true)
  920. {
  921. $this->path_style = $style;
  922. return $this;
  923. }
  924. /*%******************************************************************************************%*/
  925. // BUCKET METHODS
  926. /**
  927. * Creates an Amazon S3 bucket.
  928. *
  929. * Every object stored in Amazon S3 is contained in a bucket. Buckets partition the namespace of
  930. * objects stored in Amazon S3 at the top level. in a bucket, any name can be used for objects.
  931. * However, bucket names must be unique across all of Amazon S3.
  932. *
  933. * @param string $bucket (Required) The name of the bucket to create.
  934. * @param string $region (Required) The preferred geographical location for the bucket. [Allowed values: `AmazonS3::REGION_US_E1 `, `AmazonS3::REGION_US_W1`, `AmazonS3::REGION_EU_W1`, `AmazonS3::REGION_APAC_SE1`, `AmazonS3::REGION_APAC_NE1`]
  935. * @param string $acl (Optional) The ACL settings for the specified object. Accepts any of the following constants: [Allowed values: <code>AmazonS3::ACL_PRIVATE</code>, <code>AmazonS3::ACL_PUBLIC</code>, <code>AmazonS3::ACL_OPEN</code>, <code>AmazonS3::ACL_AUTH_READ</code>, <code>AmazonS3::ACL_OWNER_READ</code>, <code>AmazonS3::ACL_OWNER_FULL_CONTROL</code>]. Alternatively, an array of associative arrays. Each associative array contains an <code>id</code> and a <code>permission</code> key. The default value is <code>ACL_PRIVATE</code>.
  936. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  937. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  938. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request.</li></ul>
  939. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  940. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/UsingBucket.html Working with Amazon S3 Buckets
  941. */
  942. public function create_bucket($bucket, $region, $acl = self::ACL_PRIVATE, $opt = null)
  943. {
  944. // If the bucket contains uppercase letters...
  945. if (preg_match('/[A-Z]/', $bucket))
  946. {
  947. // Throw a warning
  948. trigger_error('Since DNS-valid bucket names cannot contain uppercase characters, "' . $bucket . '" has been automatically converted to "' . strtolower($bucket) . '"', E_USER_WARNING);
  949. // Force the bucketname to lowercase
  950. $bucket = strtolower($bucket);
  951. }
  952. // Validate the S3 bucket name for creation
  953. if (!$this->validate_bucketname_create($bucket))
  954. {
  955. // @codeCoverageIgnoreStart
  956. throw new S3_Exception('"' . $bucket . '" is not DNS-valid (i.e., <bucketname>.s3.amazonaws.com), and cannot be used as an S3 bucket name. Review "Bucket Restrictions and Limitations" in the S3 Developer Guide for more information.');
  957. // @codeCoverageIgnoreEnd
  958. }
  959. if (!$opt) $opt = array();
  960. $opt['verb'] = 'PUT';
  961. $opt['headers'] = array(
  962. 'Content-Type' => 'application/xml'
  963. );
  964. // Handle Access Control Lists. Can also be passed as an HTTP header.
  965. if (isset($acl))
  966. {
  967. if (is_array($acl))
  968. {
  969. $opt['headers'] = array_merge($opt['headers'], $this->generate_access_policy_headers($acl));
  970. }
  971. else
  972. {
  973. $opt['headers']['x-amz-acl'] = $acl;
  974. }
  975. }
  976. // Defaults
  977. $this->set_region($region); // Also sets path-style
  978. $xml = simplexml_load_string($this->base_location_constraint);
  979. switch ($region)
  980. {
  981. case self::REGION_US_E1: // Northern Virginia
  982. $opt['body'] = '';
  983. break;
  984. case self::REGION_EU_W1: // Ireland
  985. $xml->LocationConstraint = 'EU';
  986. $opt['body'] = $xml->asXML();
  987. break;
  988. default:
  989. $xml->LocationConstraint = str_replace(array('s3-', '.amazonaws.com'), '', $region);
  990. $opt['body'] = $xml->asXML();
  991. break;
  992. }
  993. $response = $this->authenticate($bucket, $opt);
  994. // Make sure we're set back to DNS-style URLs
  995. $this->enable_path_style(false);
  996. return $response;
  997. }
  998. /**
  999. * Gets the region in which the specified Amazon S3 bucket is located.
  1000. *
  1001. * @param string $bucket (Required) The name of the bucket to use.
  1002. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1003. * <li><code>preauth</code> - <code>integer|string</code> - Optional - Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.</li>
  1004. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1005. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1006. */
  1007. public function get_bucket_region($bucket, $opt = null)
  1008. {
  1009. // Add this to our request
  1010. if (!$opt) $opt = array();
  1011. $opt['verb'] = 'GET';
  1012. $opt['sub_resource'] = 'location';
  1013. // Authenticate to S3
  1014. $response = $this->authenticate($bucket, $opt);
  1015. if ($response->isOK())
  1016. {
  1017. // Handle body
  1018. $response->body = (string) $response->body;
  1019. }
  1020. return $response;
  1021. }
  1022. /**
  1023. * Gets the HTTP headers for the specified Amazon S3 bucket.
  1024. *
  1025. * @param string $bucket (Required) The name of the bucket to use.
  1026. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1027. * <li><code>preauth</code> - <code>integer|string</code> - Optional - Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.</li>
  1028. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1029. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1030. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1031. */
  1032. public function get_bucket_headers($bucket, $opt = null)
  1033. {
  1034. if (!$opt) $opt = array();
  1035. $opt['verb'] = 'HEAD';
  1036. return $this->authenticate($bucket, $opt);
  1037. }
  1038. /**
  1039. * Deletes a bucket from an Amazon S3 account. A bucket must be empty before the bucket itself can be deleted.
  1040. *
  1041. * @param string $bucket (Required) The name of the bucket to use.
  1042. * @param boolean $force (Optional) Whether to force-delete the bucket and all of its contents. The default value is <code>false</code>.
  1043. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1044. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1045. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1046. * @return mixed A <CFResponse> object if the bucket was deleted successfully. Returns boolean <code>false</code> if otherwise.
  1047. */
  1048. public function delete_bucket($bucket, $force = false, $opt = null)
  1049. {
  1050. // Set default value
  1051. $success = true;
  1052. if ($force)
  1053. {
  1054. // Delete all of the items from the bucket.
  1055. $success = $this->delete_all_object_versions($bucket);
  1056. }
  1057. // As long as we were successful...
  1058. if ($success)
  1059. {
  1060. if (!$opt) $opt = array();
  1061. $opt['verb'] = 'DELETE';
  1062. return $this->authenticate($bucket, $opt);
  1063. }
  1064. // @codeCoverageIgnoreStart
  1065. return false;
  1066. // @codeCoverageIgnoreEnd
  1067. }
  1068. /**
  1069. * Gets a list of all buckets contained in the caller's Amazon S3 account.
  1070. *
  1071. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1072. * <li><code>preauth</code> - <code>integer|string</code> - Optional - Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.</li>
  1073. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1074. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1075. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1076. */
  1077. public function list_buckets($opt = null)
  1078. {
  1079. if (!$opt) $opt = array();
  1080. $opt['verb'] = 'GET';
  1081. return $this->authenticate('', $opt);
  1082. }
  1083. /**
  1084. * Gets the access control list (ACL) settings for the specified Amazon S3 bucket.
  1085. *
  1086. * @param string $bucket (Required) The name of the bucket to use.
  1087. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1088. * <li><code>preauth</code> - <code>integer|string</code> - Optional - Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.</li>
  1089. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1090. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1091. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1092. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAccessPolicy.html REST Access Control Policy
  1093. */
  1094. public function get_bucket_acl($bucket, $opt = null)
  1095. {
  1096. // Add this to our request
  1097. if (!$opt) $opt = array();
  1098. $opt['verb'] = 'GET';
  1099. $opt['sub_resource'] = 'acl';
  1100. // Authenticate to S3
  1101. return $this->authenticate($bucket, $opt);
  1102. }
  1103. /**
  1104. * Sets the access control list (ACL) settings for the specified Amazon S3 bucket.
  1105. *
  1106. * @param string $bucket (Required) The name of the bucket to use.
  1107. * @param string $acl (Optional) The ACL settings for the specified bucket. [Allowed values: <code>AmazonS3::ACL_PRIVATE</code>, <code>AmazonS3::ACL_PUBLIC</code>, <code>AmazonS3::ACL_OPEN</code>, <code>AmazonS3::ACL_AUTH_READ</code>, <code>AmazonS3::ACL_OWNER_READ</code>, <code>AmazonS3::ACL_OWNER_FULL_CONTROL</code>]. Alternatively, an array of associative arrays. Each associative array contains an `id` and a `permission` key. The default value is <ACL_PRIVATE>.
  1108. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1109. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1110. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1111. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1112. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAccessPolicy.html REST Access Control Policy
  1113. */
  1114. public function set_bucket_acl($bucket, $acl = self::ACL_PRIVATE, $opt = null)
  1115. {
  1116. // Add this to our request
  1117. if (!$opt) $opt = array();
  1118. $opt['verb'] = 'PUT';
  1119. $opt['sub_resource'] = 'acl';
  1120. $opt['headers'] = array(
  1121. 'Content-Type' => 'application/xml'
  1122. );
  1123. // Make sure these are defined.
  1124. // @codeCoverageIgnoreStart
  1125. if (!$this->credentials->canonical_id || !$this->credentials->canonical_name)
  1126. {
  1127. // Fetch the data live.
  1128. $canonical = $this->get_canonical_user_id();
  1129. $this->credentials->canonical_id = $canonical['id'];
  1130. $this->credentials->canonical_name = $canonical['display_name'];
  1131. }
  1132. // @codeCoverageIgnoreEnd
  1133. if (is_array($acl))
  1134. {
  1135. $opt['headers'] = array_merge($opt['headers'], $this->generate_access_policy_headers($acl));
  1136. }
  1137. else
  1138. {
  1139. $opt['body'] = '';
  1140. $opt['headers']['x-amz-acl'] = $acl;
  1141. }
  1142. // Authenticate to S3
  1143. return $this->authenticate($bucket, $opt);
  1144. }
  1145. /*%******************************************************************************************%*/
  1146. // OBJECT METHODS
  1147. /**
  1148. * Creates an Amazon S3 object. After an Amazon S3 bucket is created, objects can be stored in it.
  1149. *
  1150. * Each standard object can hold up to 5 GB of data. When an object is stored in Amazon S3, the data is streamed
  1151. * to multiple storage servers in multiple data centers. This ensures the data remains available in the
  1152. * event of internal network or hardware failure.
  1153. *
  1154. * @param string $bucket (Required) The name of the bucket to use.
  1155. * @param string $filename (Required) The file name for the object.
  1156. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1157. * <li><code>acl</code> - <code>string</code> - Optional - The ACL settings for the specified object. Accepts any of the following constants: [Allowed values: <code>AmazonS3::ACL_PRIVATE</code>, <code>AmazonS3::ACL_PUBLIC</code>, <code>AmazonS3::ACL_OPEN</code>, <code>AmazonS3::ACL_AUTH_READ</code>, <code>AmazonS3::ACL_OWNER_READ</code>, <code>AmazonS3::ACL_OWNER_FULL_CONTROL</code>]. Alternatively, an array of associative arrays. Each associative array contains an <code>id</code> and a <code>permission</code> key. The default value is <code>ACL_PRIVATE</code>.</li>
  1158. * <li><code>body</code> - <code>string</code> - Required; Conditional - The data to be stored in the object. Either this parameter or <code>fileUpload</code> must be specified.</li>
  1159. * <li><code>contentType</code> - <code>string</code> - Optional - The type of content that is being sent in the body. If a file is being uploaded via <code>fileUpload</code> as a file system path, it will attempt to determine the correct mime-type based on the file extension. The default value is <code>application/octet-stream</code>.</li>
  1160. * <li><code>encryption</code> - <code>string</code> - Optional - The algorithm to use for encrypting the object. [Allowed values: <code>AES256</code>]</li>
  1161. * <li><code>fileUpload</code> - <code>string|resource</code> - Required; Conditional - The URL/path for the file to upload, or an open resource. Either this parameter or <code>body</code> is required.</li>
  1162. * <li><code>headers</code> - <code>array</code> - Optional - Standard HTTP headers to send along in the request. Accepts an associative array of key-value pairs.</li>
  1163. * <li><code>length</code> - <code>integer</code> - Optional - The size of the object in bytes. For more information, see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13">RFC 2616, section 14.13</a>. The value can also be passed to the <code>header</code> option as <code>Content-Length</code>.</li>
  1164. * <li><code>meta</code> - <code>array</code> - Optional - An associative array of key-value pairs. Represented by <code>x-amz-meta-:</code>. Any header starting with this prefix is considered user metadata. It will be stored with the object and returned when you retrieve the object. The total size of the HTTP request, not including the body, must be less than 4 KB.</li>
  1165. * <li><code>redirectTo</code> - <code>string</code> - Optional - The URI to send an HTTP 301 redirect to when accessing this object. Value must be prefixed either <code>/</code>, <code>http://</code> or <code>https://</code>.</li>
  1166. * <li><code>seekTo</code> - <code>integer</code> - Optional - The starting position in bytes within the file/stream to upload from.</li>
  1167. * <li><code>storage</code> - <code>string</code> - Optional - Whether to use Standard or Reduced Redundancy storage. [Allowed values: <code>AmazonS3::STORAGE_STANDARD</code>, <code>AmazonS3::STORAGE_REDUCED</code>]. The default value is <code>STORAGE_STANDARD</code>.</li>
  1168. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1169. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1170. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1171. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAccessPolicy.html REST Access Control Policy
  1172. */
  1173. public function create_object($bucket, $filename, $opt = null)
  1174. {
  1175. if (!$opt) $opt = array();
  1176. // Add this to our request
  1177. $opt['verb'] = 'PUT';
  1178. $opt['resource'] = $filename;
  1179. // Handle content length. Can also be passed as an HTTP header.
  1180. if (isset($opt['length']))
  1181. {
  1182. $opt['headers']['Content-Length'] = $opt['length'];
  1183. unset($opt['length']);
  1184. }
  1185. // Handle content type. Can also be passed as an HTTP header.
  1186. if (isset($opt['contentType']))
  1187. {
  1188. $opt['headers']['Content-Type'] = $opt['contentType'];
  1189. unset($opt['contentType']);
  1190. }
  1191. // Handle Access Control Lists. Can also be passed as an HTTP header.
  1192. if (isset($opt['acl']))
  1193. {
  1194. if (is_array($opt['acl']))
  1195. {
  1196. $opt['headers'] = array_merge($opt['headers'], $this->generate_access_policy_headers($opt['acl']));
  1197. }
  1198. else
  1199. {
  1200. $opt['headers']['x-amz-acl'] = $opt['acl'];
  1201. }
  1202. }
  1203. // Handle storage settings. Can also be passed as an HTTP header.
  1204. if (isset($opt['storage']))
  1205. {
  1206. $opt['headers']['x-amz-storage-class'] = $opt['storage'];
  1207. unset($opt['storage']);
  1208. }
  1209. // Handle encryption settings. Can also be passed as an HTTP header.
  1210. if (isset($opt['encryption']))
  1211. {
  1212. $opt['headers']['x-amz-server-side-encryption'] = $opt['encryption'];
  1213. unset($opt['encryption']);
  1214. }
  1215. // URI to redirect to. Can also be passed as an HTTP header.
  1216. if (isset($opt['redirectTo']))
  1217. {
  1218. $opt['headers']['x-amz-website-redirect-location'] = $opt['redirectTo'];
  1219. unset($opt['redirectTo']);
  1220. }
  1221. // Handle meta tags. Can also be passed as an HTTP header.
  1222. if (isset($opt['meta']))
  1223. {
  1224. foreach ($opt['meta'] as $meta_key => $meta_value)
  1225. {
  1226. // e.g., `My Meta Header` is converted to `x-amz-meta-my-meta-header`.
  1227. $opt['headers']['x-amz-meta-' . strtolower(str_replace(' ', '-', $meta_key))] = $meta_value;
  1228. }
  1229. unset($opt['meta']);
  1230. }
  1231. $opt['headers']['Expect'] = '100-continue';
  1232. // Authenticate to S3
  1233. return $this->authenticate($bucket, $opt);
  1234. }
  1235. /**
  1236. * Gets the contents of an Amazon S3 object in the specified bucket.
  1237. *
  1238. * The MD5 value for an object can be retrieved from the ETag HTTP header for any object that was uploaded
  1239. * with a normal PUT/POST. This value is incorrect for multipart uploads.
  1240. *
  1241. * @param string $bucket (Required) The name of the bucket to use.
  1242. * @param string $filename (Required) The file name for the object.
  1243. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1244. * <li><code>etag</code> - <code>string</code> - Optional - The <code>ETag</code> header passed in from a previous request. If specified, request <code>LastModified</code> option must be specified as well. Will trigger a <code>304 Not Modified</code> status code if the file hasn't changed.</li>
  1245. * <li><code>fileDownload</code> - <code>string|resource</code> - Optional - The file system location to download the file to, or an open file resource. Must be a server-writable location.</li>
  1246. * <li><code>headers</code> - <code>array</code> - Optional - Standard HTTP headers to send along in the request. Accepts an associative array of key-value pairs.</li>
  1247. * <li><code>lastmodified</code> - <code>string</code> - Optional - The <code>LastModified</code> header passed in from a previous request. If specified, request <code>ETag</code> option must be specified as well. Will trigger a <code>304 Not Modified</code> status code if the file hasn't changed.</li>
  1248. * <li><code>preauth</code> - <code>integer|string</code> - Optional - Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.</li>
  1249. * <li><code>range</code> - <code>string</code> - Optional - The range of bytes to fetch from the object. Specify this parameter when downloading partial bits or completing incomplete object downloads. The specified range must be notated with a hyphen (e.g., 0-10485759). Defaults to the byte range of the complete Amazon S3 object.</li>
  1250. * <li><code>response</code> - <code>array</code> - Optional - Allows adjustments to specific response headers. Pass an associative array where each key is one of the following: <code>cache-control</code>, <code>content-disposition</code>, <code>content-encoding</code>, <code>content-language</code>, <code>content-type</code>, <code>expires</code>. The <code>expires</code> value should use <php:gmdate()> and be formatted with the <code>DATE_RFC2822</code> constant.</li>
  1251. * <li><code>versionId</code> - <code>string</code> - Optional - The version of the object to retrieve. Version IDs are returned in the <code>x-amz-version-id</code> header of any previous object-related request.</li>
  1252. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1253. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1254. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1255. */
  1256. public function get_object($bucket, $filename, $opt = null)
  1257. {
  1258. if (!$opt) $opt = array();
  1259. // Add this to our request
  1260. $opt['verb'] = 'GET';
  1261. $opt['resource'] = $filename;
  1262. if (!isset($opt['headers']) || !is_array($opt['headers']))
  1263. {
  1264. $opt['headers'] = array();
  1265. }
  1266. if (isset($opt['lastmodified']))
  1267. {
  1268. $opt['headers']['If-Modified-Since'] = $opt['lastmodified'];
  1269. }
  1270. if (isset($opt['etag']))
  1271. {
  1272. $opt['headers']['If-None-Match'] = $opt['etag'];
  1273. }
  1274. // Partial content range
  1275. if (isset($opt['range']))
  1276. {
  1277. $opt['headers']['Range'] = 'bytes=' . $opt['range'];
  1278. }
  1279. // GET responses
  1280. if (isset($opt['response']))
  1281. {
  1282. foreach ($opt['response'] as $key => $value)
  1283. {
  1284. $opt['response-' . $key] = $value;
  1285. unset($opt['response'][$key]);
  1286. }
  1287. }
  1288. // Authenticate to S3
  1289. $this->parse_the_response = false;
  1290. $response = $this->authenticate($bucket, $opt);
  1291. $this->parse_the_response = true;
  1292. return $response;
  1293. }
  1294. /**
  1295. * Gets the HTTP headers for the specified Amazon S3 object.
  1296. *
  1297. * The MD5 value for an object can be retrieved from the ETag HTTP header for any object that was uploaded
  1298. * with a normal PUT/POST. This value is incorrect for multipart uploads.
  1299. *
  1300. * @param string $bucket (Required) The name of the bucket to use.
  1301. * @param string $filename (Required) The file name for the object.
  1302. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1303. * <li><code>versionId</code> - <code>string</code> - Optional - The version of the object to retrieve. Version IDs are returned in the <code>x-amz-version-id</code> header of any previous object-related request.</li>
  1304. * <li><code>preauth</code> - <code>integer|string</code> - Optional - Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.</li>
  1305. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1306. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1307. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1308. */
  1309. public function get_object_headers($bucket, $filename, $opt = null)
  1310. {
  1311. // Add this to our request
  1312. if (!$opt) $opt = array();
  1313. $opt['verb'] = 'HEAD';
  1314. $opt['resource'] = $filename;
  1315. // Authenticate to S3
  1316. return $this->authenticate($bucket, $opt);
  1317. }
  1318. /**
  1319. * Deletes an Amazon S3 object from the specified bucket.
  1320. *
  1321. * @param string $bucket (Required) The name of the bucket to use.
  1322. * @param string $filename (Required) The file name for the object.
  1323. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1324. * <li><code>versionId</code> - <code>string</code> - Optional - The version of the object to delete. Version IDs are returned in the <code>x-amz-version-id</code> header of any previous object-related request.</li>
  1325. * <li><code>MFASerial</code> - <code>string</code> - Optional - The serial number on the back of the Gemalto device. <code>MFASerial</code> and <code>MFAToken</code> must both be set for MFA to work.</li>
  1326. * <li><code>MFAToken</code> - <code>string</code> - Optional - The current token displayed on the Gemalto device. <code>MFASerial</code> and <code>MFAToken</code> must both be set for MFA to work.</li>
  1327. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1328. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1329. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1330. * @link http://aws.amazon.com/mfa/ Multi-Factor Authentication
  1331. */
  1332. public function delete_object($bucket, $filename, $opt = null)
  1333. {
  1334. // Add this to our request
  1335. if (!$opt) $opt = array();
  1336. $opt['verb'] = 'DELETE';
  1337. $opt['resource'] = $filename;
  1338. // Enable MFA delete?
  1339. // @codeCoverageIgnoreStart
  1340. if (isset($opt['MFASerial']) && isset($opt['MFAToken']))
  1341. {
  1342. $opt['headers'] = array(
  1343. 'x-amz-mfa' => ($opt['MFASerial'] . ' ' . $opt['MFAToken'])
  1344. );
  1345. }
  1346. // @codeCoverageIgnoreEnd
  1347. // Authenticate to S3
  1348. return $this->authenticate($bucket, $opt);
  1349. }
  1350. /**
  1351. * Deletes one or more specified Amazon S3 objects from the specified bucket.
  1352. *
  1353. * Since `delete_object()` is designed for deleting a single object, this method is intended to be used
  1354. * when there are two or more objects to delete.
  1355. *
  1356. * @param string $bucket (Required) The name of the bucket to use.
  1357. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1358. * <li><code>objects</code> - <code>array</code> - Required - The object references to delete from the bucket. <ul>
  1359. * <li><code>key</code> - <code>string</code> - Required - The name of the object (e.g., the "key") to delete. This should include the entire file path including all "subdirectories".</li>
  1360. * <li><code>version_id</code> - <code>string</code> - Optional - If the object is versioned, include the version ID to delete.</li>
  1361. * </ul></li>
  1362. * <li><code>quiet</code> - <code>boolean</code> - Optional - Whether or not Amazon S3 should use "Quiet" mode for this operation. A value of <code>true</code> will enable Quiet mode. A value of <code>false</code> will use Verbose mode. The default value is <code>false</code>.</li>
  1363. * <li><code>MFASerial</code> - <code>string</code> - Optional - The serial number on the back of the Gemalto device. <code>MFASerial</code> and <code>MFAToken</code> must both be set for MFA to work.</li>
  1364. * <li><code>MFAToken</code> - <code>string</code> - Optional - The current token displayed on the Gemalto device. <code>MFASerial</code> and <code>MFAToken</code> must both be set for MFA to work.</li>
  1365. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1366. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1367. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1368. * @link http://aws.amazon.com/mfa/ Multi-Factor Authentication
  1369. */
  1370. public function delete_objects($bucket, $opt = null)
  1371. {
  1372. // Add this to our request
  1373. if (!$opt) $opt = array();
  1374. $opt['verb'] = 'POST';
  1375. $opt['sub_resource'] = 'delete';
  1376. $opt['body'] = '';
  1377. // Bail out
  1378. if (!isset($opt['objects']) || !is_array($opt['objects']))
  1379. {
  1380. throw new S3_Exception('The ' . __FUNCTION__ . ' method requires the "objects" option to be set as an array.');
  1381. }
  1382. $xml = new SimpleXMLElement($this->multi_object_delete_xml);
  1383. // Add the objects
  1384. foreach ($opt['objects'] as $object)
  1385. {
  1386. $xobject = $xml->addChild('Object');
  1387. $node = $xobject->addChild('Key');
  1388. $node[0] = $object['key'];
  1389. if (isset($object['version_id']))
  1390. {
  1391. $xobject->addChild('VersionId', $object['version_id']);
  1392. }
  1393. }
  1394. // Quiet mode?
  1395. if (isset($opt['quiet']))
  1396. {
  1397. $quiet = 'false';
  1398. if (is_bool($opt['quiet'])) // Boolean
  1399. {
  1400. $quiet = $opt['quiet'] ? 'true' : 'false';
  1401. }
  1402. elseif (is_string($opt['quiet'])) // String
  1403. {
  1404. $quiet = ($opt['quiet'] === 'true') ? 'true' : 'false';
  1405. }
  1406. $xml->addChild('Quiet', $quiet);
  1407. }
  1408. // Enable MFA delete?
  1409. // @codeCoverageIgnoreStart
  1410. if (isset($opt['MFASerial']) && isset($opt['MFAToken']))
  1411. {
  1412. $opt['headers'] = array(
  1413. 'x-amz-mfa' => ($opt['MFASerial'] . ' ' . $opt['MFAToken'])
  1414. );
  1415. }
  1416. // @codeCoverageIgnoreEnd
  1417. $opt['body'] = $xml->asXML();
  1418. // Authenticate to S3
  1419. return $this->authenticate($bucket, $opt);
  1420. }
  1421. /**
  1422. * Gets a list of all Amazon S3 objects in the specified bucket.
  1423. *
  1424. * NOTE: <strong>This method is paginated</strong>, and will not return more than <code>max-keys</code> keys. If you want to retrieve a list of all keys, you will need to make multiple calls to this function using the <code>marker</code> option to specify the pagination offset (the key of the last processed key--lexically ordered) and the <code>IsTruncated</code> response key to detect when all results have been processed. See: <a href="http://docs.amazonwebservices.com/AmazonS3/latest/API/index.html?RESTBucketGET.html">the S3 REST documentation for get_bucket</a> for more information.
  1425. *
  1426. * @param string $bucket (Required) The name of the bucket to use.
  1427. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1428. * <li><code>delimiter</code> - <code>string</code> - Optional - Keys that contain the same string between the prefix and the first occurrence of the delimiter will be rolled up into a single result element in the CommonPrefixes collection.</li>
  1429. * <li><code>marker</code> - <code>string</code> - Optional - Restricts the response to contain results that only occur alphabetically after the value of the marker.</li>
  1430. * <li><code>max-keys</code> - <code>string</code> - Optional - The maximum number of results returned by the method call. The returned list will contain no more results than the specified value, but may return fewer. The default value is 1000.</li>
  1431. * <li><code>preauth</code> - <code>integer|string</code> - Optional - Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.</li>
  1432. * <li><code>prefix</code> - <code>string</code> - Optional - Restricts the response to contain results that begin only with the specified prefix.</li>
  1433. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1434. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1435. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1436. */
  1437. public function list_objects($bucket, $opt = null)
  1438. {
  1439. if (!$opt) $opt = array();
  1440. // Add this to our request
  1441. $opt['verb'] = 'GET';
  1442. foreach (array('delimiter', 'marker', 'max-keys', 'prefix') as $param)
  1443. {
  1444. if (isset($opt[$param]))
  1445. {
  1446. $opt['query_string'][$param] = $opt[$param];
  1447. unset($opt[$param]);
  1448. }
  1449. }
  1450. // Authenticate to S3
  1451. return $this->authenticate($bucket, $opt);
  1452. }
  1453. /**
  1454. * Copies an Amazon S3 object to a new location, whether in the same Amazon S3 region, bucket, or otherwise.
  1455. *
  1456. * NOTE: Object redirect locations are not carried over when an object is copied.
  1457. *
  1458. * @param array $source (Required) The bucket and file name to copy from. The following keys must be set: <ul>
  1459. * <li><code>bucket</code> - <code>string</code> - Required - Specifies the name of the bucket containing the source object.</li>
  1460. * <li><code>filename</code> - <code>string</code> - Required - Specifies the file name of the source object to copy.</li></ul>
  1461. * @param array $dest (Required) The bucket and file name to copy to. The following keys must be set: <ul>
  1462. * <li><code>bucket</code> - <code>string</code> - Required - Specifies the name of the bucket to copy the object to.</li>
  1463. * <li><code>filename</code> - <code>string</code> - Required - Specifies the file name to copy the object to.</li></ul>
  1464. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1465. * <li><code>acl</code> - <code>string</code> - Optional - The ACL settings for the specified object. [Allowed values: <code>AmazonS3::ACL_PRIVATE</code>, <code>AmazonS3::ACL_PUBLIC</code>, <code>AmazonS3::ACL_OPEN</code>, <code>AmazonS3::ACL_AUTH_READ</code>, <code>AmazonS3::ACL_OWNER_READ</code>, <code>AmazonS3::ACL_OWNER_FULL_CONTROL</code>]. Alternatively, an array of associative arrays. Each associative array contains an <code>id</code> and a <code>permission</code> key. The default value is <code>ACL_PRIVATE</code>.</li>
  1466. * <li><code>encryption</code> - <code>string</code> - Optional - The algorithm to use for encrypting the object. [Allowed values: <code>AES256</code>]</li>
  1467. * <li><code>storage</code> - <code>string</code> - Optional - Whether to use Standard or Reduced Redundancy storage. [Allowed values: <code>AmazonS3::STORAGE_STANDARD</code>, <code>AmazonS3::STORAGE_REDUCED</code>]. The default value is <code>STORAGE_STANDARD</code>.</li>
  1468. * <li><code>versionId</code> - <code>string</code> - Optional - The version of the object to copy. Version IDs are returned in the <code>x-amz-version-id</code> header of any previous object-related request.</li>
  1469. * <li><code>ifMatch</code> - <code>string</code> - Optional - The ETag header from a previous request. Copies the object if its entity tag (ETag) matches the specified tag; otherwise, the request returns a <code>412</code> HTTP status code error (precondition failed). Used in conjunction with <code>ifUnmodifiedSince</code>.</li>
  1470. * <li><code>ifUnmodifiedSince</code> - <code>string</code> - Optional - The LastModified header from a previous request. Copies the object if it hasn't been modified since the specified time; otherwise, the request returns a <code>412</code> HTTP status code error (precondition failed). Used in conjunction with <code>ifMatch</code>.</li>
  1471. * <li><code>ifNoneMatch</code> - <code>string</code> - Optional - The ETag header from a previous request. Copies the object if its entity tag (ETag) is different than the specified ETag; otherwise, the request returns a <code>412</code> HTTP status code error (failed condition). Used in conjunction with <code>ifModifiedSince</code>.</li>
  1472. * <li><code>ifModifiedSince</code> - <code>string</code> - Optional - The LastModified header from a previous request. Copies the object if it has been modified since the specified time; otherwise, the request returns a <code>412</code> HTTP status code error (failed condition). Used in conjunction with <code>ifNoneMatch</code>.</li>
  1473. * <li><code>headers</code> - <code>array</code> - Optional - Standard HTTP headers to send along in the request. Accepts an associative array of key-value pairs.</li>
  1474. * <li><code>meta</code> - <code>array</code> - Optional - Associative array of key-value pairs. Represented by <code>x-amz-meta-:</code> Any header starting with this prefix is considered user metadata. It will be stored with the object and returned when you retrieve the object. The total size of the HTTP request, not including the body, must be less than 4 KB.</li>
  1475. * <li><code>metadataDirective</code> - <code>string</code> - Optional - Accepts either COPY or REPLACE. You will likely never need to use this, as it manages itself with no issues.</li>
  1476. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1477. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1478. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1479. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/API/RESTObjectCOPY.html Copying Amazon S3 Objects
  1480. */
  1481. public function copy_object($source, $dest, $opt = null)
  1482. {
  1483. if (!$opt) $opt = array();
  1484. $batch = array();
  1485. // Add this to our request
  1486. $opt['verb'] = 'PUT';
  1487. $opt['resource'] = $dest['filename'];
  1488. $opt['body'] = '';
  1489. // Handle copy source
  1490. if (isset($source['bucket']) && isset($source['filename']))
  1491. {
  1492. $opt['headers']['x-amz-copy-source'] = '/' . $source['bucket'] . '/' . rawurlencode($source['filename'])
  1493. . (isset($opt['versionId']) ? ('?' . 'versionId=' . rawurlencode($opt['versionId'])) : ''); // Append the versionId to copy, if available
  1494. unset($opt['versionId']);
  1495. }
  1496. // Handle metadata directive
  1497. $opt['headers']['x-amz-metadata-directive'] = 'COPY';
  1498. if ($source['bucket'] === $dest['bucket'] && $source['filename'] === $dest['filename'])
  1499. {
  1500. $opt['headers']['x-amz-metadata-directive'] = 'REPLACE';
  1501. }
  1502. if (isset($opt['metadataDirective']))
  1503. {
  1504. $opt['headers']['x-amz-metadata-directive'] = $opt['metadataDirective'];
  1505. unset($opt['metadataDirective']);
  1506. }
  1507. // Handle Access Control Lists. Can also pass canned ACLs as an HTTP header.
  1508. if (isset($opt['acl']) && is_array($opt['acl']))
  1509. {
  1510. $batch[] = $this->set_object_acl($dest['bucket'], $dest['filename'], $opt['acl'], array(
  1511. 'returnCurlHandle' => true
  1512. ));
  1513. unset($opt['acl']);
  1514. }
  1515. elseif (isset($opt['acl']))
  1516. {
  1517. $opt['headers']['x-amz-acl'] = $opt['acl'];
  1518. unset($opt['acl']);
  1519. }
  1520. // Handle storage settings. Can also be passed as an HTTP header.
  1521. if (isset($opt['storage']))
  1522. {
  1523. $opt['headers']['x-amz-storage-class'] = $opt['storage'];
  1524. unset($opt['storage']);
  1525. }
  1526. // Handle encryption settings. Can also be passed as an HTTP header.
  1527. if (isset($opt['encryption']))
  1528. {
  1529. $opt['headers']['x-amz-server-side-encryption'] = $opt['encryption'];
  1530. unset($opt['encryption']);
  1531. }
  1532. // Handle conditional-copy parameters
  1533. if (isset($opt['ifMatch']))
  1534. {
  1535. $opt['headers']['x-amz-copy-source-if-match'] = $opt['ifMatch'];
  1536. unset($opt['ifMatch']);
  1537. }
  1538. if (isset($opt['ifNoneMatch']))
  1539. {
  1540. $opt['headers']['x-amz-copy-source-if-none-match'] = $opt['ifNoneMatch'];
  1541. unset($opt['ifNoneMatch']);
  1542. }
  1543. if (isset($opt['ifUnmodifiedSince']))
  1544. {
  1545. $opt['headers']['x-amz-copy-source-if-unmodified-since'] = $opt['ifUnmodifiedSince'];
  1546. unset($opt['ifUnmodifiedSince']);
  1547. }
  1548. if (isset($opt['ifModifiedSince']))
  1549. {
  1550. $opt['headers']['x-amz-copy-source-if-modified-since'] = $opt['ifModifiedSince'];
  1551. unset($opt['ifModifiedSince']);
  1552. }
  1553. // Handle meta tags. Can also be passed as an HTTP header.
  1554. if (isset($opt['meta']))
  1555. {
  1556. foreach ($opt['meta'] as $meta_key => $meta_value)
  1557. {
  1558. // e.g., `My Meta Header` is converted to `x-amz-meta-my-meta-header`.
  1559. $opt['headers']['x-amz-meta-' . strtolower(str_replace(' ', '-', $meta_key))] = $meta_value;
  1560. }
  1561. unset($opt['meta']);
  1562. }
  1563. // Authenticate to S3
  1564. $response = $this->authenticate($dest['bucket'], $opt);
  1565. // Attempt to reset ACLs
  1566. $http = new CFRequest();
  1567. $http->send_multi_request($batch);
  1568. return $response;
  1569. }
  1570. /**
  1571. * Updates an Amazon S3 object with new headers or other metadata. To replace the content of the
  1572. * specified Amazon S3 object, call <create_object()> with the same bucket and file name parameters.
  1573. *
  1574. * @param string $bucket (Required) The name of the bucket that contains the source file.
  1575. * @param string $filename (Required) The source file name that you want to update.
  1576. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1577. * <li><code>acl</code> - <code>string</code> - Optional - The ACL settings for the specified object. [Allowed values: <code>AmazonS3::ACL_PRIVATE</code>, <code>AmazonS3::ACL_PUBLIC</code>, <code>AmazonS3::ACL_OPEN</code>, <code>AmazonS3::ACL_AUTH_READ</code>, <code>AmazonS3::ACL_OWNER_READ</code>, <code>AmazonS3::ACL_OWNER_FULL_CONTROL</code>]. The default value is <ACL_PRIVATE>.</li>
  1578. * <li><code>headers</code> - <code>array</code> - Optional - Standard HTTP headers to send along in the request. Accepts an associative array of key-value pairs.</li>
  1579. * <li><code>meta</code> - <code>array</code> - Optional - An associative array of key-value pairs. Any header with the <code>x-amz-meta-</code> prefix is considered user metadata and is stored with the Amazon S3 object. It will be stored with the object and returned when you retrieve the object. The total size of the HTTP request, not including the body, must be less than 4 KB.</li>
  1580. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1581. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1582. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1583. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/API/RESTObjectCOPY.html Copying Amazon S3 Objects
  1584. */
  1585. public function update_object($bucket, $filename, $opt = null)
  1586. {
  1587. if (!$opt) $opt = array();
  1588. $opt['metadataDirective'] = 'REPLACE';
  1589. // Retrieve the original metadata
  1590. if ($metadata = $this->get_object_metadata($bucket, $filename))
  1591. {
  1592. if (isset($metadata['ACL']))
  1593. {
  1594. $opt['acl'] = isset($opt['acl']) ? $opt['acl'] : $metadata['ACL'];
  1595. }
  1596. if (isset($metadata['StorageClass']))
  1597. {
  1598. $opt['headers']['x-amz-storage-class'] = $metadata['StorageClass'];
  1599. }
  1600. if (isset($metadata['ContentType']))
  1601. {
  1602. $opt['headers']['Content-Type'] = $metadata['ContentType'];
  1603. }
  1604. }
  1605. // Remove a header
  1606. unset($metadata['Headers']['date']);
  1607. // Merge headers
  1608. $opt['headers'] = array_merge($opt['headers'], $metadata['Headers']);
  1609. // Authenticate to S3
  1610. return $this->copy_object(
  1611. array('bucket' => $bucket, 'filename' => $filename),
  1612. array('bucket' => $bucket, 'filename' => $filename),
  1613. $opt
  1614. );
  1615. }
  1616. /*%******************************************************************************************%*/
  1617. // ACCESS CONTROL LISTS
  1618. /**
  1619. * Gets the access control list (ACL) settings for the specified Amazon S3 object.
  1620. *
  1621. * @param string $bucket (Required) The name of the bucket to use.
  1622. * @param string $filename (Required) The file name for the object.
  1623. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1624. * <li><code>versionId</code> - <code>string</code> - Optional - The version of the object to retrieve. Version IDs are returned in the <code>x-amz-version-id</code> header of any previous object-related request.</li>
  1625. * <li><code>preauth</code> - <code>integer|string</code> - Optional - Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.</li>
  1626. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1627. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1628. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1629. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAccessPolicy.html REST Access Control Policy
  1630. */
  1631. public function get_object_acl($bucket, $filename, $opt = null)
  1632. {
  1633. // Add this to our request
  1634. if (!$opt) $opt = array();
  1635. $opt['verb'] = 'GET';
  1636. $opt['resource'] = $filename;
  1637. $opt['sub_resource'] = 'acl';
  1638. // Authenticate to S3
  1639. return $this->authenticate($bucket, $opt);
  1640. }
  1641. /**
  1642. * Sets the access control list (ACL) settings for the specified Amazon S3 object.
  1643. *
  1644. * @param string $bucket (Required) The name of the bucket to use.
  1645. * @param string $filename (Required) The file name for the object.
  1646. * @param string $acl (Optional) The ACL settings for the specified object. Accepts any of the following constants: [Allowed values: <code>AmazonS3::ACL_PRIVATE</code>, <code>AmazonS3::ACL_PUBLIC</code>, <code>AmazonS3::ACL_OPEN</code>, <code>AmazonS3::ACL_AUTH_READ</code>, <code>AmazonS3::ACL_OWNER_READ</code>, <code>AmazonS3::ACL_OWNER_FULL_CONTROL</code>]. Alternatively, an array of associative arrays. Each associative array contains an <code>id</code> and a <code>permission</code> key. The default value is <code>ACL_PRIVATE</code>.
  1647. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1648. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1649. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1650. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1651. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAccessPolicy.html REST Access Control Policy
  1652. */
  1653. public function set_object_acl($bucket, $filename, $acl = self::ACL_PRIVATE, $opt = null)
  1654. {
  1655. // Add this to our request
  1656. if (!$opt) $opt = array();
  1657. $opt['verb'] = 'PUT';
  1658. $opt['resource'] = $filename;
  1659. $opt['sub_resource'] = 'acl';
  1660. // Retrieve the original metadata
  1661. $metadata = $this->get_object_metadata($bucket, $filename);
  1662. if ($metadata && $metadata['ContentType'])
  1663. {
  1664. $opt['headers']['Content-Type'] = $metadata['ContentType'];
  1665. }
  1666. if ($metadata && $metadata['StorageClass'])
  1667. {
  1668. $opt['headers']['x-amz-storage-class'] = $metadata['StorageClass'];
  1669. }
  1670. // Make sure these are defined.
  1671. // @codeCoverageIgnoreStart
  1672. if (!$this->credentials->canonical_id || !$this->credentials->canonical_name)
  1673. {
  1674. // Fetch the data live.
  1675. $canonical = $this->get_canonical_user_id();
  1676. $this->credentials->canonical_id = $canonical['id'];
  1677. $this->credentials->canonical_name = $canonical['display_name'];
  1678. }
  1679. // @codeCoverageIgnoreEnd
  1680. if (is_array($acl))
  1681. {
  1682. $opt['headers'] = array_merge($opt['headers'], $this->generate_access_policy_headers($acl));
  1683. }
  1684. else
  1685. {
  1686. $opt['body'] = '';
  1687. $opt['headers']['x-amz-acl'] = $acl;
  1688. }
  1689. // Authenticate to S3
  1690. return $this->authenticate($bucket, $opt);
  1691. }
  1692. /**
  1693. * Generates the XML to be used for the Access Control Policy.
  1694. *
  1695. * @param string $canonical_id (Required) The canonical ID for the bucket owner. This is provided as the `id` return value from <get_canonical_user_id()>.
  1696. * @param string $canonical_name (Required) The canonical display name for the bucket owner. This is provided as the `display_name` value from <get_canonical_user_id()>.
  1697. * @param array $users (Optional) An array of associative arrays. Each associative array contains an `id` value and a `permission` value.
  1698. * @return string Access Control Policy XML.
  1699. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/ACLOverview.html Access Control Lists
  1700. */
  1701. public function generate_access_policy($canonical_id, $canonical_name, $users)
  1702. {
  1703. $xml = simplexml_load_string($this->base_acp_xml);
  1704. $owner = $xml->addChild('Owner');
  1705. $owner->addChild('ID', $canonical_id);
  1706. $owner->addChild('DisplayName', $canonical_name);
  1707. $acl = $xml->addChild('AccessControlList');
  1708. foreach ($users as $user)
  1709. {
  1710. $grant = $acl->addChild('Grant');
  1711. $grantee = $grant->addChild('Grantee');
  1712. switch ($user['id'])
  1713. {
  1714. // Authorized Users
  1715. case self::USERS_AUTH:
  1716. $grantee->addAttribute('xsi:type', 'Group', 'http://www.w3.org/2001/XMLSchema-instance');
  1717. $grantee->addChild('URI', self::USERS_AUTH);
  1718. break;
  1719. // All Users
  1720. case self::USERS_ALL:
  1721. $grantee->addAttribute('xsi:type', 'Group', 'http://www.w3.org/2001/XMLSchema-instance');
  1722. $grantee->addChild('URI', self::USERS_ALL);
  1723. break;
  1724. // The Logging User
  1725. case self::USERS_LOGGING:
  1726. $grantee->addAttribute('xsi:type', 'Group', 'http://www.w3.org/2001/XMLSchema-instance');
  1727. $grantee->addChild('URI', self::USERS_LOGGING);
  1728. break;
  1729. // Email Address or Canonical Id
  1730. default:
  1731. if (strpos($user['id'], '@'))
  1732. {
  1733. $grantee->addAttribute('xsi:type', 'AmazonCustomerByEmail', 'http://www.w3.org/2001/XMLSchema-instance');
  1734. $grantee->addChild('EmailAddress', $user['id']);
  1735. }
  1736. else
  1737. {
  1738. // Assume Canonical Id
  1739. $grantee->addAttribute('xsi:type', 'CanonicalUser', 'http://www.w3.org/2001/XMLSchema-instance');
  1740. $grantee->addChild('ID', $user['id']);
  1741. }
  1742. break;
  1743. }
  1744. $grant->addChild('Permission', $user['permission']);
  1745. }
  1746. return $xml->asXML();
  1747. }
  1748. /**
  1749. * Generates the HTTP headers to be used for the Access Control Policy Grants.
  1750. *
  1751. * @param array $users (Optional) An array of associative arrays. Each associative array contains an `id` value and a `permission` value.
  1752. * @return array HTTP headers to be applied to the request.
  1753. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/ACLOverview.html Access Control Lists
  1754. */
  1755. public function generate_access_policy_headers($users)
  1756. {
  1757. $headers = array();
  1758. foreach ($users as $user)
  1759. {
  1760. // Determine permission. If doesn't exist, create it.
  1761. $permission = 'x-amz-grant-' . str_replace('_', '-', strtolower($user['permission']));
  1762. if (!isset($headers[$permission]))
  1763. {
  1764. $headers[$permission] = array();
  1765. }
  1766. // Handle the IDs
  1767. switch ($user['id'])
  1768. {
  1769. case self::USERS_AUTH: // Authorized Users
  1770. case self::USERS_ALL: // All Users
  1771. case self::USERS_LOGGING: // The Logging User
  1772. $headers[$permission][] = 'uri="' . $user['id'] . '"';
  1773. break;
  1774. // Email Address or Canonical Id
  1775. default:
  1776. if (strpos($user['id'], '@'))
  1777. {
  1778. // Treat as email address
  1779. $headers[$permission][] = 'emailAddress="' . $user['id'] . '"';
  1780. }
  1781. else
  1782. {
  1783. // Assume Canonical Id
  1784. $headers[$permission][] = 'id="' . $user['id'] . '"';
  1785. }
  1786. break;
  1787. }
  1788. }
  1789. foreach ($headers as &$permission)
  1790. {
  1791. $permission = implode(', ', $permission);
  1792. }
  1793. return $headers;
  1794. }
  1795. /*%******************************************************************************************%*/
  1796. // LOGGING METHODS
  1797. /**
  1798. * Gets the access logs associated with the specified Amazon S3 bucket.
  1799. *
  1800. * @param string $bucket (Required) The name of the bucket to use. Pass a `null` value when using the <set_vhost()> method.
  1801. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1802. * <li><code>preauth</code> - <code>integer|string</code> - Optional - Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.</li>
  1803. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1804. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1805. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1806. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/ServerLogs.html Server Access Logging
  1807. */
  1808. public function get_logs($bucket, $opt = null)
  1809. {
  1810. // Add this to our request
  1811. if (!$opt) $opt = array();
  1812. $opt['verb'] = 'GET';
  1813. $opt['sub_resource'] = 'logging';
  1814. // Authenticate to S3
  1815. return $this->authenticate($bucket, $opt);
  1816. }
  1817. /**
  1818. * Enables access logging for the specified Amazon S3 bucket.
  1819. *
  1820. * @param string $bucket (Required) The name of the bucket to enable logging for. Pass a `null` value when using the <set_vhost()> method.
  1821. * @param string $target_bucket (Required) The name of the bucket to store the logs in.
  1822. * @param string $target_prefix (Required) The prefix to give to the log file names.
  1823. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1824. * <li><code>users</code> - <code>array</code> - Optional - An array of associative arrays specifying any user to give access to. Each associative array contains an <code>id</code> and <code>permission</code> value.</li>
  1825. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1826. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1827. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1828. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/LoggingAPI.html Server Access Logging Configuration API
  1829. */
  1830. public function enable_logging($bucket, $target_bucket, $target_prefix, $opt = null)
  1831. {
  1832. // Add this to our request
  1833. if (!$opt) $opt = array();
  1834. $opt['verb'] = 'PUT';
  1835. $opt['sub_resource'] = 'logging';
  1836. $opt['headers'] = array(
  1837. 'Content-Type' => 'application/xml'
  1838. );
  1839. $xml = simplexml_load_string($this->base_logging_xml);
  1840. $LoggingEnabled = $xml->addChild('LoggingEnabled');
  1841. $LoggingEnabled->addChild('TargetBucket', $target_bucket);
  1842. $LoggingEnabled->addChild('TargetPrefix', $target_prefix);
  1843. $TargetGrants = $LoggingEnabled->addChild('TargetGrants');
  1844. if (isset($opt['users']) && is_array($opt['users']))
  1845. {
  1846. foreach ($opt['users'] as $user)
  1847. {
  1848. $grant = $TargetGrants->addChild('Grant');
  1849. $grantee = $grant->addChild('Grantee');
  1850. switch ($user['id'])
  1851. {
  1852. // Authorized Users
  1853. case self::USERS_AUTH:
  1854. $grantee->addAttribute('xsi:type', 'Group', 'http://www.w3.org/2001/XMLSchema-instance');
  1855. $grantee->addChild('URI', self::USERS_AUTH);
  1856. break;
  1857. // All Users
  1858. case self::USERS_ALL:
  1859. $grantee->addAttribute('xsi:type', 'Group', 'http://www.w3.org/2001/XMLSchema-instance');
  1860. $grantee->addChild('URI', self::USERS_ALL);
  1861. break;
  1862. // The Logging User
  1863. case self::USERS_LOGGING:
  1864. $grantee->addAttribute('xsi:type', 'Group', 'http://www.w3.org/2001/XMLSchema-instance');
  1865. $grantee->addChild('URI', self::USERS_LOGGING);
  1866. break;
  1867. // Email Address or Canonical Id
  1868. default:
  1869. if (strpos($user['id'], '@'))
  1870. {
  1871. $grantee->addAttribute('xsi:type', 'AmazonCustomerByEmail', 'http://www.w3.org/2001/XMLSchema-instance');
  1872. $grantee->addChild('EmailAddress', $user['id']);
  1873. }
  1874. else
  1875. {
  1876. // Assume Canonical Id
  1877. $grantee->addAttribute('xsi:type', 'CanonicalUser', 'http://www.w3.org/2001/XMLSchema-instance');
  1878. $grantee->addChild('ID', $user['id']);
  1879. }
  1880. break;
  1881. }
  1882. $grant->addChild('Permission', $user['permission']);
  1883. }
  1884. }
  1885. $opt['body'] = $xml->asXML();
  1886. // Authenticate to S3
  1887. return $this->authenticate($bucket, $opt);
  1888. }
  1889. /**
  1890. * Disables access logging for the specified Amazon S3 bucket.
  1891. *
  1892. * @param string $bucket (Required) The name of the bucket to use. Pass `null` if using <set_vhost()>.
  1893. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  1894. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  1895. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  1896. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  1897. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/LoggingAPI.html Server Access Logging Configuration API
  1898. */
  1899. public function disable_logging($bucket, $opt = null)
  1900. {
  1901. // Add this to our request
  1902. if (!$opt) $opt = array();
  1903. $opt['verb'] = 'PUT';
  1904. $opt['sub_resource'] = 'logging';
  1905. $opt['headers'] = array(
  1906. 'Content-Type' => 'application/xml'
  1907. );
  1908. $opt['body'] = $this->base_logging_xml;
  1909. // Authenticate to S3
  1910. return $this->authenticate($bucket, $opt);
  1911. }
  1912. /*%******************************************************************************************%*/
  1913. // CONVENIENCE METHODS
  1914. /**
  1915. * Gets whether or not the specified Amazon S3 bucket exists in Amazon S3. This includes buckets
  1916. * that do not belong to the caller.
  1917. *
  1918. * @param string $bucket (Required) The name of the bucket to use.
  1919. * @return boolean A value of <code>true</code> if the bucket exists, or a value of <code>false</code> if it does not.
  1920. */
  1921. public function if_bucket_exists($bucket)
  1922. {
  1923. if ($this->use_batch_flow)
  1924. {
  1925. throw new S3_Exception(__FUNCTION__ . '() cannot be batch requested');
  1926. }
  1927. $header = $this->get_bucket_headers($bucket);
  1928. return (integer) $header->status !== 404;
  1929. }
  1930. /**
  1931. * Gets whether or not the specified Amazon S3 object exists in the specified bucket.
  1932. *
  1933. * @param string $bucket (Required) The name of the bucket to use.
  1934. * @param string $filename (Required) The file name for the object.
  1935. * @return boolean A value of <code>true</code> if the object exists, or a value of <code>false</code> if it does not.
  1936. */
  1937. public function if_object_exists($bucket, $filename)
  1938. {
  1939. if ($this->use_batch_flow)
  1940. {
  1941. throw new S3_Exception(__FUNCTION__ . '() cannot be batch requested');
  1942. }
  1943. $header = $this->get_object_headers($bucket, $filename);
  1944. if ($header->isOK()) { return true; }
  1945. elseif ($header->status === 404) { return false; }
  1946. // @codeCoverageIgnoreStart
  1947. return null;
  1948. // @codeCoverageIgnoreEnd
  1949. }
  1950. /**
  1951. * Gets whether or not the specified Amazon S3 bucket has a bucket policy associated with it.
  1952. *
  1953. * @param string $bucket (Required) The name of the bucket to use.
  1954. * @return boolean A value of <code>true</code> if a bucket policy exists, or a value of <code>false</code> if one does not.
  1955. */
  1956. public function if_bucket_policy_exists($bucket)
  1957. {
  1958. if ($this->use_batch_flow)
  1959. {
  1960. // @codeCoverageIgnoreStart
  1961. throw new S3_Exception(__FUNCTION__ . '() cannot be batch requested');
  1962. // @codeCoverageIgnoreEnd
  1963. }
  1964. $response = $this->get_bucket_policy($bucket);
  1965. if ($response->isOK()) { return true; }
  1966. elseif ($response->status === 404) { return false; }
  1967. // @codeCoverageIgnoreStart
  1968. return null;
  1969. // @codeCoverageIgnoreEnd
  1970. }
  1971. /**
  1972. * Gets the number of Amazon S3 objects in the specified bucket.
  1973. *
  1974. * @param string $bucket (Required) The name of the bucket to use.
  1975. * @return integer The number of Amazon S3 objects in the bucket.
  1976. */
  1977. public function get_bucket_object_count($bucket)
  1978. {
  1979. if ($this->use_batch_flow)
  1980. {
  1981. // @codeCoverageIgnoreStart
  1982. throw new S3_Exception(__FUNCTION__ . '() cannot be batch requested');
  1983. // @codeCoverageIgnoreEnd
  1984. }
  1985. return count($this->get_object_list($bucket));
  1986. }
  1987. /**
  1988. * Gets the cumulative file size of the contents of the Amazon S3 bucket.
  1989. *
  1990. * @param string $bucket (Required) The name of the bucket to use.
  1991. * @param boolean $friendly_format (Optional) A value of <code>true</code> will format the return value to 2 decimal points using the largest possible unit (i.e., 3.42 GB). A value of <code>false</code> will format the return value as the raw number of bytes.
  1992. * @return integer|string The number of bytes as an integer, or the friendly format as a string.
  1993. */
  1994. public function get_bucket_filesize($bucket, $friendly_format = false)
  1995. {
  1996. if ($this->use_batch_flow)
  1997. {
  1998. throw new S3_Exception(__FUNCTION__ . '() cannot be batch requested');
  1999. }
  2000. $filesize = 0;
  2001. $list = $this->list_objects($bucket);
  2002. foreach ($list->body->Contents as $filename)
  2003. {
  2004. $filesize += (integer) $filename->Size;
  2005. }
  2006. while ((string) $list->body->IsTruncated === 'true')
  2007. {
  2008. $body = (array) $list->body;
  2009. $list = $this->list_objects($bucket, array(
  2010. 'marker' => (string) end($body['Contents'])->Key
  2011. ));
  2012. foreach ($list->body->Contents as $object)
  2013. {
  2014. $filesize += (integer) $object->Size;
  2015. }
  2016. }
  2017. if ($friendly_format)
  2018. {
  2019. $filesize = $this->util->size_readable($filesize);
  2020. }
  2021. return $filesize;
  2022. }
  2023. /**
  2024. * Gets the file size of the specified Amazon S3 object.
  2025. *
  2026. * @param string $bucket (Required) The name of the bucket to use.
  2027. * @param string $filename (Required) The file name for the object.
  2028. * @param boolean $friendly_format (Optional) A value of <code>true</code> will format the return value to 2 decimal points using the largest possible unit (i.e., 3.42 GB). A value of <code>false</code> will format the return value as the raw number of bytes.
  2029. * @return integer|string The number of bytes as an integer, or the friendly format as a string.
  2030. */
  2031. public function get_object_filesize($bucket, $filename, $friendly_format = false)
  2032. {
  2033. if ($this->use_batch_flow)
  2034. {
  2035. throw new S3_Exception(__FUNCTION__ . '() cannot be batch requested');
  2036. }
  2037. $object = $this->get_object_headers($bucket, $filename);
  2038. if ($object->isOK()) {
  2039. $filesize = (integer) $object->header['content-length'];
  2040. } else {
  2041. $filesize = 0;
  2042. }
  2043. if ($friendly_format)
  2044. {
  2045. $filesize = $this->util->size_readable($filesize);
  2046. }
  2047. return $filesize;
  2048. }
  2049. /**
  2050. * Changes the content type for an existing Amazon S3 object.
  2051. *
  2052. * @param string $bucket (Required) The name of the bucket to use.
  2053. * @param string $filename (Required) The file name for the object.
  2054. * @param string $contentType (Required) The content-type to apply to the object.
  2055. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2056. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2057. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2058. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2059. */
  2060. public function change_content_type($bucket, $filename, $contentType, $opt = null)
  2061. {
  2062. if (!$opt) $opt = array();
  2063. // Retrieve the original metadata
  2064. $metadata = $this->get_object_metadata($bucket, $filename);
  2065. if ($metadata && isset($metadata['ACL']))
  2066. {
  2067. $opt['acl'] = $metadata['ACL'];
  2068. }
  2069. if ($metadata && isset($metadata['StorageClass']))
  2070. {
  2071. $opt['headers']['x-amz-storage-class'] = $metadata['StorageClass'];
  2072. }
  2073. // Merge optional parameters
  2074. $opt = array_merge_recursive(array(
  2075. 'headers' => array(
  2076. 'Content-Type' => $contentType
  2077. ),
  2078. 'metadataDirective' => 'REPLACE'
  2079. ), $opt);
  2080. return $this->copy_object(
  2081. array('bucket' => $bucket, 'filename' => $filename),
  2082. array('bucket' => $bucket, 'filename' => $filename),
  2083. $opt
  2084. );
  2085. }
  2086. /**
  2087. * Changes the storage redundancy for an existing object.
  2088. *
  2089. * @param string $bucket (Required) The name of the bucket to use.
  2090. * @param string $filename (Required) The file name for the object.
  2091. * @param string $storage (Required) The storage setting to apply to the object. [Allowed values: <code>AmazonS3::STORAGE_STANDARD</code>, <code>AmazonS3::STORAGE_REDUCED</code>]
  2092. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2093. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2094. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2095. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2096. */
  2097. public function change_storage_redundancy($bucket, $filename, $storage, $opt = null)
  2098. {
  2099. if (!$opt) $opt = array();
  2100. // Retrieve the original metadata
  2101. $metadata = $this->get_object_metadata($bucket, $filename);
  2102. if ($metadata && isset($metadata['ACL']))
  2103. {
  2104. $opt['acl'] = $metadata['ACL'];
  2105. }
  2106. if ($metadata && isset($metadata['StorageClass']))
  2107. {
  2108. $opt['headers']['x-amz-storage-class'] = $metadata['StorageClass'];
  2109. }
  2110. // Merge optional parameters
  2111. $opt = array_merge(array(
  2112. 'storage' => $storage,
  2113. 'metadataDirective' => 'COPY',
  2114. ), $opt);
  2115. return $this->copy_object(
  2116. array('bucket' => $bucket, 'filename' => $filename),
  2117. array('bucket' => $bucket, 'filename' => $filename),
  2118. $opt
  2119. );
  2120. }
  2121. /**
  2122. * Gets a simplified list of bucket names on an Amazon S3 account.
  2123. *
  2124. * @param string $pcre (Optional) A Perl-Compatible Regular Expression (PCRE) to filter the bucket names against.
  2125. * @return array The list of matching bucket names. If there are no results, the method will return an empty array.
  2126. * @link http://php.net/pcre Regular Expressions (Perl-Compatible)
  2127. */
  2128. public function get_bucket_list($pcre = null)
  2129. {
  2130. if ($this->use_batch_flow)
  2131. {
  2132. throw new S3_Exception(__FUNCTION__ . '() cannot be batch requested');
  2133. }
  2134. // Get a list of buckets.
  2135. $list = $this->list_buckets();
  2136. if ($list = $list->body->query('descendant-or-self::Name'))
  2137. {
  2138. $list = $list->map_string($pcre);
  2139. return $list;
  2140. }
  2141. // @codeCoverageIgnoreStart
  2142. return array();
  2143. // @codeCoverageIgnoreEnd
  2144. }
  2145. /**
  2146. * Gets a simplified list of Amazon S3 object file names contained in a bucket.
  2147. *
  2148. * @param string $bucket (Required) The name of the bucket to use.
  2149. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2150. * <li><code>delimiter</code> - <code>string</code> - Optional - Keys that contain the same string between the prefix and the first occurrence of the delimiter will be rolled up into a single result element in the CommonPrefixes collection.</li>
  2151. * <li><code>marker</code> - <code>string</code> - Optional - Restricts the response to contain results that only occur alphabetically after the value of the marker.</li>
  2152. * <li><code>max-keys</code> - <code>integer</code> - Optional - The maximum number of results returned by the method call. The returned list will contain no more results than the specified value, but may return less. A value of zero is treated as if you did not specify max-keys.</li>
  2153. * <li><code>pcre</code> - <code>string</code> - Optional - A Perl-Compatible Regular Expression (PCRE) to filter the names against. This is applied only AFTER any native Amazon S3 filtering from specified <code>prefix</code>, <code>marker</code>, <code>max-keys</code>, or <code>delimiter</code> values are applied.</li>
  2154. * <li><code>prefix</code> - <code>string</code> - Optional - Restricts the response to contain results that begin only with the specified prefix.</li>
  2155. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2156. * @return array The list of matching object names. If there are no results, the method will return an empty array.
  2157. * @link http://php.net/pcre Regular Expressions (Perl-Compatible)
  2158. */
  2159. public function get_object_list($bucket, $opt = null)
  2160. {
  2161. if ($this->use_batch_flow)
  2162. {
  2163. throw new S3_Exception(__FUNCTION__ . '() cannot be batch requested');
  2164. }
  2165. if (!$opt) $opt = array();
  2166. unset($opt['returnCurlHandle']); // This would cause problems
  2167. // Set some default values
  2168. $pcre = isset($opt['pcre']) ? $opt['pcre'] : null;
  2169. $max_keys = (isset($opt['max-keys']) && is_int($opt['max-keys'])) ? $opt['max-keys'] : null;
  2170. $objects = array();
  2171. if (!$max_keys)
  2172. {
  2173. // No max-keys specified. Get everything.
  2174. do
  2175. {
  2176. $list = $this->list_objects($bucket, $opt);
  2177. if ($keys = $list->body->query('descendant-or-self::Key')->map_string($pcre))
  2178. {
  2179. $objects = array_merge($objects, $keys);
  2180. }
  2181. $body = (array) $list->body;
  2182. $opt = array_merge($opt, array(
  2183. 'marker' => (isset($body['Contents']) && is_array($body['Contents'])) ?
  2184. ((string) end($body['Contents'])->Key) :
  2185. ((string) $list->body->Contents->Key)
  2186. ));
  2187. }
  2188. while ((string) $list->body->IsTruncated === 'true');
  2189. }
  2190. else
  2191. {
  2192. // Max-keys specified. Approximate number of loops and make the requests.
  2193. $max_keys = $opt['max-keys'];
  2194. $loops = ceil($max_keys / 1000);
  2195. do
  2196. {
  2197. $list = $this->list_objects($bucket, $opt);
  2198. $keys = $list->body->query('descendant-or-self::Key')->map_string($pcre);
  2199. if ($count = count($keys))
  2200. {
  2201. $objects = array_merge($objects, $keys);
  2202. if ($count < 1000)
  2203. {
  2204. break;
  2205. }
  2206. }
  2207. if ($max_keys > 1000)
  2208. {
  2209. $max_keys -= 1000;
  2210. }
  2211. $body = (array) $list->body;
  2212. $opt = array_merge($opt, array(
  2213. 'max-keys' => $max_keys,
  2214. 'marker' => (isset($body['Contents']) && is_array($body['Contents'])) ?
  2215. ((string) end($body['Contents'])->Key) :
  2216. ((string) $list->body->Contents->Key)
  2217. ));
  2218. }
  2219. while (--$loops);
  2220. }
  2221. return $objects;
  2222. }
  2223. /**
  2224. * Deletes all Amazon S3 objects inside the specified bucket.
  2225. *
  2226. * @param string $bucket (Required) The name of the bucket to use.
  2227. * @param string $pcre (Optional) A Perl-Compatible Regular Expression (PCRE) to filter the names against. The default value is <PCRE_ALL>.
  2228. * @return boolean A value of <code>true</code> means that all objects were successfully deleted. A value of <code>false</code> means that at least one object failed to delete.
  2229. * @link http://php.net/pcre Regular Expressions (Perl-Compatible)
  2230. */
  2231. public function delete_all_objects($bucket, $pcre = self::PCRE_ALL)
  2232. {
  2233. // Collect all matches
  2234. $list = $this->get_object_list($bucket, array('pcre' => $pcre));
  2235. // As long as we have at least one match...
  2236. if (count($list) > 0)
  2237. {
  2238. $objects = array();
  2239. foreach ($list as $object)
  2240. {
  2241. $objects[] = array('key' => $object);
  2242. }
  2243. $batch = new CFBatchRequest();
  2244. $batch->use_credentials($this->credentials);
  2245. foreach (array_chunk($objects, 1000) as $object_set)
  2246. {
  2247. $this->batch($batch)->delete_objects($bucket, array(
  2248. 'objects' => $object_set
  2249. ));
  2250. }
  2251. $responses = $this->batch($batch)->send();
  2252. $is_ok = true;
  2253. foreach ($responses as $response)
  2254. {
  2255. if (!$response->isOK() || isset($response->body->Error))
  2256. {
  2257. $is_ok = false;
  2258. }
  2259. }
  2260. return $is_ok;
  2261. }
  2262. // If there are no matches, return true
  2263. return true;
  2264. }
  2265. /**
  2266. * Deletes all of the versions of all Amazon S3 objects inside the specified bucket.
  2267. *
  2268. * @param string $bucket (Required) The name of the bucket to use.
  2269. * @param string $pcre (Optional) A Perl-Compatible Regular Expression (PCRE) to filter the names against. The default value is <PCRE_ALL>.
  2270. * @return boolean A value of <code>true</code> means that all object versions were successfully deleted. A value of <code>false</code> means that at least one object/version failed to delete.
  2271. * @link http://php.net/pcre Regular Expressions (Perl-Compatible)
  2272. */
  2273. public function delete_all_object_versions($bucket, $pcre = null)
  2274. {
  2275. // Instantiate
  2276. $versions = $this->list_bucket_object_versions($bucket);
  2277. // Gather all nodes together into a single array
  2278. if ($versions->body->DeleteMarker() && $versions->body->Version())
  2279. {
  2280. $markers = array_merge($versions->body->DeleteMarker()->getArrayCopy(), $versions->body->Version()->getArrayCopy());
  2281. }
  2282. elseif ($versions->body->DeleteMarker())
  2283. {
  2284. $markers = $versions->body->DeleteMarker()->getArrayCopy();
  2285. }
  2286. elseif ($versions->body->Version())
  2287. {
  2288. $markers = $versions->body->Version()->getArrayCopy();
  2289. }
  2290. else
  2291. {
  2292. $markers = array();
  2293. }
  2294. while ((string) $versions->body->IsTruncated === 'true')
  2295. {
  2296. $versions = $this->list_bucket_object_versions($bucket, array(
  2297. 'key-marker' => (string) $versions->body->NextKeyMarker
  2298. ));
  2299. // Gather all nodes together into a single array
  2300. if ($versions->body->DeleteMarker() && $versions->body->Version())
  2301. {
  2302. $markers = array_merge($markers, $versions->body->DeleteMarker()->getArrayCopy(), $versions->body->Version()->getArrayCopy());
  2303. }
  2304. elseif ($versions->body->DeleteMarker())
  2305. {
  2306. $markers = array_merge($markers, $versions->body->DeleteMarker()->getArrayCopy());
  2307. }
  2308. elseif ($versions->body->Version())
  2309. {
  2310. $markers = array_merge($markers, $versions->body->Version()->getArrayCopy());
  2311. }
  2312. }
  2313. $objects = array();
  2314. // Loop through markers
  2315. foreach ($markers as $marker)
  2316. {
  2317. if ($pcre)
  2318. {
  2319. if (preg_match($pcre, (string) $marker->Key))
  2320. {
  2321. $xx = array('key' => (string) $marker->Key);
  2322. if ((string) $marker->VersionId !== 'null')
  2323. {
  2324. $xx['version_id'] = (string) $marker->VersionId;
  2325. }
  2326. $objects[] = $xx;
  2327. unset($xx);
  2328. }
  2329. }
  2330. else
  2331. {
  2332. $xx = array('key' => (string) $marker->Key);
  2333. if ((string) $marker->VersionId !== 'null')
  2334. {
  2335. $xx['version_id'] = (string) $marker->VersionId;
  2336. }
  2337. $objects[] = $xx;
  2338. unset($xx);
  2339. }
  2340. }
  2341. $batch = new CFBatchRequest();
  2342. $batch->use_credentials($this->credentials);
  2343. foreach (array_chunk($objects, 1000) as $object_set)
  2344. {
  2345. $this->batch($batch)->delete_objects($bucket, array(
  2346. 'objects' => $object_set
  2347. ));
  2348. }
  2349. $responses = $this->batch($batch)->send();
  2350. $is_ok = true;
  2351. foreach ($responses as $response)
  2352. {
  2353. if (!$response->isOK() || isset($response->body->Error))
  2354. {
  2355. $is_ok = false;
  2356. }
  2357. }
  2358. return $is_ok;
  2359. }
  2360. /**
  2361. * Gets the collective metadata for the given Amazon S3 object.
  2362. *
  2363. * The MD5 value for an object can be retrieved from the ETag HTTP header for any object that was uploaded
  2364. * with a normal PUT/POST. This value is incorrect for multipart uploads.
  2365. *
  2366. * @param string $bucket (Required) The name of the bucket to use.
  2367. * @param string $filename (Required) The file name for the Amazon S3 object.
  2368. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2369. * <li><code>versionId</code> - <code>string</code> - Optional - The version of the object to retrieve. Version IDs are returned in the <code>x-amz-version-id</code> header of any previous object-related request.</li>
  2370. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2371. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2372. * @return mixed If the object exists, the method returns the collective metadata for the Amazon S3 object. If the object does not exist, the method returns boolean <code>false</code>.
  2373. */
  2374. public function get_object_metadata($bucket, $filename, $opt = null)
  2375. {
  2376. $batch = new CFBatchRequest();
  2377. $this->batch($batch)->get_object_acl($bucket, $filename); // Get ACL info
  2378. $this->batch($batch)->get_object_headers($bucket, $filename); // Get content-type
  2379. $this->batch($batch)->list_objects($bucket, array( // Get other metadata
  2380. 'max-keys' => 1,
  2381. 'prefix' => $filename
  2382. ));
  2383. $response = $this->batch($batch)->send();
  2384. // Fail if any requests were unsuccessful
  2385. if (!$response->areOK())
  2386. {
  2387. return false;
  2388. }
  2389. $data = array(
  2390. 'ACL' => array(),
  2391. 'ContentType' => null,
  2392. 'ETag' => null,
  2393. 'Headers' => null,
  2394. 'Key' => null,
  2395. 'LastModified' => null,
  2396. 'Owner' => array(),
  2397. 'Size' => null,
  2398. 'StorageClass' => null,
  2399. );
  2400. // Add the content type
  2401. $data['ContentType'] = (string) $response[1]->header['content-type'];
  2402. // Add the other metadata (including storage type)
  2403. $contents = json_decode(json_encode($response[2]->body->query('descendant-or-self::Contents')->first()), true);
  2404. $data = array_merge($data, (is_array($contents) ? $contents : array()));
  2405. // Add ACL info
  2406. $grants = $response[0]->body->query('descendant-or-self::Grant');
  2407. $max = count($grants);
  2408. // Add raw header info
  2409. $data['Headers'] = $response[1]->header;
  2410. foreach (array('_info', 'x-amz-id-2', 'x-amz-request-id', 'cneonction', 'server', 'content-length', 'content-type', 'etag') as $header)
  2411. {
  2412. unset($data['Headers'][$header]);
  2413. }
  2414. ksort($data['Headers']);
  2415. if (count($grants) > 0)
  2416. {
  2417. foreach ($grants as $grant)
  2418. {
  2419. $dgrant = array(
  2420. 'id' => (string) $this->util->try_these(array('ID', 'URI'), $grant->Grantee),
  2421. 'permission' => (string) $grant->Permission
  2422. );
  2423. $data['ACL'][] = $dgrant;
  2424. }
  2425. }
  2426. return $data;
  2427. }
  2428. /*%******************************************************************************************%*/
  2429. // URLS
  2430. /**
  2431. * Gets the web-accessible URL for the Amazon S3 object or generates a time-limited signed request for
  2432. * a private file.
  2433. *
  2434. * @param string $bucket (Required) The name of the bucket to use.
  2435. * @param string $filename (Required) The file name for the Amazon S3 object.
  2436. * @param integer|string $preauth (Optional) Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.
  2437. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2438. * <li><code>https</code> - <code>boolean</code> - Optional - Set to <code>true</code> if you would like the URL be in https mode. Otherwise, the default behavior is always to use http regardless of your SSL settings.</li>
  2439. * <li><code>method</code> - <code>string</code> - Optional - The HTTP method to use for the request. Defaults to a value of <code>GET</code>.</li>
  2440. * <li><code>response</code> - <code>array</code> - Optional - Allows adjustments to specific response headers. Pass an associative array where each key is one of the following: <code>cache-control</code>, <code>content-disposition</code>, <code>content-encoding</code>, <code>content-language</code>, <code>content-type</code>, <code>expires</code>. The <code>expires</code> value should use <php:gmdate()> and be formatted with the <code>DATE_RFC2822</code> constant.</li>
  2441. * <li><code>torrent</code> - <code>boolean</code> - Optional - A value of <code>true</code> will return a URL to a torrent of the Amazon S3 object. A value of <code>false</code> will return a non-torrent URL. Defaults to <code>false</code>.</li>
  2442. * <li><code>versionId</code> - <code>string</code> - Optional - The version of the object. Version IDs are returned in the <code>x-amz-version-id</code> header of any previous object-related request.</li>
  2443. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2444. * @return string The file URL, with authentication and/or torrent parameters if requested.
  2445. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/S3_QSAuth.html Using Query String Authentication
  2446. */
  2447. public function get_object_url($bucket, $filename, $preauth = 0, $opt = null)
  2448. {
  2449. // Add this to our request
  2450. if (!$opt) $opt = array();
  2451. $opt['verb'] = isset($opt['method']) ? $opt['method'] : 'GET';
  2452. $opt['resource'] = $filename;
  2453. $opt['preauth'] = $preauth;
  2454. if (isset($opt['torrent']) && $opt['torrent'])
  2455. {
  2456. $opt['sub_resource'] = 'torrent';
  2457. unset($opt['torrent']);
  2458. }
  2459. // GET responses
  2460. if (isset($opt['response']))
  2461. {
  2462. foreach ($opt['response'] as $key => $value)
  2463. {
  2464. $opt['response-' . $key] = $value;
  2465. unset($opt['response'][$key]);
  2466. }
  2467. }
  2468. // Determine whether or not to use SSL
  2469. $use_ssl = isset($opt['https']) ? (bool) $opt['https'] : false;
  2470. unset($opt['https']);
  2471. $current_use_ssl_setting = $this->use_ssl;
  2472. // Authenticate to S3
  2473. $this->use_ssl = $use_ssl;
  2474. $response = $this->authenticate($bucket, $opt);
  2475. $this->use_ssl = $current_use_ssl_setting;
  2476. return $response;
  2477. }
  2478. /**
  2479. * Gets the web-accessible URL to a torrent of the Amazon S3 object. The Amazon S3 object's access
  2480. * control list settings (ACL) MUST be set to <ACL_PUBLIC> for a valid URL to be returned.
  2481. *
  2482. * @param string $bucket (Required) The name of the bucket to use.
  2483. * @param string $filename (Required) The file name for the object.
  2484. * @param integer|string $preauth (Optional) Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.
  2485. * @return string The torrent URL, with authentication parameters if requested.
  2486. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?S3TorrentRetrieve.html Using BitTorrent to Retrieve Objects Stored in Amazon S3
  2487. */
  2488. public function get_torrent_url($bucket, $filename, $preauth = 0)
  2489. {
  2490. return $this->get_object_url($bucket, $filename, $preauth, array(
  2491. 'torrent' => true
  2492. ));
  2493. }
  2494. /*%******************************************************************************************%*/
  2495. // VERSIONING
  2496. /**
  2497. * Enables versioning support for the specified Amazon S3 bucket.
  2498. *
  2499. * @param string $bucket (Required) The name of the bucket to use.
  2500. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2501. * <li><code>MFASerial</code> - string (Optional) The serial number on the back of the Gemalto device. <code>MFASerial</code>, <code>MFAToken</code> and <code>MFAStatus</code> must all be set for MFA to work.</li>
  2502. * <li><code>MFAToken</code> - string (Optional) The current token displayed on the Gemalto device. <code>MFASerial</code>, <code>MFAToken</code> and <code>MFAStatus</code> must all be set for MFA to work.</li>
  2503. * <li><code>MFAStatus</code> - string (Optional) The MFA Delete status. Can be <code>Enabled</code> or <code>Disabled</code>. <code>MFASerial</code>, <code>MFAToken</code> and <code>MFAStatus</code> must all be set for MFA to work.</li>
  2504. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2505. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2506. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2507. * @link http://aws.amazon.com/mfa/ Multi-Factor Authentication
  2508. */
  2509. public function enable_versioning($bucket, $opt = null)
  2510. {
  2511. if (!$opt) $opt = array();
  2512. // Add this to our request
  2513. $opt['verb'] = 'PUT';
  2514. $opt['sub_resource'] = 'versioning';
  2515. $opt['headers'] = array(
  2516. 'Content-Type' => 'application/xml'
  2517. );
  2518. $xml = simplexml_load_string($this->base_versioning_xml);
  2519. $xml->addChild('Status', 'Enabled');
  2520. // Enable MFA delete?
  2521. // @codeCoverageIgnoreStart
  2522. if (isset($opt['MFASerial']) && isset($opt['MFAToken']) && isset($opt['MFAStatus']))
  2523. {
  2524. $xml->addChild('MfaDelete', $opt['MFAStatus']);
  2525. $opt['headers']['x-amz-mfa'] = ($opt['MFASerial'] . ' ' . $opt['MFAToken']);
  2526. }
  2527. // @codeCoverageIgnoreEnd
  2528. $opt['body'] = $xml->asXML();
  2529. // Authenticate to S3
  2530. return $this->authenticate($bucket, $opt);
  2531. }
  2532. /**
  2533. * Disables versioning support for the specified Amazon S3 bucket.
  2534. *
  2535. * @param string $bucket (Required) The name of the bucket to use.
  2536. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2537. * <li><code>MFASerial</code> - <code>string</code> - Optional - The serial number on the back of the Gemalto device. <code>MFASerial</code>, <code>MFAToken</code> and <code>MFAStatus</code> must all be set for MFA to work.</li>
  2538. * <li><code>MFAToken</code> - <code>string</code> - Optional - The current token displayed on the Gemalto device. <code>MFASerial</code>, <code>MFAToken</code> and <code>MFAStatus</code> must all be set for MFA to work.</li>
  2539. * <li><code>MFAStatus</code> - <code>string</code> - Optional - The MFA Delete status. Can be <code>Enabled</code> or <code>Disabled</code>. <code>MFASerial</code>, <code>MFAToken</code> and <code>MFAStatus</code> must all be set for MFA to work.</li>
  2540. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2541. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2542. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2543. * @link http://aws.amazon.com/mfa/ Multi-Factor Authentication
  2544. */
  2545. public function disable_versioning($bucket, $opt = null)
  2546. {
  2547. if (!$opt) $opt = array();
  2548. // Add this to our request
  2549. $opt['verb'] = 'PUT';
  2550. $opt['sub_resource'] = 'versioning';
  2551. $opt['headers'] = array(
  2552. 'Content-Type' => 'application/xml'
  2553. );
  2554. $xml = simplexml_load_string($this->base_versioning_xml);
  2555. $xml->addChild('Status', 'Suspended');
  2556. // Enable MFA delete?
  2557. // @codeCoverageIgnoreStart
  2558. if (isset($opt['MFASerial']) && isset($opt['MFAToken']) && isset($opt['MFAStatus']))
  2559. {
  2560. $xml->addChild('MfaDelete', $opt['MFAStatus']);
  2561. $opt['headers']['x-amz-mfa'] = ($opt['MFASerial'] . ' ' . $opt['MFAToken']);
  2562. }
  2563. // @codeCoverageIgnoreEnd
  2564. $opt['body'] = $xml->asXML();
  2565. // Authenticate to S3
  2566. return $this->authenticate($bucket, $opt);
  2567. }
  2568. /**
  2569. * Gets an Amazon S3 bucket's versioning status.
  2570. *
  2571. * @param string $bucket (Required) The name of the bucket to use.
  2572. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2573. * <li><code>preauth</code> - <code>integer|string</code> - Optional - Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.</li>
  2574. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2575. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2576. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2577. */
  2578. public function get_versioning_status($bucket, $opt = null)
  2579. {
  2580. if (!$opt) $opt = array();
  2581. $opt['verb'] = 'GET';
  2582. $opt['sub_resource'] = 'versioning';
  2583. // Authenticate to S3
  2584. return $this->authenticate($bucket, $opt);
  2585. }
  2586. /**
  2587. * Gets a list of all the versions of Amazon S3 objects in the specified bucket.
  2588. *
  2589. * @param string $bucket (Required) The name of the bucket to use.
  2590. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2591. * <li><code>delimiter</code> - <code>string</code> - Optional - Unicode string parameter. Keys that contain the same string between the prefix and the first occurrence of the delimiter will be rolled up into a single result element in the CommonPrefixes collection.</li>
  2592. * <li><code>key-marker</code> - <code>string</code> - Optional - Restricts the response to contain results that only occur alphabetically after the value of the <code>key-marker</code>.</li>
  2593. * <li><code>max-keys</code> - <code>string</code> - Optional - Limits the number of results returned in response to your query. Will return no more than this number of results, but possibly less.</li>
  2594. * <li><code>prefix</code> - <code>string</code> - Optional - Restricts the response to only contain results that begin with the specified prefix.</li>
  2595. * <li><code>version-id-marker</code> - <code>string</code> - Optional - Restricts the response to contain results that only occur alphabetically after the value of the <code>version-id-marker</code>.</li>
  2596. * <li><code>preauth</code> - <code>integer|string</code> - Optional - Specifies that a presigned URL for this request should be returned. May be passed as a number of seconds since UNIX Epoch, or any string compatible with <php:strtotime()>.</li>
  2597. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2598. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2599. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2600. */
  2601. public function list_bucket_object_versions($bucket, $opt = null)
  2602. {
  2603. if (!$opt) $opt = array();
  2604. $opt['verb'] = 'GET';
  2605. $opt['sub_resource'] = 'versions';
  2606. foreach (array('delimiter', 'key-marker', 'max-keys', 'prefix', 'version-id-marker') as $param)
  2607. {
  2608. if (isset($opt[$param]))
  2609. {
  2610. $opt['query_string'][$param] = $opt[$param];
  2611. unset($opt[$param]);
  2612. }
  2613. }
  2614. // Authenticate to S3
  2615. return $this->authenticate($bucket, $opt);
  2616. }
  2617. /*%******************************************************************************************%*/
  2618. // BUCKET POLICIES
  2619. /**
  2620. * Sets the policy sub-resource for the specified Amazon S3 bucket. The specified policy replaces any
  2621. * policy the bucket already has.
  2622. *
  2623. * To perform this operation, the caller must be authorized to set a policy for the bucket and have
  2624. * PutPolicy permissions. If the caller does not have PutPolicy permissions for the bucket, Amazon S3
  2625. * returns a `403 Access Denied` error. If the caller has the correct permissions but has not been
  2626. * authorized by the bucket owner, Amazon S3 returns a `405 Method Not Allowed` error.
  2627. *
  2628. * @param string $bucket (Required) The name of the bucket to use.
  2629. * @param CFPolicy $policy (Required) The JSON policy to use.
  2630. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2631. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2632. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2633. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2634. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/AccessPolicyLanguage.html Appendix: The Access Policy Language
  2635. */
  2636. public function set_bucket_policy($bucket, CFPolicy $policy, $opt = null)
  2637. {
  2638. if (!$opt) $opt = array();
  2639. $opt['verb'] = 'PUT';
  2640. $opt['sub_resource'] = 'policy';
  2641. $opt['body'] = $policy->get_json();
  2642. // Authenticate to S3
  2643. return $this->authenticate($bucket, $opt);
  2644. }
  2645. /**
  2646. * Gets the policy of the specified Amazon S3 bucket.
  2647. *
  2648. * To use this operation, the caller must have GetPolicy permissions for the specified bucket and must be
  2649. * the bucket owner. If the caller does not have GetPolicy permissions, this method will generate a
  2650. * `403 Access Denied` error. If the caller has the correct permissions but is not the bucket owner, this
  2651. * method will generate a `405 Method Not Allowed` error. If the bucket does not have a policy defined for
  2652. * it, this method will generate a `404 Policy Not Found` error.
  2653. *
  2654. * @param string $bucket (Required) The name of the bucket to use.
  2655. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2656. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2657. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2658. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2659. */
  2660. public function get_bucket_policy($bucket, $opt = null)
  2661. {
  2662. if (!$opt) $opt = array();
  2663. $opt['verb'] = 'GET';
  2664. $opt['sub_resource'] = 'policy';
  2665. // Authenticate to S3
  2666. return $this->authenticate($bucket, $opt);
  2667. }
  2668. /**
  2669. * Deletes the bucket policy for the specified Amazon S3 bucket. To delete the policy, the caller must
  2670. * be the bucket owner and have `DeletePolicy` permissions for the specified bucket.
  2671. *
  2672. * @param string $bucket (Required) The name of the bucket to use.
  2673. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2674. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2675. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2676. * @return CFResponse A <CFResponse> object containing a parsed HTTP response. If you do not have `DeletePolicy` permissions, Amazon S3 returns a `403 Access Denied` error. If you have the correct permissions, but are not the bucket owner, Amazon S3 returns a `405 Method Not Allowed` error. If the bucket doesn't have a policy, Amazon S3 returns a `204 No Content` error.
  2677. */
  2678. public function delete_bucket_policy($bucket, $opt = null)
  2679. {
  2680. if (!$opt) $opt = array();
  2681. $opt['verb'] = 'DELETE';
  2682. $opt['sub_resource'] = 'policy';
  2683. // Authenticate to S3
  2684. return $this->authenticate($bucket, $opt);
  2685. }
  2686. /*%******************************************************************************************%*/
  2687. // BUCKET NOTIFICATIONS
  2688. /**
  2689. * Enables notifications of specified events for an Amazon S3 bucket. Currently, the
  2690. * `s3:ReducedRedundancyLostObject` event is the only event supported for notifications. The
  2691. * `s3:ReducedRedundancyLostObject` event is triggered when Amazon S3 detects that it has lost all
  2692. * copies of an Amazon S3 object and can no longer service requests for that object.
  2693. *
  2694. * If the bucket owner and Amazon SNS topic owner are the same, the bucket owner has permission to
  2695. * publish notifications to the topic by default. Otherwise, the owner of the topic must create a
  2696. * policy to enable the bucket owner to publish to the topic.
  2697. *
  2698. * By default, only the bucket owner can configure notifications on a bucket. However, bucket owners
  2699. * can use bucket policies to grant permission to other users to set this configuration with the
  2700. * `s3:PutBucketNotification` permission.
  2701. *
  2702. * After a PUT operation is called to configure notifications on a bucket, Amazon S3 publishes a test
  2703. * notification to ensure that the topic exists and that the bucket owner has permission to publish
  2704. * to the specified topic. If the notification is successfully published to the SNS topic, the PUT
  2705. * operation updates the bucket configuration and returns the 200 OK responses with a
  2706. * `x-amz-sns-test-message-id` header containing the message ID of the test notification sent to topic.
  2707. *
  2708. * @param string $bucket (Required) The name of the bucket to create bucket notifications for.
  2709. * @param string $topic_arn (Required) The SNS topic ARN to send notifications to.
  2710. * @param string $event (Required) The event type to listen for.
  2711. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2712. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2713. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2714. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2715. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/NotificationHowTo.html Setting Up Notification of Bucket Events
  2716. */
  2717. public function create_bucket_notification($bucket, $topic_arn, $event, $opt = null)
  2718. {
  2719. if (!$opt) $opt = array();
  2720. $opt['verb'] = 'PUT';
  2721. $opt['sub_resource'] = 'notification';
  2722. $opt['headers'] = array(
  2723. 'Content-Type' => 'application/xml'
  2724. );
  2725. $xml = simplexml_load_string($this->base_notification_xml);
  2726. $topic_config = $xml->addChild('TopicConfiguration');
  2727. $topic_config->addChild('Topic', $topic_arn);
  2728. $topic_config->addChild('Event', $event);
  2729. $opt['body'] = $xml->asXML();
  2730. // Authenticate to S3
  2731. return $this->authenticate($bucket, $opt);
  2732. }
  2733. /**
  2734. * Gets the notification configuration of a bucket. Currently, the `s3:ReducedRedundancyLostObject` event
  2735. * is the only event supported for notifications. The `s3:ReducedRedundancyLostObject` event is triggered
  2736. * when Amazon S3 detects that it has lost all replicas of a Reduced Redundancy Storage object and can no
  2737. * longer service requests for that object.
  2738. *
  2739. * If notifications are not enabled on the bucket, the operation returns an empty
  2740. * `NotificatonConfiguration` element.
  2741. *
  2742. * By default, you must be the bucket owner to read the notification configuration of a bucket. However,
  2743. * the bucket owner can use a bucket policy to grant permission to other users to read this configuration
  2744. * with the `s3:GetBucketNotification` permission.
  2745. *
  2746. * @param string $bucket (Required) The name of the bucket to use.
  2747. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2748. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2749. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2750. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2751. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/NotificationHowTo.html Setting Up Notification of Bucket Events
  2752. */
  2753. public function get_bucket_notifications($bucket, $opt = null)
  2754. {
  2755. if (!$opt) $opt = array();
  2756. $opt['verb'] = 'GET';
  2757. $opt['sub_resource'] = 'notification';
  2758. // Authenticate to S3
  2759. return $this->authenticate($bucket, $opt);
  2760. }
  2761. /**
  2762. * Empties the list of SNS topics to send notifications to.
  2763. *
  2764. * @param string $bucket (Required) The name of the bucket to use.
  2765. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2766. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2767. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2768. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2769. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/NotificationHowTo.html Setting Up Notification of Bucket Events
  2770. */
  2771. public function delete_bucket_notification($bucket, $opt = null)
  2772. {
  2773. if (!$opt) $opt = array();
  2774. $opt['verb'] = 'PUT';
  2775. $opt['sub_resource'] = 'notification';
  2776. $opt['body'] = $this->base_notification_xml;
  2777. // Authenticate to S3
  2778. return $this->authenticate($bucket, $opt);
  2779. }
  2780. /*%******************************************************************************************%*/
  2781. // MULTIPART UPLOAD
  2782. /**
  2783. * Calculates the correct values for sequentially reading a file for multipart upload. This method should
  2784. * be used in conjunction with <upload_part()>.
  2785. *
  2786. * @param integer $filesize (Required) The size in bytes of the entire file.
  2787. * @param integer $part_size (Required) The size in bytes of the part of the file to send.
  2788. * @return array An array containing key-value pairs. The keys are `seekTo` and `length`.
  2789. */
  2790. public function get_multipart_counts($filesize, $part_size)
  2791. {
  2792. $i = 0;
  2793. $sizecount = $filesize;
  2794. $values = array();
  2795. while ($sizecount > 0)
  2796. {
  2797. $sizecount -= $part_size;
  2798. $values[] = array(
  2799. 'seekTo' => ($part_size * $i),
  2800. 'length' => (($sizecount > 0) ? $part_size : ($sizecount + $part_size)),
  2801. );
  2802. $i++;
  2803. }
  2804. return $values;
  2805. }
  2806. /**
  2807. * Initiates a multipart upload and returns an `UploadId`.
  2808. *
  2809. * @param string $bucket (Required) The name of the bucket to use.
  2810. * @param string $filename (Required) The file name for the object.
  2811. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2812. * <li><code>acl</code> - <code>string</code> - Optional - The ACL settings for the specified object. Accepts any of the following constants: [Allowed values: <code>AmazonS3::ACL_PRIVATE</code>, <code>AmazonS3::ACL_PUBLIC</code>, <code>AmazonS3::ACL_OPEN</code>, <code>AmazonS3::ACL_AUTH_READ</code>, <code>AmazonS3::ACL_OWNER_READ</code>, <code>AmazonS3::ACL_OWNER_FULL_CONTROL</code>]. Alternatively, an array of associative arrays. Each associative array contains an <code>id</code> and a <code>permission</code> key. The default value is <code>ACL_PRIVATE</code>.</li>
  2813. * <li><code>contentType</code> - <code>string</code> - Optional - The type of content that is being sent. The default value is <code>application/octet-stream</code>.</li>
  2814. * <li><code>encryption</code> - <code>string</code> - Optional - The algorithm to use for encrypting the object. [Allowed values: <code>AES256</code>]</li>
  2815. * <li><code>headers</code> - <code>array</code> - Optional - Standard HTTP headers to send along in the request. Accepts an associative array of key-value pairs.</li>
  2816. * <li><code>meta</code> - <code>array</code> - Optional - An associative array of key-value pairs. Any header starting with <code>x-amz-meta-:</code> is considered user metadata. It will be stored with the object and returned when you retrieve the object. The total size of the HTTP request, not including the body, must be less than 4 KB.</li>
  2817. * <li><code>storage</code> - <code>string</code> - Optional - Whether to use Standard or Reduced Redundancy storage. [Allowed values: <code>AmazonS3::STORAGE_STANDARD</code>, <code>AmazonS3::STORAGE_REDUCED</code>]. The default value is <code>STORAGE_STANDARD</code>.</li>
  2818. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2819. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2820. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2821. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAccessPolicy.html REST Access Control Policy
  2822. */
  2823. public function initiate_multipart_upload($bucket, $filename, $opt = null)
  2824. {
  2825. if (!$opt) $opt = array();
  2826. // Add this to our request
  2827. $opt['verb'] = 'POST';
  2828. $opt['resource'] = $filename;
  2829. $opt['sub_resource'] = 'uploads';
  2830. $opt['body'] = '';
  2831. // Handle content type. Can also be passed as an HTTP header.
  2832. if (isset($opt['contentType']))
  2833. {
  2834. $opt['headers']['Content-Type'] = $opt['contentType'];
  2835. unset($opt['contentType']);
  2836. }
  2837. // Set a default content type.
  2838. if (!isset($opt['headers']['Content-Type']))
  2839. {
  2840. $opt['headers']['Content-Type'] = 'application/octet-stream';
  2841. }
  2842. // Handle Access Control Lists. Can also be passed as an HTTP header.
  2843. if (isset($opt['acl']))
  2844. {
  2845. if (is_array($opt['acl']))
  2846. {
  2847. $opt['headers'] = array_merge($opt['headers'], $this->generate_access_policy_headers($opt['acl']));
  2848. }
  2849. else
  2850. {
  2851. $opt['headers']['x-amz-acl'] = $opt['acl'];
  2852. }
  2853. }
  2854. // Handle storage settings. Can also be passed as an HTTP header.
  2855. if (isset($opt['storage']))
  2856. {
  2857. $opt['headers']['x-amz-storage-class'] = $opt['storage'];
  2858. unset($opt['storage']);
  2859. }
  2860. // Handle encryption settings. Can also be passed as an HTTP header.
  2861. if (isset($opt['encryption']))
  2862. {
  2863. $opt['headers']['x-amz-server-side-encryption'] = $opt['encryption'];
  2864. unset($opt['encryption']);
  2865. }
  2866. // Handle meta tags. Can also be passed as an HTTP header.
  2867. if (isset($opt['meta']))
  2868. {
  2869. foreach ($opt['meta'] as $meta_key => $meta_value)
  2870. {
  2871. // e.g., `My Meta Header` is converted to `x-amz-meta-my-meta-header`.
  2872. $opt['headers']['x-amz-meta-' . strtolower(str_replace(' ', '-', $meta_key))] = $meta_value;
  2873. }
  2874. unset($opt['meta']);
  2875. }
  2876. // Authenticate to S3
  2877. return $this->authenticate($bucket, $opt);
  2878. }
  2879. /**
  2880. * Uploads a single part of a multipart upload. The part size cannot be smaller than 5 MB
  2881. * or larger than 5 TB. A multipart upload can have no more than 10,000 parts.
  2882. *
  2883. * Amazon S3 charges for storage as well as requests to the service. Smaller part sizes (and more
  2884. * requests) allow for faster failures and better upload reliability. Larger part sizes (and fewer
  2885. * requests) costs slightly less but has lower upload reliability.
  2886. *
  2887. * @param string $bucket (Required) The name of the bucket to use.
  2888. * @param string $filename (Required) The file name for the object.
  2889. * @param string $upload_id (Required) The upload ID identifying the multipart upload whose parts are being listed. The upload ID is retrieved from a call to <initiate_multipart_upload()>.
  2890. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2891. * <li><code>fileUpload</code> - <code>string|resource</code> - Required - The URL/path for the file to upload or an open resource.</li>
  2892. * <li><code>partNumber</code> - <code>integer</code> - Required - The part number order of the multipart upload.</li>
  2893. * <li><code>expect</code> - <code>string</code> - Optional - Specifies that the SDK not send the request body until it receives an acknowledgement. If the message is rejected based on the headers, the body of the message is not sent. For more information, see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.20">RFC 2616, section 14.20</a>. The value can also be passed to the <code>header</code> option as <code>Expect</code>. [Allowed values: <code>100-continue</code>]</li>
  2894. * <li><code>headers</code> - <code>array</code> - Optional - Standard HTTP headers to send along in the request. Accepts an associative array of key-value pairs.</li>
  2895. * <li><code>length</code> - <code>integer</code> - Optional - The size of the part in bytes. For more information, see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13">RFC 2616, section 14.13</a>. The value can also be passed to the <code>header</code> option as <code>Content-Length</code>.</li>
  2896. * <li><code>md5</code> - <code>string</code> - Optional - The base64 encoded 128-bit MD5 digest of the part data. This header can be used as a message integrity check to verify that the part data is the same data that was originally sent. Although it is optional, we recommend using this mechanism as an end-to-end integrity check. For more information, see <a href="http://www.ietf.org/rfc/rfc1864.txt">RFC 1864</a>. The value can also be passed to the <code>header</code> option as <code>Content-MD5</code>.</li>
  2897. * <li><code>seekTo</code> - <code>integer</code> - Optional - The starting position in bytes for the piece of the file/stream to upload.</li>
  2898. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2899. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2900. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2901. */
  2902. public function upload_part($bucket, $filename, $upload_id, $opt = null)
  2903. {
  2904. if (!$opt) $opt = array();
  2905. // Add this to our request
  2906. $opt['verb'] = 'PUT';
  2907. $opt['resource'] = $filename;
  2908. $opt['uploadId'] = $upload_id;
  2909. if (!isset($opt['fileUpload']) || !isset($opt['partNumber']))
  2910. {
  2911. throw new S3_Exception('The `fileUpload` and `partNumber` options are both required in ' . __FUNCTION__ . '().');
  2912. }
  2913. // Handle expectation. Can also be passed as an HTTP header.
  2914. if (isset($opt['expect']))
  2915. {
  2916. $opt['headers']['Expect'] = $opt['expect'];
  2917. unset($opt['expect']);
  2918. }
  2919. // Handle content length. Can also be passed as an HTTP header.
  2920. if (isset($opt['length']))
  2921. {
  2922. $opt['headers']['Content-Length'] = $opt['length'];
  2923. unset($opt['length']);
  2924. }
  2925. // Handle content md5. Can also be passed as an HTTP header.
  2926. if (isset($opt['md5']))
  2927. {
  2928. $opt['headers']['Content-MD5'] = $opt['md5'];
  2929. unset($opt['md5']);
  2930. }
  2931. $opt['headers']['Expect'] = '100-continue';
  2932. // Authenticate to S3
  2933. return $this->authenticate($bucket, $opt);
  2934. }
  2935. /**
  2936. * Lists the completed parts of an in-progress multipart upload.
  2937. *
  2938. * @param string $bucket (Required) The name of the bucket to use.
  2939. * @param string $filename (Required) The file name for the object.
  2940. * @param string $upload_id (Required) The upload ID identifying the multipart upload whose parts are being listed. The upload ID is retrieved from a call to <initiate_multipart_upload()>.
  2941. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2942. * <li><code>max-parts</code> - <code>integer</code> - Optional - The maximum number of parts to return in the response body.</li>
  2943. * <li><code>part-number-marker</code> - <code>string</code> - Optional - Restricts the response to contain results that only occur numerically after the value of the <code>part-number-marker</code>.</li>
  2944. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2945. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2946. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2947. */
  2948. public function list_parts($bucket, $filename, $upload_id, $opt = null)
  2949. {
  2950. if (!$opt) $opt = array();
  2951. // Add this to our request
  2952. $opt['verb'] = 'GET';
  2953. $opt['resource'] = $filename;
  2954. $opt['uploadId'] = $upload_id;
  2955. $opt['query_string'] = array();
  2956. foreach (array('max-parts', 'part-number-marker') as $param)
  2957. {
  2958. if (isset($opt[$param]))
  2959. {
  2960. $opt['query_string'][$param] = $opt[$param];
  2961. unset($opt[$param]);
  2962. }
  2963. }
  2964. // Authenticate to S3
  2965. return $this->authenticate($bucket, $opt);
  2966. }
  2967. /**
  2968. * Aborts an in-progress multipart upload. This operation cannot be reversed.
  2969. *
  2970. * @param string $bucket (Required) The name of the bucket to use.
  2971. * @param string $filename (Required) The file name for the object.
  2972. * @param string $upload_id (Required) The upload ID identifying the multipart upload whose parts are being listed. The upload ID is retrieved from a call to <initiate_multipart_upload()>.
  2973. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2974. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2975. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2976. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  2977. */
  2978. public function abort_multipart_upload($bucket, $filename, $upload_id, $opt = null)
  2979. {
  2980. if (!$opt) $opt = array();
  2981. // Add this to our request
  2982. $opt['verb'] = 'DELETE';
  2983. $opt['resource'] = $filename;
  2984. $opt['uploadId'] = $upload_id;
  2985. // Authenticate to S3
  2986. return $this->authenticate($bucket, $opt);
  2987. }
  2988. /**
  2989. * Completes an in-progress multipart upload. A multipart upload is completed by describing the part
  2990. * numbers and corresponding ETag values in order, and submitting that data to Amazon S3 as an XML document.
  2991. *
  2992. * @param string $bucket (Required) The name of the bucket to use.
  2993. * @param string $filename (Required) The file name for the object.
  2994. * @param string $upload_id (Required) The upload ID identifying the multipart upload whose parts are being listed. The upload ID is retrieved from a call to <initiate_multipart_upload()>.
  2995. * @param string|array|SimpleXMLElement|CFResponse $parts (Required) The completion XML document. This document can be provided in multiple ways; as a string of XML, as a <php:SimpleXMLElement> object representing the XML document, as an indexed array of associative arrays where the keys are <code>PartNumber</code> and <code>ETag</code>, or as a <CFResponse> object returned by <list_parts()>.
  2996. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  2997. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  2998. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  2999. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3000. */
  3001. public function complete_multipart_upload($bucket, $filename, $upload_id, $parts, $opt = null)
  3002. {
  3003. if (!$opt) $opt = array();
  3004. // Add this to our request
  3005. $opt['verb'] = 'POST';
  3006. $opt['resource'] = $filename;
  3007. $opt['uploadId'] = $upload_id;
  3008. $opt['headers'] = array(
  3009. 'Content-Type' => 'application/xml'
  3010. );
  3011. // Disable Content-MD5 calculation for this operation
  3012. $opt['NoContentMD5'] = true;
  3013. if (is_string($parts))
  3014. {
  3015. // Assume it's the intended XML.
  3016. $opt['body'] = $parts;
  3017. }
  3018. elseif ($parts instanceof SimpleXMLElement)
  3019. {
  3020. // Assume it's a SimpleXMLElement object representing the XML.
  3021. $opt['body'] = $parts->asXML();
  3022. }
  3023. elseif (is_array($parts) || $parts instanceof CFResponse)
  3024. {
  3025. $xml = simplexml_load_string($this->complete_mpu_xml);
  3026. if (is_array($parts))
  3027. {
  3028. // Generate the appropriate XML.
  3029. foreach ($parts as $node)
  3030. {
  3031. $part = $xml->addChild('Part');
  3032. $part->addChild('PartNumber', $node['PartNumber']);
  3033. $part->addChild('ETag', $node['ETag']);
  3034. }
  3035. }
  3036. elseif ($parts instanceof CFResponse)
  3037. {
  3038. // Assume it's a response from list_parts().
  3039. foreach ($parts->body->Part as $node)
  3040. {
  3041. $part = $xml->addChild('Part');
  3042. $part->addChild('PartNumber', (string) $node->PartNumber);
  3043. $part->addChild('ETag', (string) $node->ETag);
  3044. }
  3045. }
  3046. $opt['body'] = $xml->asXML();
  3047. }
  3048. // Authenticate to S3
  3049. return $this->authenticate($bucket, $opt);
  3050. }
  3051. /**
  3052. * Lists the in-progress multipart uploads.
  3053. *
  3054. * @param string $bucket (Required) The name of the bucket to use.
  3055. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3056. * <li><code>delimiter</code> - <code>string</code> - Optional - Keys that contain the same string between the prefix and the first occurrence of the delimiter will be rolled up into a single result element in the CommonPrefixes collection.</li>
  3057. * <li><code>key-marker</code> - <code>string</code> - Optional - Restricts the response to contain results that only occur alphabetically after the value of the <code>key-marker</code>. If used in conjunction with <code>upload-id-marker</code>, the results will be filtered to include keys whose upload ID is alphabetically after the value of <code>upload-id-marker</code>.</li>
  3058. * <li><code>upload-id-marker</code> - <code>string</code> - Optional - Restricts the response to contain results that only occur alphabetically after the value of the <code>upload-id-marker</code>. Must be used in conjunction with <code>key-marker</code>.</li>
  3059. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3060. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3061. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3062. */
  3063. public function list_multipart_uploads($bucket, $opt = null)
  3064. {
  3065. if (!$opt) $opt = array();
  3066. // Add this to our request
  3067. $opt['verb'] = 'GET';
  3068. $opt['sub_resource'] = 'uploads';
  3069. foreach (array('key-marker', 'max-uploads', 'upload-id-marker') as $param)
  3070. {
  3071. if (isset($opt[$param]))
  3072. {
  3073. $opt['query_string'][$param] = $opt[$param];
  3074. unset($opt[$param]);
  3075. }
  3076. }
  3077. // Authenticate to S3
  3078. return $this->authenticate($bucket, $opt);
  3079. }
  3080. /**
  3081. * Since Amazon S3's standard <copy_object()> operation only supports copying objects that are smaller than
  3082. * 5 GB, the ability to copy large objects (greater than 5 GB) requires the use of "Multipart Copy".
  3083. *
  3084. * Copying large objects requires the developer to initiate a new multipart "upload", copy pieces of the
  3085. * large object (specifying a range of bytes up to 5 GB from the large source file), then complete the
  3086. * multipart "upload".
  3087. *
  3088. * NOTE: <strong>This is a synchronous operation</strong>, not an <em>asynchronous</em> operation, which means
  3089. * that Amazon S3 will not return a response for this operation until the copy has completed across the Amazon
  3090. * S3 server fleet. Copying objects within a single region will complete more quickly than copying objects
  3091. * <em>across</em> regions. The synchronous nature of this operation is different from other services where
  3092. * responses are typically returned immediately, even if the operation itself has not yet been completed on
  3093. * the server-side.
  3094. *
  3095. * @param array $source (Required) The bucket and file name to copy from. The following keys must be set: <ul>
  3096. * <li><code>bucket</code> - <code>string</code> - Required - Specifies the name of the bucket containing the source object.</li>
  3097. * <li><code>filename</code> - <code>string</code> - Required - Specifies the file name of the source object to copy.</li></ul>
  3098. * @param array $dest (Required) The bucket and file name to copy to. The following keys must be set: <ul>
  3099. * <li><code>bucket</code> - <code>string</code> - Required - Specifies the name of the bucket to copy the object to.</li>
  3100. * <li><code>filename</code> - <code>string</code> - Required - Specifies the file name to copy the object to.</li></ul>
  3101. * @param string $upload_id (Required) The upload ID identifying the multipart upload whose parts are being listed. The upload ID is retrieved from a call to <initiate_multipart_upload()>.
  3102. * @param integer $part_number (Required) A part number uniquely identifies a part and defines its position within the destination object. When you complete a multipart upload, a complete object is created by concatenating parts in ascending order based on part number. If you copy a new part using the same part number as a previously copied/uploaded part, the previously written part is overwritten.
  3103. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3104. * <li><code>ifMatch</code> - <code>string</code> - Optional - The ETag header from a previous request. Copies the object if its entity tag (ETag) matches the specified tag; otherwise, the request returns a <code>412</code> HTTP status code error (precondition failed). Used in conjunction with <code>ifUnmodifiedSince</code>.</li>
  3105. * <li><code>ifUnmodifiedSince</code> - <code>string</code> - Optional - The LastModified header from a previous request. Copies the object if it hasn't been modified since the specified time; otherwise, the request returns a <code>412</code> HTTP status code error (precondition failed). Used in conjunction with <code>ifMatch</code>.</li>
  3106. * <li><code>ifNoneMatch</code> - <code>string</code> - Optional - The ETag header from a previous request. Copies the object if its entity tag (ETag) is different than the specified ETag; otherwise, the request returns a <code>412</code> HTTP status code error (failed condition). Used in conjunction with <code>ifModifiedSince</code>.</li>
  3107. * <li><code>ifModifiedSince</code> - <code>string</code> - Optional - The LastModified header from a previous request. Copies the object if it has been modified since the specified time; otherwise, the request returns a <code>412</code> HTTP status code error (failed condition). Used in conjunction with <code>ifNoneMatch</code>.</li>
  3108. * <li><code>range</code> - <code>string</code> - Optional - The range of bytes to copy from the object. Specify this parameter when copying partial bits. The specified range must be notated with a hyphen (e.g., 0-10485759). Defaults to the byte range of the complete Amazon S3 object.</li>
  3109. * <li><code>versionId</code> - <code>string</code> - Optional - The version of the object to copy. Version IDs are returned in the <code>x-amz-version-id</code> header of any previous object-related request.</li>
  3110. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3111. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3112. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3113. */
  3114. public function copy_part($source, $dest, $upload_id, $part_number, $opt = null)
  3115. {
  3116. if (!$opt) $opt = array();
  3117. // Add this to our request
  3118. $opt['verb'] = 'PUT';
  3119. $opt['resource'] = $dest['filename'];
  3120. $opt['uploadId'] = $upload_id;
  3121. $opt['partNumber'] = $part_number;
  3122. // Handle copy source
  3123. if (isset($source['bucket']) && isset($source['filename']))
  3124. {
  3125. $opt['headers']['x-amz-copy-source'] = '/' . $source['bucket'] . '/' . rawurlencode($source['filename'])
  3126. . (isset($opt['versionId']) ? ('?' . 'versionId=' . rawurlencode($opt['versionId'])) : ''); // Append the versionId to copy, if available
  3127. unset($opt['versionId']);
  3128. }
  3129. // Handle conditional-copy parameters
  3130. if (isset($opt['ifMatch']))
  3131. {
  3132. $opt['headers']['x-amz-copy-source-if-match'] = $opt['ifMatch'];
  3133. unset($opt['ifMatch']);
  3134. }
  3135. if (isset($opt['ifNoneMatch']))
  3136. {
  3137. $opt['headers']['x-amz-copy-source-if-none-match'] = $opt['ifNoneMatch'];
  3138. unset($opt['ifNoneMatch']);
  3139. }
  3140. if (isset($opt['ifUnmodifiedSince']))
  3141. {
  3142. $opt['headers']['x-amz-copy-source-if-unmodified-since'] = $opt['ifUnmodifiedSince'];
  3143. unset($opt['ifUnmodifiedSince']);
  3144. }
  3145. if (isset($opt['ifModifiedSince']))
  3146. {
  3147. $opt['headers']['x-amz-copy-source-if-modified-since'] = $opt['ifModifiedSince'];
  3148. unset($opt['ifModifiedSince']);
  3149. }
  3150. // Partial content range
  3151. if (isset($opt['range']))
  3152. {
  3153. $opt['headers']['x-amz-copy-source-range'] = 'bytes=' . $opt['range'];
  3154. }
  3155. // Authenticate to S3
  3156. return $this->authenticate($dest['bucket'], $opt);
  3157. }
  3158. /**
  3159. * Creates an Amazon S3 object using the multipart upload APIs. It is analogous to <create_object()>.
  3160. *
  3161. * While each individual part of a multipart upload can hold up to 5 GB of data, this method limits the
  3162. * part size to a maximum of 500 MB. The combined size of all parts can not exceed 5 TB of data. When an
  3163. * object is stored in Amazon S3, the data is streamed to multiple storage servers in multiple data
  3164. * centers. This ensures the data remains available in the event of internal network or hardware failure.
  3165. *
  3166. * Amazon S3 charges for storage as well as requests to the service. Smaller part sizes (and more
  3167. * requests) allow for faster failures and better upload reliability. Larger part sizes (and fewer
  3168. * requests) costs slightly less but has lower upload reliability.
  3169. *
  3170. * In certain cases with large objects, it's possible for this method to attempt to open more file system
  3171. * connections than allowed by the OS. In this case, either
  3172. * <a href="https://forums.aws.amazon.com/thread.jspa?threadID=70216">increase the number of connections
  3173. * allowed</a> or increase the value of the <code>partSize</code> parameter to use a larger part size.
  3174. *
  3175. * @param string $bucket (Required) The name of the bucket to use.
  3176. * @param string $filename (Required) The file name for the object.
  3177. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3178. * <li><code>fileUpload</code> - <code>string|resource</code> - Required - The URL/path for the file to upload, or an open resource.</li>
  3179. * <li><code>acl</code> - <code>string</code> - Optional - The ACL settings for the specified object. [Allowed values: <code>AmazonS3::ACL_PRIVATE</code>, <code>AmazonS3::ACL_PUBLIC</code>, <code>AmazonS3::ACL_OPEN</code>, <code>AmazonS3::ACL_AUTH_READ</code>, <code>AmazonS3::ACL_OWNER_READ</code>, <code>AmazonS3::ACL_OWNER_FULL_CONTROL</code>]. The default value is <code>ACL_PRIVATE</code>.</li>
  3180. * <li><code>contentType</code> - <code>string</code> - Optional - The type of content that is being sent in the body. The default value is <code>application/octet-stream</code>.</li>
  3181. * <li><code>headers</code> - <code>array</code> - Optional - Standard HTTP headers to send along in the request. Accepts an associative array of key-value pairs.</li>
  3182. * <li><code>length</code> - <code>integer</code> - Optional - The size of the object in bytes. For more information, see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13">RFC 2616, section 14.13</a>. The value can also be passed to the <code>header</code> option as <code>Content-Length</code>.</li>
  3183. * <li><code>limit</code> - <code>integer</code> - Optional - The maximum number of concurrent uploads done by cURL. Gets passed to <code>CFBatchRequest</code>.</li>
  3184. * <li><code>meta</code> - <code>array</code> - Optional - An associative array of key-value pairs. Any header starting with <code>x-amz-meta-:</code> is considered user metadata. It will be stored with the object and returned when you retrieve the object. The total size of the HTTP request, not including the body, must be less than 4 KB.</li>
  3185. * <li><code>partSize</code> - <code>integer</code> - Optional - The size of an individual part. The size may not be smaller than 5 MB or larger than 500 MB. The default value is 50 MB.</li>
  3186. * <li><code>redirectTo</code> - <code>string</code> - Optional - The URI to send an HTTP 301 redirect to when accessing this object. Value must be prefixed either <code>/</code>, <code>http://</code> or <code>https://</code>.</li>
  3187. * <li><code>seekTo</code> - <code>integer</code> - Optional - The starting position in bytes for the first piece of the file/stream to upload.</li>
  3188. * <li><code>storage</code> - <code>string</code> - Optional - Whether to use Standard or Reduced Redundancy storage. [Allowed values: <code>AmazonS3::STORAGE_STANDARD</code>, <code>AmazonS3::STORAGE_REDUCED</code>]. The default value is <code>STORAGE_STANDARD</code>.</li>
  3189. * <li><code>uploadId</code> - <code>string</code> - Optional - An upload ID identifying an existing multipart upload to use. If this option is not set, one will be created automatically.</li>
  3190. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3191. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3192. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3193. * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAccessPolicy.html REST Access Control Policy
  3194. */
  3195. public function create_mpu_object($bucket, $filename, $opt = null)
  3196. {
  3197. if ($this->use_batch_flow)
  3198. {
  3199. throw new S3_Exception(__FUNCTION__ . '() cannot be batch requested');
  3200. }
  3201. if (!$opt) $opt = array();
  3202. // Handle content length. Can also be passed as an HTTP header.
  3203. if (isset($opt['length']))
  3204. {
  3205. $opt['headers']['Content-Length'] = $opt['length'];
  3206. unset($opt['length']);
  3207. }
  3208. // URI to redirect to. Can also be passed as an HTTP header.
  3209. if (isset($opt['redirectTo']))
  3210. {
  3211. $opt['headers']['x-amz-website-redirect-location'] = $opt['redirectTo'];
  3212. unset($opt['redirectTo']);
  3213. }
  3214. if (!isset($opt['fileUpload']))
  3215. {
  3216. throw new S3_Exception('The `fileUpload` option is required in ' . __FUNCTION__ . '().');
  3217. }
  3218. elseif (is_resource($opt['fileUpload']))
  3219. {
  3220. $opt['limit'] = 1; // We can only read from this one resource.
  3221. $upload_position = isset($opt['seekTo']) ? (integer) $opt['seekTo'] : ftell($opt['fileUpload']);
  3222. $upload_filesize = isset($opt['headers']['Content-Length']) ? (integer) $opt['headers']['Content-Length'] : null;
  3223. if (!isset($upload_filesize) && $upload_position !== false)
  3224. {
  3225. $stats = fstat($opt['fileUpload']);
  3226. if ($stats && $stats['size'] >= 0)
  3227. {
  3228. $upload_filesize = $stats['size'] - $upload_position;
  3229. }
  3230. }
  3231. }
  3232. else
  3233. {
  3234. $upload_position = isset($opt['seekTo']) ? (integer) $opt['seekTo'] : 0;
  3235. if (isset($opt['headers']['Content-Length']))
  3236. {
  3237. $upload_filesize = (integer) $opt['headers']['Content-Length'];
  3238. }
  3239. else
  3240. {
  3241. $upload_filesize = filesize($opt['fileUpload']);
  3242. if ($upload_filesize !== false)
  3243. {
  3244. $upload_filesize -= $upload_position;
  3245. }
  3246. }
  3247. }
  3248. if ($upload_position === false || !isset($upload_filesize) || $upload_filesize === false || $upload_filesize < 0)
  3249. {
  3250. throw new S3_Exception('The size of `fileUpload` cannot be determined in ' . __FUNCTION__ . '().');
  3251. }
  3252. // Handle part size
  3253. if (isset($opt['partSize']))
  3254. {
  3255. // If less that 5 MB...
  3256. if ((integer) $opt['partSize'] < 5242880)
  3257. {
  3258. $opt['partSize'] = 5242880; // 5 MB
  3259. }
  3260. // If more than 500 MB...
  3261. elseif ((integer) $opt['partSize'] > 524288000)
  3262. {
  3263. $opt['partSize'] = 524288000; // 500 MB
  3264. }
  3265. }
  3266. else
  3267. {
  3268. $opt['partSize'] = 52428800; // 50 MB
  3269. }
  3270. // If the upload size is smaller than the piece size, failover to create_object().
  3271. if ($upload_filesize < $opt['partSize'] && !isset($opt['uploadId']))
  3272. {
  3273. return $this->create_object($bucket, $filename, $opt);
  3274. }
  3275. // Initiate multipart upload
  3276. if (isset($opt['uploadId']))
  3277. {
  3278. $upload_id = $opt['uploadId'];
  3279. }
  3280. else
  3281. {
  3282. // Compose options for initiate_multipart_upload().
  3283. $_opt = array();
  3284. foreach (array('contentType', 'acl', 'storage', 'headers', 'meta') as $param)
  3285. {
  3286. if (isset($opt[$param]))
  3287. {
  3288. $_opt[$param] = $opt[$param];
  3289. }
  3290. }
  3291. $upload = $this->initiate_multipart_upload($bucket, $filename, $_opt);
  3292. if (!$upload->isOK())
  3293. {
  3294. return $upload;
  3295. }
  3296. // Fetch the UploadId
  3297. $upload_id = (string) $upload->body->UploadId;
  3298. }
  3299. // Get the list of pieces
  3300. $pieces = $this->get_multipart_counts($upload_filesize, (integer) $opt['partSize']);
  3301. // Queue batch requests
  3302. $batch = new CFBatchRequest(isset($opt['limit']) ? (integer) $opt['limit'] : null);
  3303. foreach ($pieces as $i => $piece)
  3304. {
  3305. $this->batch($batch)->upload_part($bucket, $filename, $upload_id, array(
  3306. 'expect' => '100-continue',
  3307. 'fileUpload' => $opt['fileUpload'],
  3308. 'partNumber' => ($i + 1),
  3309. 'seekTo' => $upload_position + (integer) $piece['seekTo'],
  3310. 'length' => (integer) $piece['length'],
  3311. ));
  3312. }
  3313. // Send batch requests
  3314. $batch_responses = $this->batch($batch)->send();
  3315. if (!$batch_responses->areOK())
  3316. {
  3317. return $batch_responses;
  3318. }
  3319. // Compose completion XML
  3320. $parts = array();
  3321. foreach ($batch_responses as $i => $response)
  3322. {
  3323. $parts[] = array('PartNumber' => ($i + 1), 'ETag' => $response->header['etag']);
  3324. }
  3325. return $this->complete_multipart_upload($bucket, $filename, $upload_id, $parts);
  3326. }
  3327. /**
  3328. * Aborts all multipart uploads initiated before the specified date. This operation cannot be reversed.
  3329. *
  3330. * @param string $bucket (Required) The name of the bucket to use.
  3331. * @param string|integer $when (Optional) The time and date to use for comparison. Accepts any value that <php:strtotime()> understands.
  3332. * @return CFArray A <CFArray> containing a series of 0 or more <CFResponse> objects, containing a parsed HTTP response.
  3333. */
  3334. public function abort_multipart_uploads_by_date($bucket, $when = null)
  3335. {
  3336. if ($this->use_batch_flow)
  3337. {
  3338. // @codeCoverageIgnoreStart
  3339. throw new S3_Exception(__FUNCTION__ . '() cannot be batch requested');
  3340. // @codeCoverageIgnoreEnd
  3341. }
  3342. $when = $when ? $when : time();
  3343. $handles = array();
  3344. $data = $this->list_multipart_uploads($bucket)->body;
  3345. $when = is_int($when) ? $when : strtotime($when);
  3346. if (!($data instanceof CFSimpleXML))
  3347. {
  3348. return false;
  3349. }
  3350. $list = $data->query('descendant-or-self::Upload/Initiated');
  3351. if (count($list) > 0)
  3352. {
  3353. foreach ($list as $node)
  3354. {
  3355. if (strtotime((string) $node) < $when)
  3356. {
  3357. $q = new CFBatchRequest();
  3358. $parent = $node->parent();
  3359. $upload_id = $parent
  3360. ->query('descendant-or-self::UploadId')
  3361. ->first()
  3362. ->to_string();
  3363. $filename = $parent
  3364. ->query('descendant-or-self::Key')
  3365. ->first()
  3366. ->to_string();
  3367. $handles[] = $this->abort_multipart_upload($bucket, $filename, $upload_id, array(
  3368. 'returnCurlHandle' => true
  3369. ));
  3370. }
  3371. }
  3372. $http = new CFRequest();
  3373. $responses = $http->send_multi_request($handles);
  3374. if (is_array($responses) && count($responses) > 0)
  3375. {
  3376. return new CFArray($responses);
  3377. }
  3378. }
  3379. return new CFArray();
  3380. }
  3381. /*%******************************************************************************************%*/
  3382. // WEBSITE CONFIGURATION
  3383. /**
  3384. * Enables and configures an Amazon S3 website using the corresponding bucket as the content source.
  3385. * The website will have one default domain name associated with it, which is the bucket name. If you
  3386. * attempt to configure an Amazon S3 website for a bucket whose name is not compatible with DNS,
  3387. * Amazon S3 returns an <code>InvalidBucketName</code> error. For more information on bucket names and DNS,
  3388. * refer to <a href="http://docs.amazonwebservices.com/AmazonS3/latest/dev/BucketRestrictions.html">Bucket Restrictions and Limitations.</a>
  3389. *
  3390. * To visit the bucket as a website a new endpoint is created in the following pattern:
  3391. * <code>http://&lt;bucketName&gt;.s3-website-&lt;region&gt;.amazonaws.com</code>. This is a sample URL
  3392. * for a bucket called <code>example-bucket</code> in the <code>us-east-1</code> region.
  3393. * (e.g., <code>http://example-bucket.s3-website-us-east-1.amazonaws.com</code>)
  3394. *
  3395. * @param string $bucket (Required) The name of the bucket to use.
  3396. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3397. * <li><code>indexDocument</code> - <code>string</code> - Optional - The file path to use as the root document. The default value is <code>index.html</code>.</li>
  3398. * <li><code>errorDocument</code> - <code>string</code> - Optional - The file path to use as the error document. The default value is <code>error.html</code>.</li>
  3399. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3400. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3401. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3402. */
  3403. public function create_website_config($bucket, $opt = null)
  3404. {
  3405. if (!$opt) $opt = array();
  3406. $opt['verb'] = 'PUT';
  3407. $opt['sub_resource'] = 'website';
  3408. $xml = simplexml_load_string($this->website_config_xml);
  3409. if (isset($opt['indexDocument']))
  3410. {
  3411. $xml->IndexDocument->Suffix = $opt['indexDocument'];
  3412. }
  3413. if (isset($opt['errorDocument']))
  3414. {
  3415. $xml->ErrorDocument->Key = $opt['errorDocument'];
  3416. }
  3417. $opt['body'] = $xml->asXML();
  3418. // Authenticate to S3
  3419. return $this->authenticate($bucket, $opt);
  3420. }
  3421. /**
  3422. * Retrieves the website configuration for a bucket. The contents of this response are identical to the
  3423. * content submitted by the user during the website creation operation. If a website configuration has
  3424. * never been set, Amazon S3 will return a 404 error.
  3425. *
  3426. * @param string $bucket (Required) The name of the bucket to use.
  3427. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3428. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3429. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3430. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3431. */
  3432. public function get_website_config($bucket, $opt = null)
  3433. {
  3434. if (!$opt) $opt = array();
  3435. $opt['verb'] = 'GET';
  3436. $opt['sub_resource'] = 'website';
  3437. $opt['headers'] = array(
  3438. 'Content-Type' => 'application/xml'
  3439. );
  3440. // Authenticate to S3
  3441. return $this->authenticate($bucket, $opt);
  3442. }
  3443. /**
  3444. * Removes the website configuration for a bucket.
  3445. *
  3446. * @param string $bucket (Required) The name of the bucket to use.
  3447. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3448. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3449. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3450. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3451. */
  3452. public function delete_website_config($bucket, $opt = null)
  3453. {
  3454. if (!$opt) $opt = array();
  3455. $opt['verb'] = 'DELETE';
  3456. $opt['sub_resource'] = 'website';
  3457. // Authenticate to S3
  3458. return $this->authenticate($bucket, $opt);
  3459. }
  3460. /*%******************************************************************************************%*/
  3461. // OBJECT LIFECYCLE
  3462. /**
  3463. * Enables the ability to specify a configuration that relates to the object's _lifecycle_.
  3464. *
  3465. * **NOTE:** In cases where the lifecycle configuration dictates that an object should be deleted, Amazon S3
  3466. * guarantees that the object will be deleted when the expiration time is passed.
  3467. *
  3468. * @param string $bucket (Required) The name of the bucket to use.
  3469. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3470. * <li><code>rules</code> - <code>string</code> - Required - The object expiration rule-sets to apply to the bucket. <ul>
  3471. * <li><code>x</code> - <code>array</code> - Required - This represents a simple array index. <ul>
  3472. * <li><code>id</code> - <code>string</code> - Optional - Unique identifier for the rule. The value cannot be longer than 255 characters.</li>
  3473. * <li><code>prefix</code> - <code>string</code> - Required - The Amazon S3 object prefix which targets the file(s) for expiration.</li>
  3474. * <li><code>expiration</code> - <code>array</code> - Optional - The container for the unit of measurement by which the expiration time is calculated. At least one action (either <code>transition</code> or <code>expiration</code>) is required within one lifecycle rule. <ul>
  3475. * <li><code>date</code> - <code>string</code> - Conditionally Required - The timestamp for when the targetted objects are to be moved or expired from the bucket. Should be in ISO 8601 Format. HH:MM:SS will be enforced as midnight GMT/UTC.</li>
  3476. * <li><code>days</code> - <code>integer</code> - Conditionally Required - The number of days until the targetted objects are to be moved or expired from the bucket. Must be a positive integer.</li>
  3477. * </ul></li>
  3478. * <li><code>transition</code> - <code>array</code> - Optional - The container for the element that describes a transition action. At least one action (either <code>transition</code> or <code>expiration</code>) is required within one lifecycle rule. <ul>
  3479. * <li><code>date</code> - <code>string</code> - Conditionally Required - The timestamp for when the targetted objects are to be moved or expired from the bucket. Should be in ISO 8601 Format. HH:MM:SS will be enforced as midnight GMT/UTC.</li>
  3480. * <li><code>days</code> - <code>integer</code> - Conditionally Required - The number of days until the targetted objects are to be moved or expired from the bucket. Must be a positive integer.</li>
  3481. * <li><code>storage</code> - <code>string</code> - Required - The storage setting of an object. [Allowed values: <code>AmazonS3::STORAGE_STANDARD</code>, <code>AmazonS3::STORAGE_REDUCED</code>, <code>STORAGE_GLACIER</code>]. The default value is <code>STORAGE_STANDARD</code>.</li>
  3482. * </ul></li>
  3483. * <li><code>enabled</code> - <code>boolean</code> - Optional - Whether or not to enable this rule-set. A value of <code>true</code> enables the rule-set. A value of <code>false</code> disables the rule-set. The default value is <code>true</code>.</li>
  3484. * </ul></li>
  3485. * </ul></li>
  3486. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3487. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3488. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3489. */
  3490. public function create_lifecycle_config($bucket, $opt = null)
  3491. {
  3492. if (!$opt) $opt = array();
  3493. $opt['verb'] = 'PUT';
  3494. $opt['sub_resource'] = 'lifecycle';
  3495. $opt['headers'] = array(
  3496. 'Content-Type' => 'application/xml'
  3497. );
  3498. $xml = simplexml_load_string($this->object_expiration_xml, $this->parser_class);
  3499. if (isset($opt['rules']) && is_array($opt['rules']) && count($opt['rules']))
  3500. {
  3501. foreach ($opt['rules'] as $rule)
  3502. {
  3503. $xrule = $xml->addChild('Rule');
  3504. // ID
  3505. if (isset($rule['id']))
  3506. {
  3507. if (strlen($rule['id']) > 255)
  3508. {
  3509. throw new S3_Exception('The "id" for a rule must not be more than 255 characters in the ' . __FUNCTION__ . ' method.');
  3510. }
  3511. $xrule->addChild('ID', $rule['id']);
  3512. }
  3513. // Prefix
  3514. if (isset($rule['prefix']))
  3515. {
  3516. $xrule->addChild('Prefix', $rule['prefix']);
  3517. }
  3518. else
  3519. {
  3520. throw new S3_Exception('Each rule requires a "prefix" in the ' . __FUNCTION__ . ' method.');
  3521. }
  3522. // Status
  3523. $enabled = 'Enabled';
  3524. if (isset($rule['enabled']))
  3525. {
  3526. if (is_bool($rule['enabled'])) // Boolean
  3527. {
  3528. $enabled = $rule['enabled'] ? 'Enabled' : 'Disabled';
  3529. }
  3530. elseif (is_string($rule['enabled'])) // String
  3531. {
  3532. $enabled = (strtolower($rule['enabled']) === 'true') ? 'Enabled' : 'Disabled';
  3533. }
  3534. $xrule->addChild('Status', $enabled);
  3535. }
  3536. else
  3537. {
  3538. $xrule->addChild('Status', 'Enabled');
  3539. }
  3540. // Expiration
  3541. if (isset($rule['expiration']))
  3542. {
  3543. $xexpiration = $xrule->addChild('Expiration');
  3544. if (isset($rule['expiration']['date']))
  3545. {
  3546. $xexpiration->addChild('Date', $rule['expiration']['date']);
  3547. }
  3548. elseif (isset($rule['expiration']['days']))
  3549. {
  3550. $xexpiration->addChild('Days', $rule['expiration']['days']);
  3551. }
  3552. }
  3553. // Transition
  3554. if (isset($rule['transition']))
  3555. {
  3556. $xtransition = $xrule->addChild('Transition');
  3557. if (isset($rule['transition']['date']))
  3558. {
  3559. $xtransition->addChild('Date', $rule['transition']['date']);
  3560. }
  3561. elseif (isset($rule['transition']['days']))
  3562. {
  3563. $xtransition->addChild('Days', $rule['transition']['days']);
  3564. }
  3565. if (isset($rule['transition']['storage']))
  3566. {
  3567. $xtransition->addChild('StorageClass', $rule['transition']['storage']);
  3568. }
  3569. }
  3570. if (!isset($rule['expiration']) && !isset($rule['transition']))
  3571. {
  3572. throw new S3_Exception('Each rule requires a either a "transition" or "expiration" entry in the ' . __FUNCTION__ . ' method.');
  3573. }
  3574. }
  3575. }
  3576. $opt['body'] = $xml->asXML();
  3577. // Authenticate to S3
  3578. return $this->authenticate($bucket, $opt);
  3579. }
  3580. /**
  3581. * Retrieves the configuration that relates to the object's _lifecycle_.
  3582. *
  3583. * @param string $bucket (Required) The name of the bucket to use.
  3584. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3585. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3586. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3587. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3588. */
  3589. public function get_lifecycle_config($bucket, $opt = null)
  3590. {
  3591. if (!$opt) $opt = array();
  3592. $opt['verb'] = 'GET';
  3593. $opt['sub_resource'] = 'lifecycle';
  3594. // Authenticate to S3
  3595. return $this->authenticate($bucket, $opt);
  3596. }
  3597. /**
  3598. * Deletes the configuration that relates to the object's _lifecycle_.
  3599. *
  3600. * @param string $bucket (Required) The name of the bucket to use.
  3601. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3602. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3603. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3604. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3605. */
  3606. public function delete_lifecycle_config($bucket, $opt = null)
  3607. {
  3608. if (!$opt) $opt = array();
  3609. $opt['verb'] = 'DELETE';
  3610. $opt['sub_resource'] = 'lifecycle';
  3611. // Authenticate to S3
  3612. return $this->authenticate($bucket, $opt);
  3613. }
  3614. /**
  3615. * Restore an object archived in Amazon Glacier back to Amazon S3.
  3616. *
  3617. * @param string $bucket (Required) The name of the bucket to use.
  3618. * @param string $filename (Required) The file name for the object.
  3619. * @param integer $days (Required) The number of days until the targetted objects are to be moved or expired from the bucket. Must be a positive integer.
  3620. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3621. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3622. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3623. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3624. */
  3625. public function restore_archived_object($bucket, $filename, $days, $opt = null)
  3626. {
  3627. if (!$opt) $opt = array();
  3628. $opt['verb'] = 'POST';
  3629. $opt['sub_resource'] = 'restore';
  3630. $opt['headers'] = array(
  3631. 'Content-Type' => 'application/xml'
  3632. );
  3633. $xml = simplexml_load_string($this->restore_request_xml, $this->parser_class);
  3634. $xml->addChild('Days', (integer) $days);
  3635. $opt['body'] = $xml->asXML();
  3636. // Authenticate to S3
  3637. return $this->authenticate($bucket, $opt);
  3638. }
  3639. /**
  3640. * Alias of {@see AmazonS3::create_lifecycle_config()}.
  3641. *
  3642. * @deprecated
  3643. */
  3644. public function create_object_expiration_config($bucket, $opt = null)
  3645. {
  3646. return $this->create_lifecycle_config($bucket, $opt);
  3647. }
  3648. /**
  3649. * Alias of {@see AmazonS3::get_lifecycle_config()}.
  3650. *
  3651. * @deprecated
  3652. */
  3653. public function get_object_expiration_config($bucket, $opt = null)
  3654. {
  3655. return $this->get_lifecycle_config($bucket, $opt);
  3656. }
  3657. /**
  3658. * Alias of {@see AmazonS3::delete_lifecycle_config()}.
  3659. *
  3660. * @deprecated
  3661. */
  3662. public function delete_object_expiration_config($bucket, $opt = null)
  3663. {
  3664. return $this->delete_lifecycle_config($bucket, $opt);
  3665. }
  3666. /*%******************************************************************************************%*/
  3667. // BUCKET TAGS
  3668. /**
  3669. * Apply a set of tags to the specified bucket. Bucket Tags simplify the task of associating Amazon S3
  3670. * costs with specific buckets.
  3671. *
  3672. * This operation requires permission to perform <code>s3:PutBucketTagging</code> actions. By default,
  3673. * the bucket owner is permitted to perform these actions, and can grant permission to other users.
  3674. *
  3675. * @param string $bucket (Required) The name of the bucket to use.
  3676. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3677. * <li><code>tags</code> - <code>array</code> - Required - An associative array of custom key-value pairs. <ul>
  3678. * <li><code>[custom-key]</code> - <code>string</code> - Optional - A custom key-value pair to tag the bucket with.</li>
  3679. * </ul></li>
  3680. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3681. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3682. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3683. */
  3684. public function create_bucket_tags($bucket, $opt = null)
  3685. {
  3686. if (!$opt) $opt = array();
  3687. $opt['verb'] = 'PUT';
  3688. $opt['sub_resource'] = 'tagging';
  3689. $xml = simplexml_load_string($this->bucket_tagging_xml);
  3690. if (isset($opt['tags']) && is_array($opt['tags']))
  3691. {
  3692. foreach ($opt['tags'] as $key => $value)
  3693. {
  3694. $xtag = $xml->TagSet->addChild('Tag');
  3695. $xtag->addChild('Key', $key);
  3696. $xtag->addChild('Value', $value);
  3697. }
  3698. }
  3699. $opt['body'] = $xml->asXML();
  3700. // Authenticate to S3
  3701. return $this->authenticate($bucket, $opt);
  3702. }
  3703. /**
  3704. * Retrieve all associated tags for the specified bucket.
  3705. *
  3706. * @param string $bucket (Required) The name of the bucket to use.
  3707. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3708. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3709. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3710. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3711. */
  3712. public function get_bucket_tags($bucket, $opt = null)
  3713. {
  3714. if (!$opt) $opt = array();
  3715. $opt['verb'] = 'GET';
  3716. $opt['sub_resource'] = 'tagging';
  3717. $opt['headers'] = array(
  3718. 'Content-Type' => 'application/xml'
  3719. );
  3720. // Authenticate to S3
  3721. return $this->authenticate($bucket, $opt);
  3722. }
  3723. /**
  3724. * Delete all associated tags from the specified bucket.
  3725. *
  3726. * @param string $bucket (Required) The name of the bucket to use.
  3727. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3728. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3729. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3730. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3731. */
  3732. public function delete_bucket_tags($bucket, $opt = null)
  3733. {
  3734. if (!$opt) $opt = array();
  3735. $opt['verb'] = 'DELETE';
  3736. $opt['sub_resource'] = 'tagging';
  3737. // Authenticate to S3
  3738. return $this->authenticate($bucket, $opt);
  3739. }
  3740. /*%******************************************************************************************%*/
  3741. // CROSS-ORIGIN RESOURCE SHARING (CORS)
  3742. /**
  3743. * Create a new CORS configuration.
  3744. *
  3745. * @param string $bucket (Required) The name of the bucket to use.
  3746. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3747. * <li><code>cors_rule</code> - <code>array</code> - Required - One or more rule-sets. <ul>
  3748. * <li><code>x</code> - <code>array</code> - Required - This represents a simple array index. <ul>
  3749. * <li><code>allowed_header</code> - <code>array</code> - Required - Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.</li>
  3750. * <li><code>allowed_method</code> - <code>array</code> - Required - An array of HTTP methods to allow. There must be at least one method set. [Allowed values: `GET`, `PUT`, `HEAD`, `POST`, `DELETE`]</li>
  3751. * <li><code>allowed_origin</code> - <code>array</code> - Required - An array of hostnames to allow. This could be `*` to indicate it is open to all domains. If one of them contains the string `*`, then there can be exactly one.</li>
  3752. * <li><code>expose_header</code> - <code>string</code> - Optional - Enable the browser to read this header.</li>
  3753. * <li><code>id</code> - <code>string</code> - Optional - Unique identifier for the rule. The value cannot be longer than 255 characters.</li>
  3754. * <li><code>max_age</code> - <code>integer</code> - Optional - Alter the client's caching behavior for the pre-flight request.</li>
  3755. * </ul></li>
  3756. * </ul></li>
  3757. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3758. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3759. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3760. */
  3761. public function create_cors_config($bucket, $opt = null)
  3762. {
  3763. if (!$opt) $opt = array();
  3764. $opt['verb'] = 'PUT';
  3765. $opt['sub_resource'] = 'cors';
  3766. $opt['headers'] = array(
  3767. 'Content-Type' => 'application/xml'
  3768. );
  3769. $xml = simplexml_load_string($this->cors_config_xml, $this->parser_class);
  3770. if (isset($opt['cors_rule']) && is_array($opt['cors_rule']))
  3771. {
  3772. foreach ($opt['cors_rule'] as $rule_set)
  3773. {
  3774. // New rule node
  3775. $xrule = $xml->addChild('CORSRule');
  3776. // ID node
  3777. if (isset($rule_set['id']))
  3778. {
  3779. $xrule->addChild('ID', $rule_set['id']);
  3780. }
  3781. // ExposeHeader node
  3782. if (isset($rule_set['expose_header']))
  3783. {
  3784. $xrule->addChild('ExposeHeader', $rule_set['expose_header']);
  3785. }
  3786. // MaxAgeSeconds node
  3787. if (isset($rule_set['max_age']))
  3788. {
  3789. $xrule->addChild('MaxAgeSeconds', $rule_set['max_age']);
  3790. }
  3791. // AllowedHeader node
  3792. if (isset($rule_set['allowed_header']))
  3793. {
  3794. if (!is_array($rule_set['allowed_header']))
  3795. {
  3796. $rule_set['allowed_header'] = array($rule_set['allowed_header']);
  3797. }
  3798. foreach ($rule_set['allowed_header'] as $method)
  3799. {
  3800. $xrule->addChild('AllowedHeader', $method);
  3801. }
  3802. }
  3803. // AllowedMethod node
  3804. if (isset($rule_set['allowed_method']))
  3805. {
  3806. if (!is_array($rule_set['allowed_method']))
  3807. {
  3808. $rule_set['allowed_method'] = array($rule_set['allowed_method']);
  3809. }
  3810. foreach ($rule_set['allowed_method'] as $method)
  3811. {
  3812. $xrule->addChild('AllowedMethod', $method);
  3813. }
  3814. }
  3815. // AllowedOrigin node
  3816. if (isset($rule_set['allowed_origin']))
  3817. {
  3818. if (!is_array($rule_set['allowed_origin']))
  3819. {
  3820. $rule_set['allowed_origin'] = array($rule_set['allowed_origin']);
  3821. }
  3822. foreach ($rule_set['allowed_origin'] as $method)
  3823. {
  3824. $xrule->addChild('AllowedOrigin', $method);
  3825. }
  3826. }
  3827. }
  3828. }
  3829. $opt['body'] = $xml->asXML();
  3830. // Authenticate to S3
  3831. return $this->authenticate($bucket, $opt);
  3832. }
  3833. /**
  3834. * Retrieves the CORS configuration.
  3835. *
  3836. * @param string $bucket (Required) The name of the bucket to use.
  3837. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3838. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3839. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3840. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3841. */
  3842. public function get_cors_config($bucket, $opt = null)
  3843. {
  3844. if (!$opt) $opt = array();
  3845. $opt['verb'] = 'GET';
  3846. $opt['sub_resource'] = 'cors';
  3847. // Authenticate to S3
  3848. return $this->authenticate($bucket, $opt);
  3849. }
  3850. /**
  3851. * Deletes the CORS configuration.
  3852. *
  3853. * @param string $bucket (Required) The name of the bucket to use.
  3854. * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
  3855. * <li><code>curlopts</code> - <code>array</code> - Optional - A set of values to pass directly into <code>curl_setopt()</code>, where the key is a pre-defined <code>CURLOPT_*</code> constant.</li>
  3856. * <li><code>returnCurlHandle</code> - <code>boolean</code> - Optional - A private toggle specifying that the cURL handle be returned rather than actually completing the request. This toggle is useful for manually managed batch requests.</li></ul>
  3857. * @return CFResponse A <CFResponse> object containing a parsed HTTP response.
  3858. */
  3859. public function delete_cors_config($bucket, $opt = null)
  3860. {
  3861. if (!$opt) $opt = array();
  3862. $opt['verb'] = 'DELETE';
  3863. $opt['sub_resource'] = 'cors';
  3864. // Authenticate to S3
  3865. return $this->authenticate($bucket, $opt);
  3866. }
  3867. /*%******************************************************************************************%*/
  3868. // MISCELLANEOUS
  3869. /**
  3870. * Gets the canonical user ID and display name from the Amazon S3 server.
  3871. *
  3872. * @return array An associative array containing the `id` and `display_name` values.
  3873. */
  3874. public function get_canonical_user_id()
  3875. {
  3876. if ($this->use_batch_flow)
  3877. {
  3878. throw new S3_Exception(__FUNCTION__ . '() cannot be batch requested');
  3879. }
  3880. $id = $this->list_buckets();
  3881. return array(
  3882. 'id' => (string) $id->body->Owner->ID,
  3883. 'display_name' => (string) $id->body->Owner->DisplayName
  3884. );
  3885. }
  3886. /**
  3887. * Loads and registers the S3StreamWrapper class as a stream wrapper.
  3888. *
  3889. * @param string $protocol (Optional) The name of the protocol to register.
  3890. * @return boolean Whether or not the registration succeeded.
  3891. */
  3892. public function register_stream_wrapper($protocol = 's3')
  3893. {
  3894. require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'extensions'
  3895. . DIRECTORY_SEPARATOR . 's3streamwrapper.class.php';
  3896. return S3StreamWrapper::register($this, $protocol);
  3897. }
  3898. }