PageRenderTime 97ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/include/s3/s3.class.php

https://github.com/radicaldesigns/amp
PHP | 612 lines | 242 code | 187 blank | 183 comment | 74 complexity | e68c73e5b62a29b93f0da21fadd9de3a MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, BSD-3-Clause, LGPL-2.0, CC-BY-SA-3.0, AGPL-1.0
  1. <?php
  2. // Note that version HTTP_Request 1.3.0 has a BUG in it! Change line
  3. // 765 from:
  4. // (HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_postData) && empty($this->_postFiles))) {
  5. // to:
  6. // (HTTP_REQUEST_METHOD_POST == $this->_method && empty($this->_postData) && empty($this->_postFiles))) {
  7. // Without this change PUTs with non-empty content-type will fail!
  8. /**
  9. * Amazon S3 REST API Implementation
  10. *
  11. * This a generic PHP class that can hook-in to Amazon's S3 Simple Storage Service
  12. *
  13. * Contributions and/or donations are welcome.
  14. *
  15. * Author: Geoffrey P. Gaudreault
  16. * http://www.neurofuzzy.net
  17. *
  18. * This code is free, provided AS-IS with no warranty expressed or implied. Use at your own risk.
  19. * If you find errors or bugs in this code, please contact me at interested@zanpo.com
  20. * If you enhance this code in any way, please send me an update. Thank you!
  21. *
  22. * Version: 0.31a
  23. * Last Updated: 9/09/2006
  24. *
  25. * NOTE: ENTER YOUR API ID AND SECRET KEY BELOW!!!
  26. *
  27. */
  28. class s3 {
  29. // The API access point URL
  30. var $S3_URL = "http://s3.amazonaws.com/";
  31. // list of valid actions (validation not implemented yet)
  32. var $verbs = array("GET"=>1, "DELETE"=>1, "PUT"=>1);
  33. // set to true to echo debug info
  34. var $_debug = false;
  35. // -----------------------------------------
  36. // -----------------------------------------
  37. // your API key ID
  38. var $keyId = AMP_SYSTEM_FILE_S3_KEY;
  39. // your API Secret Key
  40. var $secretKey = AMP_SYSTEM_FILE_S3_KEY_SECRET;
  41. // -----------------------------------------
  42. // -----------------------------------------
  43. // default action
  44. var $_verb = "GET";
  45. // default ACL
  46. var $_acl = "public-read";
  47. // default content type
  48. var $_contentType = "image/jpeg";
  49. // default response content type
  50. var $_responseContentType = "text/xml";
  51. // bucket object name prefix
  52. var $prefix = "";
  53. // bucket list marker (useful for pagination)
  54. var $marker = "";
  55. // number of keys to retrieve in a list
  56. var $max_keys = "";
  57. // list delimiter
  58. var $delimiter = "";
  59. // your default bucket name
  60. var $bucketname = "radicaldesigns";
  61. // your current object name
  62. var $objectname = "temp";
  63. var $date_format = 'D, d M Y H:i:s T';
  64. /*
  65. * Constructor: Amazon S3 REST API implementation
  66. */
  67. function s3($options = NULL) {
  68. if ( !defined( 'DATE_RFC822')) {
  69. define('DATE_RFC822', 'D, d M Y H:i:s T');
  70. }
  71. $this->httpDate = gmdate( $this->date_format );
  72. $available_options = array("acl", "contentType");
  73. if (is_array($options)) {
  74. foreach ($options as $key => $value) {
  75. $this->debug_text("Option: $key");
  76. if (in_array($key, $available_options) ) {
  77. $this->debug_text("Valid Config options: $key");
  78. $property = '_'.$key;
  79. $this->$property = $value;
  80. $this->debug_text("Setting $property to $value");
  81. } else {
  82. $this->debug_text("ERROR: Config option: $key is not a valid option");
  83. }
  84. }
  85. }
  86. // REQUIRES PEAR PACKAGE
  87. // get with "pear install Crypt_HMAC"
  88. require_once 'Crypt/HMAC.php';
  89. $this->hasher = new Crypt_HMAC($this->secretKey, "sha1");
  90. // REQUIRES PEAR PACKAGE
  91. // get with "pear install --onlyreqdeps HTTP_Request"
  92. // NOTE FROM AMAZON:
  93. //
  94. // Note that version HTTP_Request 1.3.0 has a BUG in it! Change line
  95. // 765 from:
  96. // (HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_postData) && empty($this->_postFiles))) {
  97. // to:
  98. // (HTTP_REQUEST_METHOD_POST == $this->_method && empty($this->_postData) && empty($this->_postFiles))) {
  99. //
  100. // Without this change PUTs with non-empty content-type will fail!
  101. require_once 'HTTP/Request.php';
  102. }
  103. /*
  104. * Method: setBucketName
  105. * Sets the name of the default bucket
  106. */
  107. function setBucketName ($bucket) {
  108. $this->bucketname = $bucket;
  109. }
  110. /*
  111. * Method: getBucketName
  112. * Gets the name of the default bucket
  113. */
  114. function getBucketName () {
  115. return $this->bucketname;
  116. }
  117. /*
  118. * Method: setBucketName
  119. * Sets the name of the default bucket
  120. */
  121. function setObjectName ($object) {
  122. $this->objectname = $object;
  123. }
  124. /*
  125. * Method: getObjectName
  126. * Gets the name of the current object
  127. */
  128. function getObjectName () {
  129. return $this->objectname;
  130. }
  131. /*
  132. * Method: setContentType
  133. * Sets the content type of the object
  134. */
  135. function setContentType ($ct) {
  136. $this->_contentType = $ct;
  137. }
  138. /*
  139. * Method: getContentType
  140. * Gets the content type of the object
  141. */
  142. function getContentType () {
  143. return $this->_contentType;
  144. }
  145. /*
  146. * Method: getResponseContentType
  147. * Gets the content type of the response
  148. */
  149. function getResponseContentType () {
  150. return $this->_responseContentType;
  151. }
  152. /*
  153. * Method: setAcl
  154. * sets the acces control policy for the current object
  155. */
  156. function setAcl ($acl) {
  157. $this->_acl = $acl;
  158. }
  159. /*
  160. * Method: getAcl
  161. * gets the acces control policy for the current object
  162. */
  163. function getAcl () {
  164. return $this->_acl;
  165. }
  166. /*
  167. * Method: sendRequest
  168. * Sends the request to S3
  169. *
  170. * Parameters:
  171. * resource - the name of the resource to act upon
  172. * verb - the action to apply to the resource (GET, PUT, DELETE, HEAD)
  173. * objectdata - the source data (body) of the resource (only applies to objects)
  174. * acl - the access control policy for the resource
  175. * contentType - the contentType of the resource (only applies to objects)
  176. * metadata - any metadata you want to save in the header of the object
  177. */
  178. function sendRequest ($resource, $verb = NULL, $objectdata = NULL, $acl = NULL, $contentType = NULL, $metadata = NULL) {
  179. if ($verb == NULL) {
  180. $verb = $this->verb;
  181. }
  182. if ($acl == NULL) {
  183. $aclstring = "";
  184. } else {
  185. $aclstring = "x-amz-acl:$acl\n";
  186. }
  187. $contenttypestring = "";
  188. if ($contentType != NULL && ($verb == "PUT") && ($objectdata != NULL) && ($objectdata != "")) {
  189. $contenttypestring = "$contentType";
  190. }
  191. // update date / time on each request
  192. $this->httpDate = gmdate( $this->date_format );
  193. $httpDate = $this->httpDate;
  194. $paramstring = "";
  195. $delim = "?";
  196. if (strlen($this->prefix)) {
  197. $paramstring .= $delim."prefix=".urlencode($this->prefix);
  198. $delim = "&";
  199. }
  200. if (strlen($this->marker)) {
  201. $paramstring .= $delim."marker=".urlencode($this->marker);
  202. $delim = "&";
  203. }
  204. if (strlen($this->max_keys)) {
  205. $paramstring .= $delim."max-keys=".$this->max_keys;
  206. $delim = "&";
  207. }
  208. if (strlen($this->delimiter)) {
  209. $paramstring .= $delim."delimiter=".urlencode($this->delimiter);
  210. $delim = "&";
  211. }
  212. $this->debug_text("HTTP Request sent to: " . $this->S3_URL . $resource . $paramstring);
  213. $req = new HTTP_Request($this->S3_URL . $resource . $paramstring);
  214. $req->setMethod($verb);
  215. if (($objectdata != NULL) && ($objectdata != "")) {
  216. $contentMd5 = $this->hex2b64(md5($objectdata));
  217. $req->addHeader("CONTENT-MD5", $contentMd5);
  218. $this->debug_text("MD5 HASH OF DATA: " . $contentMd5);
  219. $contentmd5string = $contentMd5;
  220. } else {
  221. $contentmd5string = "";
  222. }
  223. if (strlen($contenttypestring)) {
  224. $this->debug_text("Setting content type to $contentType");
  225. $req->addHeader("CONTENT-TYPE", $contentType);
  226. }
  227. $req->addHeader("DATE", $httpDate);
  228. if (strlen($aclstring)) {
  229. $this->debug_text("Setting acl string to $acl");
  230. $req->addHeader("x-amz-acl", $acl);
  231. }
  232. $metadatastring = "";
  233. if (is_array($metadata)) {
  234. ksort($metadata);
  235. $this->debug_text("Metadata found.");
  236. foreach ($metadata as $key => $value) {
  237. $metadatastring .= "x-amz-meta-".$key.":".trim($value)."\n";
  238. $req->addHeader("x-amz-meta-".$key, trim($value));
  239. $this->debug_text("Setting x-amz-meta-$key to '$value'");
  240. }
  241. }
  242. if (($objectdata != NULL) && ($objectdata != "")) {
  243. $req->setBody($objectdata);
  244. }
  245. $stringToSign = "$verb\n$contentmd5string\n$contenttypestring\n$httpDate\n$aclstring$metadatastring/$resource";
  246. $this->debug_text("Signing String: $stringToSign");
  247. $signature = $this->hex2b64($this->hasher->hash($stringToSign));
  248. $req->addHeader("Authorization", "AWS " . $this->keyId . ":" . $signature);
  249. $req->sendRequest();
  250. $this->_responseContentType = $req->getResponseHeader("content-type");
  251. if (strlen($req->getResponseBody())) {
  252. $this->debug_text($req->getResponseBody());
  253. return $req->getResponseBody();
  254. } else {
  255. $this->debug_text($req->getResponseHeader());
  256. return $req->getResponseHeader();
  257. }
  258. }
  259. /*
  260. * Method: getBuckets
  261. * Returns a list of all buckets
  262. */
  263. function getBuckets () {
  264. return $this->sendRequest("","GET");
  265. }
  266. /*
  267. * Method: getBucket
  268. * Gets a list of all objects in the default bucket
  269. */
  270. function getBucket ($bucketname = NULL) {
  271. if ($bucketname == NULL) {
  272. return $this->sendRequest($this->bucketname,"GET");
  273. } else {
  274. return $this->sendRequest($bucketname,"GET");
  275. }
  276. }
  277. /*
  278. * Method: getObjects
  279. * Gets a list of all objects in the specified bucket
  280. *
  281. * Parameters:
  282. * prefix - (optional) Limits the response to keys which begin with the indicated prefix. You can use prefixes to separate a bucket into different sets of keys in a way similar to how a file system uses folders.
  283. * marker - (optional) Indicates where in the bucket to begin listing. The list will only include keys that occur lexicographically after marker. This is convenient for pagination: To get the next page of results use the last key of the current page as the marker.
  284. * max-keys - (optional) The maximum number of keys you'd like to see in the response body. The server may return fewer than this many keys, but will not return more.
  285. */
  286. function getObjects ($bucketname, $prefix = NULL, $marker = NULL, $max_keys = NULL, $delimiter = NULL) {
  287. if ($prefix != NULL) {
  288. $this->prefix = $prefix;
  289. } else {
  290. $this->prefix = "";
  291. }
  292. if ($marker != NULL) {
  293. $this->marker = $marker;
  294. } else {
  295. $this->marker = "";
  296. }
  297. if ($max_keys != NULL) {
  298. $this->max_keys = $max_keys;
  299. } else {
  300. $this->max_keys = "";
  301. }
  302. if ($delimiter != NULL) {
  303. $this->delimiter = $delimiter;
  304. } else {
  305. $this->delimiter = "";
  306. }
  307. if ($bucketname != NULL) {
  308. return $this->sendRequest($bucketname,"GET");
  309. } else {
  310. return false;
  311. }
  312. }
  313. /*
  314. * Method: getObjectInfo
  315. * Get header information about the object. The HEAD operation is used to retrieve information about a specific object,
  316. * without actually fetching the object itself
  317. *
  318. * Parameters:
  319. * objectname - The name of the object to get information about
  320. * bucketname - (optional) the name of the bucket containing the object. If none is supplied, the default bucket is used
  321. */
  322. function getObjectInfo ($objectname, $bucketname = NULL) {
  323. if ($bucketname == NULL) {
  324. $bucketname = $this->bucketname;
  325. }
  326. return $this->sendRequest($bucketname."/".$objectname,"HEAD");
  327. }
  328. /*
  329. * Method: getObject
  330. * Gets an object from S3
  331. *
  332. * Parameters:
  333. * objectname - the name of the object to get
  334. * bucketname - (optional) the name of the bucket containing the object. If none is supplied, the default bucket is used
  335. */
  336. function getObject ($objectname, $bucketname = NULL) {
  337. if ($bucketname == NULL) {
  338. $bucketname = $this->bucketname;
  339. }
  340. return $this->sendRequest($bucketname."/".$objectname,"GET");
  341. }
  342. /*
  343. * Method: putBucket
  344. * Creates a new bucket in S3
  345. *
  346. * Parameters:
  347. * bucketname - the name of the bucket. It must be unique. No other S3 users may have this bucket name
  348. */
  349. function putBucket ($bucketname) {
  350. return $this->sendRequest($bucketname,"PUT");
  351. }
  352. /*
  353. * Method: putObject
  354. * Puts an object into S3
  355. *
  356. * Parameters:
  357. * objectname - the name of the object to put
  358. * objectdata - the source data (body) of the resource (only applies to objects)
  359. * bucketname - (optional) the name of the bucket containing the object. If none is supplied, the default bucket is used
  360. * acl - the access control policy for the resource
  361. * contentType - the contentType of the resource (only applies to objects)
  362. * metadata - any metadata you want to save in the header of the object
  363. */
  364. function putObject ($objectname, $objectdata, $bucketname = NULL, $acl = NULL, $contentType = NULL, $metadata = NULL) {
  365. if ($bucketname == NULL) {
  366. $bucketname = $this->bucketname;
  367. }
  368. if ($acl == NULL || $acl == "") {
  369. $acl = $this->_acl;
  370. }
  371. if ($contentType == NULL || $contentType == "") {
  372. $contentType = $this->_contentType;
  373. }
  374. if ($objectdata != NULL) {
  375. return $this->sendRequest($bucketname."/".$objectname, "PUT", $objectdata, $acl, $contentType, $metadata);
  376. } else {
  377. return false;
  378. }
  379. }
  380. /*
  381. * Method: deleteBucket
  382. * Deletes bucket in S3. The bucket name will fall into the public domain.
  383. */
  384. function deleteBucket ($bucketname) {
  385. return $this->sendRequest($bucketname, "DELETE");
  386. }
  387. /*
  388. * Method: deleteObject
  389. * Deletes an object from S3
  390. *
  391. * Parameters:
  392. * objectname - the name of the object to delete
  393. * bucketname - (optional) the name of the bucket containing the object. If none is supplied, the default bucket is used
  394. */
  395. function deleteObject ($objectname, $bucketname = NULL) {
  396. if ($bucketname == NULL) {
  397. $bucketname = $this->bucketname;
  398. }
  399. return $this->sendRequest($bucketname."/".$objectname, "DELETE");
  400. }
  401. /*
  402. * Method: hex2b64
  403. * Utility function for constructing signatures
  404. */
  405. function hex2b64($str) {
  406. $raw = '';
  407. for ($i=0; $i < strlen($str); $i+=2) {
  408. $raw .= chr(hexdec(substr($str, $i, 2)));
  409. }
  410. return base64_encode($raw);
  411. }
  412. /*
  413. * Method: debug_text
  414. * Echoes debug information to the browser. Set this->debug to false for production use
  415. */
  416. function debug_text($text) {
  417. if ($this->_debug) {
  418. echo("<br>\n");
  419. print_r($text);
  420. echo("<br><br>\n\n");
  421. }
  422. return true;
  423. }
  424. }
  425. ?>