PageRenderTime 211ms CodeModel.GetById 84ms RepoModel.GetById 1ms app.codeStats 1ms

/administrator/components/com_akeeba/akeeba/plugins/utils/cloudfiles.php

https://bitbucket.org/kraymitchell/saiu
PHP | 2137 lines | 1226 code | 155 blank | 756 comment | 246 complexity | 27458181cb8938e511d402a6818d90e0 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-3.0, BSD-3-Clause, LGPL-2.1, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. Copyright (C) 2008 Rackspace US, Inc.
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in
  11. all copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18. SOFTWARE.
  19. Except as contained in this notice, the name of Rackspace US, Inc. shall not
  20. be used in advertising or otherwise to promote the sale, use or other dealings
  21. in this Software without prior written authorization from Rackspace US, Inc.
  22. *
  23. * <code>
  24. * $auth = new AEUtilCFAuthentication($username, $api_key);
  25. * $auth->authenticate();
  26. * $conn = new AEUtilCFConnection($auth);
  27. * $images = $conn->create_container("photos");
  28. * $bday = $images->create_object("first_birthday.jpg");
  29. * $bday->load_from_filename("/home/user/photos/birthdays/birthday1.jpg");
  30. * </code>
  31. *
  32. * @author Eric "EJ" Johnson <ej@racklabs.com>
  33. * @copyright Copyright (c) 2008, Rackspace US, Inc.
  34. * @package php-cloudfiles
  35. */
  36. class AEUtilCloudfiles {}
  37. define("DEFAULT_CF_API_VERSION", 1);
  38. define("MAX_CONTAINER_NAME_LEN", 256);
  39. define("MAX_OBJECT_NAME_LEN", 1024);
  40. define("MAX_OBJECT_SIZE", 5*1024*1024*1024+1); # bigger than S3! ;-)
  41. define("PHP_CF_VERSION", "1.7.0");
  42. define("USER_AGENT", sprintf("PHP-CloudFiles/%s", PHP_CF_VERSION));
  43. define("ACCOUNT_CONTAINER_COUNT", "X-Account-Container-Count");
  44. define("ACCOUNT_BYTES_USED", "X-Account-Bytes-Used");
  45. define("CONTAINER_OBJ_COUNT", "X-Container-Object-Count");
  46. define("CONTAINER_BYTES_USED", "X-Container-Bytes-Used");
  47. define("METADATA_HEADER", "X-Object-Meta-");
  48. define("CDN_URI", "X-CDN-URI");
  49. define("CDN_ENABLED", "X-CDN-Enabled");
  50. define("CDN_LOG_RETENTION", "X-Log-Retention");
  51. define("CDN_ACL_USER_AGENT", "X-User-Agent-ACL");
  52. define("CDN_ACL_REFERRER", "X-Referrer-ACL");
  53. define("CDN_TTL", "X-TTL");
  54. define("CDNM_URL", "X-CDN-Management-Url");
  55. define("STORAGE_URL", "X-Storage-Url");
  56. define("AUTH_TOKEN", "X-Auth-Token");
  57. define("AUTH_USER_HEADER", "X-Auth-User");
  58. define("AUTH_KEY_HEADER", "X-Auth-Key");
  59. define("AUTH_USER_HEADER_LEGACY", "X-Storage-User");
  60. define("AUTH_KEY_HEADER_LEGACY", "X-Storage-Pass");
  61. define("AUTH_TOKEN_LEGACY", "X-Storage-Token");
  62. class SyntaxException extends Exception { }
  63. class AuthenticationException extends Exception { }
  64. class InvalidResponseException extends Exception { }
  65. class NonEmptyContainerException extends Exception { }
  66. class NoSuchObjectException extends Exception { }
  67. class NoSuchContainerException extends Exception { }
  68. class NoSuchAccountException extends Exception { }
  69. class MisMatchedChecksumException extends Exception { }
  70. class IOException extends Exception { }
  71. class CDNNotEnabledException extends Exception { }
  72. class BadContentTypeException extends Exception { }
  73. class InvalidUTF8Exception extends Exception { }
  74. class ConnectionNotOpenException extends Exception { }
  75. /**
  76. * HTTP/cURL wrapper for Cloud Files
  77. *
  78. * This class should not be used directly. It's only purpose is to abstract
  79. * out the HTTP communication from the main API.
  80. *
  81. * @package php-cloudfiles-http
  82. */
  83. class AEUtilCfhttp
  84. {
  85. private $error_str;
  86. private $dbug;
  87. private $cabundle_path;
  88. private $api_version;
  89. # Authentication instance variables
  90. #
  91. private $storage_url;
  92. private $cdnm_url;
  93. private $auth_token;
  94. # Request/response variables
  95. #
  96. private $response_status;
  97. private $response_reason;
  98. private $connections;
  99. # Variables used for content/header callbacks
  100. #
  101. private $_user_read_progress_callback_func;
  102. private $_user_write_progress_callback_func;
  103. private $_write_callback_type;
  104. private $_text_list;
  105. private $_account_container_count;
  106. private $_account_bytes_used;
  107. private $_container_object_count;
  108. private $_container_bytes_used;
  109. private $_obj_etag;
  110. private $_obj_last_modified;
  111. private $_obj_content_type;
  112. private $_obj_content_length;
  113. private $_obj_metadata;
  114. private $_obj_write_resource;
  115. private $_obj_write_string;
  116. private $_cdn_enabled;
  117. private $_cdn_uri;
  118. private $_cdn_ttl;
  119. private $_cdn_log_retention;
  120. private $_cdn_acl_user_agent;
  121. private $_cdn_acl_referrer;
  122. private $isUKAccount = false;
  123. function __construct($api_version, $isUKAccount = false)
  124. {
  125. $this->dbug = False;
  126. $this->cabundle_path = NULL;
  127. $this->api_version = $api_version;
  128. $this->error_str = NULL;
  129. $this->storage_url = NULL;
  130. $this->cdnm_url = NULL;
  131. $this->auth_token = NULL;
  132. $this->response_status = NULL;
  133. $this->response_reason = NULL;
  134. # Curl connections array - since there is no way to "re-set" the
  135. # connection paramaters for a cURL handle, we keep an array of
  136. # the unique use-cases and funnel all of those same type
  137. # requests through the appropriate curl connection.
  138. #
  139. $this->connections = array(
  140. "GET_CALL" => NULL, # GET objects/containers/lists
  141. "PUT_OBJ" => NULL, # PUT object
  142. "HEAD" => NULL, # HEAD requests
  143. "PUT_CONT" => NULL, # PUT container
  144. "DEL_POST" => NULL, # DELETE containers/objects, POST objects
  145. );
  146. $this->_user_read_progress_callback_func = NULL;
  147. $this->_user_write_progress_callback_func = NULL;
  148. $this->_write_callback_type = NULL;
  149. $this->_text_list = array();
  150. $this->_return_list = NULL;
  151. $this->_account_container_count = 0;
  152. $this->_account_bytes_used = 0;
  153. $this->_container_object_count = 0;
  154. $this->_container_bytes_used = 0;
  155. $this->_obj_write_resource = NULL;
  156. $this->_obj_write_string = "";
  157. $this->_obj_etag = NULL;
  158. $this->_obj_last_modified = NULL;
  159. $this->_obj_content_type = NULL;
  160. $this->_obj_content_length = NULL;
  161. $this->_obj_metadata = array();
  162. $this->_cdn_enabled = NULL;
  163. $this->_cdn_uri = NULL;
  164. $this->_cdn_ttl = NULL;
  165. $this->_cdn_log_retention = NULL;
  166. $this->_cdn_acl_user_agent = NULL;
  167. $this->_cdn_acl_referrer = NULL;
  168. $this->isUKAccount = $isUKAccount;
  169. }
  170. # Uses separate cURL connection to authenticate
  171. #
  172. function authenticate($user, $pass, $acct=NULL, $host=NULL)
  173. {
  174. $path = array();
  175. if (isset($acct) || isset($host)) {
  176. $headers = array(
  177. sprintf("%s: %s", AUTH_USER_HEADER_LEGACY, $user),
  178. sprintf("%s: %s", AUTH_KEY_HEADER_LEGACY, $pass),
  179. );
  180. $path[] = $host;
  181. $path[] = rawurlencode(sprintf("v%d",$this->api_version));
  182. $path[] = rawurlencode($acct);
  183. } else {
  184. $headers = array(
  185. sprintf("%s: %s", AUTH_USER_HEADER, $user),
  186. sprintf("%s: %s", AUTH_KEY_HEADER, $pass),
  187. );
  188. if(!$this->isUKAccount) {
  189. $path[] = "https://auth.api.rackspacecloud.com";
  190. } else {
  191. $path[] = "https://lon.auth.api.rackspacecloud.com";
  192. }
  193. }
  194. $path[] = "v1.0";
  195. $url = implode("/", $path);
  196. $curl_ch = curl_init();
  197. @curl_setopt($curl_ch, CURLOPT_CAINFO, AKEEBA_CACERT_PEM);
  198. curl_setopt($curl_ch, CURLOPT_VERBOSE, $this->dbug);
  199. curl_setopt($curl_ch, CURLOPT_FOLLOWLOCATION, 1);
  200. curl_setopt($curl_ch, CURLOPT_MAXREDIRS, 4);
  201. curl_setopt($curl_ch, CURLOPT_HEADER, 0);
  202. curl_setopt($curl_ch, CURLOPT_HTTPHEADER, $headers);
  203. curl_setopt($curl_ch, CURLOPT_USERAGENT, USER_AGENT);
  204. curl_setopt($curl_ch, CURLOPT_RETURNTRANSFER, TRUE);
  205. curl_setopt($curl_ch, CURLOPT_HEADERFUNCTION,array(&$this,'_auth_hdr_cb'));
  206. curl_setopt($curl_ch, CURLOPT_SSL_VERIFYPEER, (stristr(PHP_OS, 'WIN') ? false : true));
  207. curl_setopt($curl_ch, CURLOPT_URL, $url);
  208. curl_exec($curl_ch);
  209. curl_close($curl_ch);
  210. return array($this->response_status, $this->response_reason,
  211. $this->storage_url, $this->cdnm_url, $this->auth_token);
  212. }
  213. # HEAD /v1/Account
  214. #
  215. function head_account()
  216. {
  217. $conn_type = "HEAD";
  218. $url_path = $this->_make_path();
  219. $return_code = $this->_send_request($conn_type,$url_path);
  220. if (!$return_code) {
  221. $this->error_str .= ": Failed to obtain valid HTTP response.";
  222. array(0,$this->error_str,0,0);
  223. }
  224. if ($return_code == 404) {
  225. return array($return_code,"Account not found.",0,0);
  226. }
  227. if ($return_code == 204) {
  228. return array($return_code,$this->response_reason,
  229. $this->_account_container_count, $this->_account_bytes_used);
  230. }
  231. return array($return_code,$this->response_reason,0,0);
  232. }
  233. # HEAD /v1/Account/Container
  234. #
  235. function head_container($container_name)
  236. {
  237. if ($container_name == "") {
  238. $this->error_str = "Container name not set.";
  239. return False;
  240. }
  241. if ($container_name != "0" and !isset($container_name)) {
  242. $this->error_str = "Container name not set.";
  243. return False;
  244. }
  245. $conn_type = "HEAD";
  246. $url_path = $this->_make_path("STORAGE", $container_name);
  247. $return_code = $this->_send_request($conn_type,$url_path);
  248. if (!$return_code) {
  249. $this->error_str .= ": Failed to obtain valid HTTP response.";
  250. array(0,$this->error_str,0,0);
  251. }
  252. if ($return_code == 404) {
  253. return array($return_code,"Container not found.",0,0);
  254. }
  255. if ($return_code == 204 or 200) {
  256. return array($return_code,$this->response_reason,
  257. $this->_container_object_count, $this->_container_bytes_used);
  258. }
  259. return array($return_code,$this->response_reason,0,0);
  260. }
  261. # GET /v1/Account/Container/Object
  262. #
  263. function get_object_to_stream(&$obj, &$resource=NULL, $hdrs=array())
  264. {
  265. if (!is_object($obj) || get_class($obj) != "AEUtilCFObject") {
  266. throw new SyntaxException(
  267. "Method argument is not a valid AEUtilCFObject.");
  268. }
  269. if (!is_resource($resource)) {
  270. throw new SyntaxException(
  271. "Resource argument not a valid PHP resource.");
  272. }
  273. $conn_type = "GET_CALL";
  274. $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name);
  275. $this->_obj_write_resource = $resource;
  276. $this->_write_callback_type = "OBJECT_STREAM";
  277. $return_code = $this->_send_request($conn_type,$url_path,$hdrs);
  278. if (!$return_code) {
  279. $this->error_str .= ": Failed to obtain valid HTTP response.";
  280. return array($return_code,$this->error_str);
  281. }
  282. if ($return_code == 404) {
  283. $this->error_str = "Object not found.";
  284. return array($return_code,$this->error_str);
  285. }
  286. if (($return_code < 200) || ($return_code > 299
  287. && $return_code != 412 && $return_code != 304)) {
  288. $this->error_str = "Unexpected HTTP return code: $return_code";
  289. return array($return_code,$this->error_str);
  290. }
  291. return array($return_code,$this->response_reason);
  292. }
  293. # PUT /v1/Account/Container/Object
  294. #
  295. function put_object(&$obj, &$fp)
  296. {
  297. if (!is_object($obj) || get_class($obj) != "AEUtilCFObject") {
  298. throw new SyntaxException(
  299. "Method argument is not a valid AEUtilCFObject.");
  300. }
  301. if (!is_resource($fp)) {
  302. throw new SyntaxException(
  303. "File pointer argument is not a valid resource.");
  304. }
  305. $conn_type = "PUT_OBJ";
  306. $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name);
  307. $hdrs = $this->_metadata_headers($obj);
  308. $etag = $obj->getETag();
  309. if (isset($etag)) {
  310. $hdrs[] = "ETag: " . $etag;
  311. }
  312. if (!$obj->content_type) {
  313. $hdrs[] = "Content-Type: application/octet-stream";
  314. } else {
  315. $hdrs[] = "Content-Type: " . $obj->content_type;
  316. }
  317. $this->_init($conn_type);
  318. curl_setopt($this->connections[$conn_type],
  319. CURLOPT_INFILE, $fp);
  320. if (!$obj->content_length) {
  321. # We don''t know the Content-Length, so assumed "chunked" PUT
  322. #
  323. curl_setopt($this->connections[$conn_type], CURLOPT_UPLOAD, True);
  324. $hdrs[] = 'Transfer-Encoding: chunked';
  325. } else {
  326. # We know the Content-Length, so use regular transfer
  327. #
  328. curl_setopt($this->connections[$conn_type],
  329. CURLOPT_INFILESIZE, $obj->content_length);
  330. }
  331. $return_code = $this->_send_request($conn_type,$url_path,$hdrs);
  332. if (!$return_code) {
  333. $this->error_str .= ": Failed to obtain valid HTTP response.";
  334. return array(0,$this->error_str,NULL);
  335. }
  336. if ($return_code == 412) {
  337. $this->error_str = "Missing Content-Type header";
  338. return array($return_code,$this->error_str,NULL);
  339. }
  340. if ($return_code == 422) {
  341. $this->error_str = "Derived and computed checksums do not match.";
  342. return array($return_code,$this->error_str,NULL);
  343. }
  344. if ($return_code != 201) {
  345. $this->error_str = "Unexpected HTTP return code: $return_code";
  346. return array($return_code,$this->error_str,NULL);
  347. }
  348. return array($return_code,$this->response_reason,$this->_obj_etag);
  349. }
  350. # HEAD /v1/Account/Container/Object
  351. #
  352. function head_object(&$obj)
  353. {
  354. if (!is_object($obj) || get_class($obj) != "AEUtilCFObject") {
  355. throw new SyntaxException(
  356. "Method argument is not a valid AEUtilCFObject.");
  357. }
  358. $conn_type = "HEAD";
  359. $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name);
  360. $return_code = $this->_send_request($conn_type,$url_path);
  361. if (!$return_code) {
  362. $this->error_str .= ": Failed to obtain valid HTTP response.";
  363. return array(0, $this->error_str." ".$this->response_reason,
  364. NULL, NULL, NULL, NULL, array());
  365. }
  366. if ($return_code == 404) {
  367. return array($return_code, $this->response_reason,
  368. NULL, NULL, NULL, NULL, array());
  369. }
  370. if ($return_code == 204 or 200) {
  371. return array($return_code,$this->response_reason,
  372. $this->_obj_etag,
  373. $this->_obj_last_modified,
  374. $this->_obj_content_type,
  375. $this->_obj_content_length,
  376. $this->_obj_metadata);
  377. }
  378. $this->error_str = "Unexpected HTTP return code: $return_code";
  379. return array($return_code, $this->error_str." ".$this->response_reason,
  380. NULL, NULL, NULL, NULL, array());
  381. }
  382. # GET /v1/Account/Container?format=json
  383. #
  384. function get_objects($cname,$limit=0,$marker=NULL,$prefix=NULL,$path=NULL)
  385. {
  386. if (!$cname) {
  387. $this->error_str = "Container name not set.";
  388. return array(0, $this->error_str, array());
  389. }
  390. $url_path = $this->_make_path("STORAGE", $cname);
  391. $limit = intval($limit);
  392. $params = array();
  393. $params[] = "format=json";
  394. if ($limit > 0) {
  395. $params[] = "limit=$limit";
  396. }
  397. if ($marker) {
  398. $params[] = "marker=".rawurlencode($marker);
  399. }
  400. if ($prefix) {
  401. $params[] = "prefix=".rawurlencode($prefix);
  402. }
  403. if ($path) {
  404. $params[] = "path=".rawurlencode($path);
  405. }
  406. if (!empty($params)) {
  407. $url_path .= "?" . implode("&", $params);
  408. }
  409. $conn_type = "GET_CALL";
  410. $this->_write_callback_type = "OBJECT_STRING";
  411. $return_code = $this->_send_request($conn_type,$url_path);
  412. if (!$return_code) {
  413. $this->error_str .= ": Failed to obtain valid HTTP response.";
  414. return array(0,$this->error_str,array());
  415. }
  416. if ($return_code == 204) {
  417. $this->error_str = "Container has no Objects.";
  418. return array($return_code,$this->error_str,array());
  419. }
  420. if ($return_code == 404) {
  421. $this->error_str = "Container has no Objects.";
  422. return array($return_code,$this->error_str,array());
  423. }
  424. if ($return_code == 200) {
  425. $json_body = json_decode($this->_obj_write_string, True);
  426. return array($return_code,$this->response_reason, $json_body);
  427. }
  428. $this->error_str = "Unexpected HTTP response code: $return_code";
  429. return array(0,$this->error_str,array());
  430. }
  431. function get_error()
  432. {
  433. return $this->error_str;
  434. }
  435. function setDebug($bool)
  436. {
  437. $this->dbug = $bool;
  438. foreach ($this->connections as $k => $v) {
  439. if (!is_null($v)) {
  440. curl_setopt($this->connections[$k], CURLOPT_VERBOSE, $this->dbug);
  441. }
  442. }
  443. }
  444. function getStorageUrl()
  445. {
  446. return $this->storage_url;
  447. }
  448. function getAuthToken()
  449. {
  450. return $this->auth_token;
  451. }
  452. function setCFAuth($cfs_auth, $servicenet=False)
  453. {
  454. if ($servicenet) {
  455. $this->storage_url = "https://snet-" . substr($cfs_auth->storage_url, 8);
  456. } else {
  457. $this->storage_url = $cfs_auth->storage_url;
  458. }
  459. $this->auth_token = $cfs_auth->auth_token;
  460. $this->cdnm_url = $cfs_auth->cdnm_url;
  461. }
  462. function setReadProgressFunc($func_name)
  463. {
  464. $this->_user_read_progress_callback_func = $func_name;
  465. }
  466. function setWriteProgressFunc($func_name)
  467. {
  468. $this->_user_write_progress_callback_func = $func_name;
  469. }
  470. function getCDNMUrl()
  471. {
  472. return $this->cdnm_url;
  473. }
  474. # DELETE /v1/Account/Container/Object
  475. #
  476. function delete_object($container_name, $object_name)
  477. {
  478. if ($container_name == "") {
  479. $this->error_str = "Container name not set.";
  480. return 0;
  481. }
  482. if ($container_name != "0" and !isset($container_name)) {
  483. $this->error_str = "Container name not set.";
  484. return 0;
  485. }
  486. if (!$object_name) {
  487. $this->error_str = "Object name not set.";
  488. return 0;
  489. }
  490. $url_path = $this->_make_path("STORAGE", $container_name,$object_name);
  491. $return_code = $this->_send_request("DEL_POST",$url_path,NULL,"DELETE");
  492. switch ($return_code) {
  493. case 204:
  494. break;
  495. case 0:
  496. $this->error_str .= ": Failed to obtain valid HTTP response.";
  497. $return_code = 0;
  498. break;
  499. case 404:
  500. $this->error_str = "Specified container did not exist to delete.";
  501. break;
  502. default:
  503. $this->error_str = "Unexpected HTTP return code: $return_code.";
  504. }
  505. return $return_code;
  506. }
  507. private function _header_cb($ch, $header)
  508. {
  509. preg_match("/^HTTP\/1\.[01] (\d{3}) (.*)/", $header, $matches);
  510. if (isset($matches[1])) {
  511. $this->response_status = $matches[1];
  512. }
  513. if (isset($matches[2])) {
  514. $this->response_reason = $matches[2];
  515. }
  516. if (stripos($header, ACCOUNT_CONTAINER_COUNT) === 0) {
  517. $this->_account_container_count = (float) trim(substr($header,
  518. strlen(ACCOUNT_CONTAINER_COUNT)+1))+0;
  519. return strlen($header);
  520. }
  521. if (stripos($header, ACCOUNT_BYTES_USED) === 0) {
  522. $this->_account_bytes_used = (float) trim(substr($header,
  523. strlen(ACCOUNT_BYTES_USED)+1))+0;
  524. return strlen($header);
  525. }
  526. if (stripos($header, CONTAINER_OBJ_COUNT) === 0) {
  527. $this->_container_object_count = (float) trim(substr($header,
  528. strlen(CONTAINER_OBJ_COUNT)+1))+0;
  529. return strlen($header);
  530. }
  531. if (stripos($header, CONTAINER_BYTES_USED) === 0) {
  532. $this->_container_bytes_used = (float) trim(substr($header,
  533. strlen(CONTAINER_BYTES_USED)+1))+0;
  534. return strlen($header);
  535. }
  536. if (stripos($header, METADATA_HEADER) === 0) {
  537. # $header => X-Object-Meta-Foo: bar baz
  538. $temp = substr($header, strlen(METADATA_HEADER));
  539. # $temp => Foo: bar baz
  540. $parts = explode(":", $temp);
  541. # $parts[0] => Foo
  542. $val = substr(strstr($temp, ":"), 1);
  543. # $val => bar baz
  544. $this->_obj_metadata[$parts[0]] = trim($val);
  545. return strlen($header);
  546. }
  547. if (stripos($header, "ETag:") === 0) {
  548. # $header => ETag: abc123def456...
  549. $val = substr(strstr($header, ":"), 1);
  550. # $val => abc123def456...
  551. $this->_obj_etag = trim($val);
  552. return strlen($header);
  553. }
  554. if (stripos($header, "Last-Modified:") === 0) {
  555. $val = substr(strstr($header, ":"), 1);
  556. $this->_obj_last_modified = trim($val);
  557. return strlen($header);
  558. }
  559. if (stripos($header, "Content-Type:") === 0) {
  560. $val = substr(strstr($header, ":"), 1);
  561. $this->_obj_content_type = trim($val);
  562. return strlen($header);
  563. }
  564. if (stripos($header, "Content-Length:") === 0) {
  565. $val = substr(strstr($header, ":"), 1);
  566. $this->_obj_content_length = (float) trim($val)+0;
  567. return strlen($header);
  568. }
  569. return strlen($header);
  570. }
  571. private function _read_cb($ch, $fd, $length)
  572. {
  573. $data = fread($fd, $length);
  574. $len = strlen($data);
  575. if (isset($this->_user_write_progress_callback_func)) {
  576. call_user_func($this->_user_write_progress_callback_func, $len);
  577. }
  578. return $data;
  579. }
  580. private function _write_cb($ch, $data)
  581. {
  582. $dlen = strlen($data);
  583. switch ($this->_write_callback_type) {
  584. case "TEXT_LIST":
  585. $this->_return_list = $this->_return_list . $data;
  586. //= explode("\n",$data); # keep tab,space
  587. //his->_text_list[] = rtrim($data,"\n\r\x0B"); # keep tab,space
  588. break;
  589. case "OBJECT_STREAM":
  590. fwrite($this->_obj_write_resource, $data, $dlen);
  591. break;
  592. case "OBJECT_STRING":
  593. $this->_obj_write_string .= $data;
  594. break;
  595. }
  596. if (isset($this->_user_read_progress_callback_func)) {
  597. call_user_func($this->_user_read_progress_callback_func, $dlen);
  598. }
  599. return $dlen;
  600. }
  601. private function _auth_hdr_cb($ch, $header)
  602. {
  603. preg_match("/^HTTP\/1\.[01] (\d{3}) (.*)/", $header, $matches);
  604. if (isset($matches[1])) {
  605. $this->response_status = $matches[1];
  606. }
  607. if (isset($matches[2])) {
  608. $this->response_reason = $matches[2];
  609. }
  610. if (stripos($header, STORAGE_URL) === 0) {
  611. $this->storage_url = trim(substr($header, strlen(STORAGE_URL)+1));
  612. }
  613. if (stripos($header, AUTH_TOKEN) === 0) {
  614. $this->auth_token = trim(substr($header, strlen(AUTH_TOKEN)+1));
  615. }
  616. if (stripos($header, AUTH_TOKEN_LEGACY) === 0) {
  617. $this->auth_token = trim(substr($header,strlen(AUTH_TOKEN_LEGACY)+1));
  618. }
  619. return strlen($header);
  620. }
  621. private function _make_headers($hdrs=NULL)
  622. {
  623. $new_headers = array();
  624. $has_stoken = False;
  625. $has_uagent = False;
  626. if (is_array($hdrs)) {
  627. foreach ($hdrs as $h => $v) {
  628. if (is_int($h)) {
  629. $parts = explode(":", $v);
  630. $header = $parts[0];
  631. $value = trim(substr(strstr($v, ":"), 1));
  632. } else {
  633. $header = $h;
  634. $value = trim($v);
  635. }
  636. if (stripos($header, AUTH_TOKEN) === 0) {
  637. $has_stoken = True;
  638. }
  639. if (stripos($header, "user-agent") === 0) {
  640. $has_uagent = True;
  641. }
  642. $new_headers[] = $header . ": " . $value;
  643. }
  644. }
  645. if (!$has_stoken) {
  646. $new_headers[] = AUTH_TOKEN . ": " . $this->auth_token;
  647. }
  648. if (!$has_uagent) {
  649. $new_headers[] = "User-Agent: " . USER_AGENT;
  650. }
  651. return $new_headers;
  652. }
  653. private function _init($conn_type, $force_new=False)
  654. {
  655. if (!array_key_exists($conn_type, $this->connections)) {
  656. $this->error_str = "Invalid CURL_XXX connection type";
  657. return False;
  658. }
  659. if (is_null($this->connections[$conn_type]) || $force_new) {
  660. $ch = curl_init();
  661. @curl_setopt($ch, CURLOPT_CAINFO, AKEEBA_CACERT_PEM);
  662. } else {
  663. return;
  664. }
  665. if ($this->dbug) { curl_setopt($ch, CURLOPT_VERBOSE, 1); }
  666. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (stristr(PHP_OS, 'WIN') ? false : true));
  667. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  668. curl_setopt($ch, CURLOPT_MAXREDIRS, 4);
  669. curl_setopt($ch, CURLOPT_HEADER, 0);
  670. curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this, '_header_cb'));
  671. if ($conn_type == "GET_CALL") {
  672. curl_setopt($ch, CURLOPT_WRITEFUNCTION, array(&$this, '_write_cb'));
  673. }
  674. if ($conn_type == "PUT_OBJ") {
  675. curl_setopt($ch, CURLOPT_PUT, 1);
  676. curl_setopt($ch, CURLOPT_READFUNCTION, array(&$this, '_read_cb'));
  677. }
  678. if ($conn_type == "HEAD") {
  679. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "HEAD");
  680. curl_setopt($ch, CURLOPT_NOBODY, 1);
  681. }
  682. if ($conn_type == "PUT_CONT") {
  683. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
  684. curl_setopt($ch, CURLOPT_INFILESIZE, 0);
  685. curl_setopt($ch, CURLOPT_NOBODY, 1);
  686. }
  687. if ($conn_type == "DEL_POST") {
  688. curl_setopt($ch, CURLOPT_NOBODY, 1);
  689. }
  690. $this->connections[$conn_type] = $ch;
  691. return;
  692. }
  693. private function _reset_callback_vars()
  694. {
  695. $this->_text_list = array();
  696. $this->_return_list = NULL;
  697. $this->_account_container_count = 0;
  698. $this->_account_bytes_used = 0;
  699. $this->_container_object_count = 0;
  700. $this->_container_bytes_used = 0;
  701. $this->_obj_etag = NULL;
  702. $this->_obj_last_modified = NULL;
  703. $this->_obj_content_type = NULL;
  704. $this->_obj_content_length = NULL;
  705. $this->_obj_metadata = array();
  706. $this->_obj_write_string = "";
  707. $this->_cdn_enabled = NULL;
  708. $this->_cdn_uri = NULL;
  709. $this->_cdn_ttl = NULL;
  710. $this->response_status = 0;
  711. $this->response_reason = "";
  712. }
  713. private function _make_path($t="STORAGE",$c=NULL,$o=NULL)
  714. {
  715. $path = array();
  716. switch ($t) {
  717. case "STORAGE":
  718. $path[] = $this->storage_url; break;
  719. }
  720. if ($c == "0")
  721. $path[] = rawurlencode($c);
  722. if ($c) {
  723. $path[] = rawurlencode($c);
  724. }
  725. if ($o) {
  726. # mimic Python''s urllib.quote() feature of a "safe" '/' character
  727. #
  728. $path[] = str_replace("%2F","/",rawurlencode($o));
  729. }
  730. return implode("/",$path);
  731. }
  732. private function _metadata_headers(&$obj)
  733. {
  734. $hdrs = array();
  735. foreach ($obj->metadata as $k => $v) {
  736. if (strpos($k,":") !== False) {
  737. throw new SyntaxException(
  738. "Metadata keys cannot contain a ':' character.");
  739. }
  740. $k = trim($k);
  741. $key = sprintf("%s%s", METADATA_HEADER, $k);
  742. if (!array_key_exists($key, $hdrs)) {
  743. if (strlen($k) > 128 || strlen($v) > 256) {
  744. $this->error_str = "Metadata key or value exceeds ";
  745. $this->error_str .= "maximum length: ($k: $v)";
  746. return 0;
  747. }
  748. $hdrs[] = sprintf("%s%s: %s", METADATA_HEADER, $k, trim($v));
  749. }
  750. }
  751. return $hdrs;
  752. }
  753. private function _send_request($conn_type, $url_path, $hdrs=NULL, $method="GET")
  754. {
  755. $this->_init($conn_type);
  756. $this->_reset_callback_vars();
  757. $headers = $this->_make_headers($hdrs);
  758. if (gettype($this->connections[$conn_type]) == "unknown type")
  759. throw new ConnectionNotOpenException (
  760. "Connection is not open."
  761. );
  762. switch ($method) {
  763. case "DELETE":
  764. curl_setopt($this->connections[$conn_type],
  765. CURLOPT_CUSTOMREQUEST, "DELETE");
  766. break;
  767. case "POST":
  768. curl_setopt($this->connections[$conn_type],
  769. CURLOPT_CUSTOMREQUEST, "POST");
  770. default:
  771. break;
  772. }
  773. curl_setopt($this->connections[$conn_type],
  774. CURLOPT_HTTPHEADER, $headers);
  775. curl_setopt($this->connections[$conn_type],
  776. CURLOPT_URL, $url_path);
  777. if (!curl_exec($this->connections[$conn_type])) {
  778. $this->error_str = "(curl error: "
  779. . curl_errno($this->connections[$conn_type]) . ") ";
  780. $this->error_str .= curl_error($this->connections[$conn_type]);
  781. return False;
  782. }
  783. return curl_getinfo($this->connections[$conn_type], CURLINFO_HTTP_CODE);
  784. }
  785. function close()
  786. {
  787. foreach ($this->connections as $cnx) {
  788. if (isset($cnx)) {
  789. curl_close($cnx);
  790. $this->connections[$cnx] = NULL;
  791. }
  792. }
  793. }
  794. private function create_array()
  795. {
  796. $this->_text_list = explode("\n",rtrim($this->_return_list,"\n\x0B"));
  797. return True;
  798. }
  799. }
  800. /**
  801. * Class for handling Cloud Files Authentication, call it's {@link authenticate()}
  802. * method to obtain authorized service urls and an authentication token.
  803. *
  804. * Example:
  805. * <code>
  806. * # Create the authentication instance
  807. * #
  808. * $auth = new AEUtilCFAuthentication("username", "api_key");
  809. * # Perform authentication request
  810. * #
  811. * $auth->authenticate();
  812. * </code>
  813. *
  814. * @package php-cloudfiles
  815. */
  816. class AEUtilCFAuthentication
  817. {
  818. public $dbug;
  819. public $username;
  820. public $api_key;
  821. public $auth_host;
  822. public $account;
  823. public $isUKAccount = false;
  824. /**
  825. * Instance variables that are set after successful authentication
  826. */
  827. public $storage_url;
  828. public $cdnm_url;
  829. public $auth_token;
  830. /**
  831. * Class constructor (PHP 5 syntax)
  832. *
  833. * @param string $username Mosso username
  834. * @param string $api_key Mosso API Access Key
  835. * @param string $account <b>Deprecated</b> <i>Account name</i>
  836. * @param string $auth_host <b>Deprecated</b> <i>Authentication service URI</i>
  837. */
  838. function __construct($username=NULL, $api_key=NULL, $account=NULL, $auth_host=NULL, $isUKAccount = false)
  839. {
  840. $this->dbug = False;
  841. $this->username = $username;
  842. $this->api_key = $api_key;
  843. $this->account_name = $account;
  844. $this->auth_host = $auth_host;
  845. $this->storage_url = NULL;
  846. $this->cdnm_url = NULL;
  847. $this->auth_token = NULL;
  848. $this->isUKAccount = $isUKAccount;
  849. $this->cfs_http = new AEUtilCfhttp(DEFAULT_CF_API_VERSION, $this->isUKAccount);
  850. }
  851. /**
  852. * Attempt to validate Username/API Access Key
  853. *
  854. * Attempts to validate credentials with the authentication service. It
  855. * either returns <kbd>True</kbd> or throws an Exception. Accepts a single
  856. * (optional) argument for the storage system API version.
  857. *
  858. * Example:
  859. * <code>
  860. * # Create the authentication instance
  861. * #
  862. * $auth = new AEUtilCFAuthentication("username", "api_key");
  863. *
  864. * # Perform authentication request
  865. * #
  866. * $auth->authenticate();
  867. * </code>
  868. *
  869. * @param string $version API version for Auth service (optional)
  870. * @return boolean <kbd>True</kbd> if successfully authenticated
  871. * @throws AuthenticationException invalid credentials
  872. * @throws InvalidResponseException invalid response
  873. */
  874. function authenticate($version=DEFAULT_CF_API_VERSION)
  875. {
  876. list($status,$reason,$surl,$curl,$atoken) =
  877. $this->cfs_http->authenticate($this->username, $this->api_key,
  878. $this->account_name, $this->auth_host);
  879. if ($status == 401) {
  880. throw new AuthenticationException("Invalid username or access key.");
  881. }
  882. if ($status != 204) {
  883. throw new InvalidResponseException(
  884. "Unexpected response (".$status."): ".$reason);
  885. }
  886. if (!($surl || $curl) || !$atoken) {
  887. throw new InvalidResponseException(
  888. "Expected headers missing from auth service.");
  889. }
  890. $this->storage_url = $surl;
  891. $this->cdnm_url = $curl;
  892. $this->auth_token = $atoken;
  893. return True;
  894. }
  895. /**
  896. * Use Cached Token and Storage URL's rather then grabbing from the Auth System
  897. *
  898. * Example:
  899. * <code>
  900. * #Create an Auth instance
  901. * $auth = new AEUtilCFAuthentication();
  902. * #Pass Cached URL's and Token as Args
  903. * $auth->load_cached_credentials("auth_token", "storage_url", "cdn_management_url");
  904. * </code>
  905. *
  906. * @param string $auth_token A Cloud Files Auth Token (Required)
  907. * @param string $storage_url The Cloud Files Storage URL (Required)
  908. * @param string $cdnm_url CDN Management URL (Required)
  909. * @return boolean <kbd>True</kbd> if successful
  910. * @throws SyntaxException If any of the Required Arguments are missing
  911. */
  912. function load_cached_credentials($auth_token, $storage_url, $cdnm_url)
  913. {
  914. if(!$storage_url || !$cdnm_url)
  915. {
  916. throw new SyntaxException("Missing Required Interface URL's!");
  917. return False;
  918. }
  919. if(!$auth_token)
  920. {
  921. throw new SyntaxException("Missing Auth Token!");
  922. return False;
  923. }
  924. $this->storage_url = $storage_url;
  925. $this->cdnm_url = $cdnm_url;
  926. $this->auth_token = $auth_token;
  927. return True;
  928. }
  929. /**
  930. * Grab Cloud Files info to be Cached for later use with the load_cached_credentials method.
  931. *
  932. * Example:
  933. * <code>
  934. * #Create an Auth instance
  935. * $auth = new AEUtilCFAuthentication("UserName","API_Key");
  936. * $auth->authenticate();
  937. * $array = $auth->export_credentials();
  938. * </code>
  939. *
  940. * @return array of url's and an auth token.
  941. */
  942. function export_credentials()
  943. {
  944. $arr = array();
  945. $arr['storage_url'] = $this->storage_url;
  946. $arr['cdnm_url'] = $this->cdnm_url;
  947. $arr['auth_token'] = $this->auth_token;
  948. return $arr;
  949. }
  950. /**
  951. * Make sure the AEUtilCFAuthentication instance has authenticated.
  952. *
  953. * Ensures that the instance variables necessary to communicate with
  954. * Cloud Files have been set from a previous authenticate() call.
  955. *
  956. * @return boolean <kbd>True</kbd> if successfully authenticated
  957. */
  958. function authenticated()
  959. {
  960. if (!($this->storage_url || $this->cdnm_url) || !$this->auth_token) {
  961. return False;
  962. }
  963. return True;
  964. }
  965. /**
  966. * Toggle debugging - set cURL verbose flag
  967. */
  968. function setDebug($bool)
  969. {
  970. $this->dbug = $bool;
  971. $this->cfs_http->setDebug($bool);
  972. }
  973. }
  974. /**
  975. * Class for establishing connections to the Cloud Files storage system.
  976. * Connection instances are used to communicate with the storage system at
  977. * the account level; listing and deleting Containers and returning Container
  978. * instances.
  979. *
  980. * Example:
  981. * <code>
  982. * # Create the authentication instance
  983. * #
  984. * $auth = new AEUtilCFAuthentication("username", "api_key");
  985. *
  986. * # Perform authentication request
  987. * #
  988. * $auth->authenticate();
  989. *
  990. * # Create a connection to the storage/cdn system(s) and pass in the
  991. * # validated AEUtilCFAuthentication instance.
  992. * #
  993. * $conn = new AEUtilCFConnection($auth);
  994. * </code>
  995. *
  996. * @package php-cloudfiles
  997. */
  998. class AEUtilCFConnection
  999. {
  1000. public $dbug;
  1001. public $cfs_http;
  1002. public $cfs_auth;
  1003. /**
  1004. * Pass in a previously authenticated AEUtilCFAuthentication instance.
  1005. *
  1006. * Example:
  1007. * <code>
  1008. * # Create the authentication instance
  1009. * #
  1010. * $auth = new AEUtilCFAuthentication("username", "api_key");
  1011. *
  1012. * # Perform authentication request
  1013. * #
  1014. * $auth->authenticate();
  1015. *
  1016. * # Create a connection to the storage/cdn system(s) and pass in the
  1017. * # validated AEUtilCFAuthentication instance.
  1018. * #
  1019. * $conn = new AEUtilCFConnection($auth);
  1020. *
  1021. * # If you are connecting via Rackspace servers and have access
  1022. * # to the servicenet network you can set the $servicenet to True
  1023. * # like this.
  1024. *
  1025. * $conn = new AEUtilCFConnection($auth, $servicenet=True);
  1026. *
  1027. * </code>
  1028. *
  1029. * If the environement variable RACKSPACE_SERVICENET is defined it will
  1030. * force to connect via the servicenet.
  1031. *
  1032. * @param obj $cfs_auth previously authenticated AEUtilCFAuthentication instance
  1033. * @param boolean $servicenet enable/disable access via Rackspace servicenet.
  1034. * @throws AuthenticationException not authenticated
  1035. */
  1036. function __construct($cfs_auth, $servicenet=False)
  1037. {
  1038. if (isset($_ENV['RACKSPACE_SERVICENET']))
  1039. $servicenet=True;
  1040. $this->cfs_http = new AEUtilCfhttp(DEFAULT_CF_API_VERSION);
  1041. $this->cfs_auth = $cfs_auth;
  1042. if (!$this->cfs_auth->authenticated()) {
  1043. $e = "Need to pass in a previously authenticated ";
  1044. $e .= "AEUtilCFAuthentication instance.";
  1045. throw new AuthenticationException($e);
  1046. }
  1047. $this->cfs_http->setCFAuth($this->cfs_auth, $servicenet=$servicenet);
  1048. $this->dbug = False;
  1049. }
  1050. /**
  1051. * Toggle debugging of instance and back-end HTTP module
  1052. *
  1053. * @param boolean $bool enable/disable cURL debugging
  1054. */
  1055. function setDebug($bool)
  1056. {
  1057. $this->dbug = (boolean) $bool;
  1058. $this->cfs_http->setDebug($this->dbug);
  1059. }
  1060. /**
  1061. * Close a connection
  1062. *
  1063. * Example:
  1064. * <code>
  1065. *
  1066. * $conn->close();
  1067. *
  1068. * </code>
  1069. *
  1070. * Will close all current cUrl active connections.
  1071. *
  1072. */
  1073. public function close()
  1074. {
  1075. $this->cfs_http->close();
  1076. }
  1077. /**
  1078. * Return a Container instance
  1079. *
  1080. * For the given name, return a Container instance if the remote Container
  1081. * exists, otherwise throw a Not Found exception.
  1082. *
  1083. * Example:
  1084. * <code>
  1085. * # ... authentication code excluded (see previous examples) ...
  1086. * #
  1087. * $conn = new AEUtilCFAuthentication($auth);
  1088. *
  1089. * $images = $conn->get_container("my photos");
  1090. * print "Number of Objects: " . $images->count . "\n";
  1091. * print "Bytes stored in container: " . $images->bytes . "\n";
  1092. * </code>
  1093. *
  1094. * @param string $container_name name of the remote Container
  1095. * @return container AEUtilCFContainer instance
  1096. * @throws NoSuchContainerException thrown if no remote Container
  1097. * @throws InvalidResponseException unexpected response
  1098. */
  1099. function get_container($container_name=NULL)
  1100. {
  1101. list($status, $reason, $count, $bytes) =
  1102. $this->cfs_http->head_container($container_name);
  1103. if ($status == 404) {
  1104. throw new NoSuchContainerException("Container not found.");
  1105. }
  1106. if ($status < 200 || $status > 299) {
  1107. throw new InvalidResponseException(
  1108. "Invalid response: ".$this->cfs_http->get_error());
  1109. }
  1110. return new AEUtilCFContainer($this->cfs_auth, $this->cfs_http,
  1111. $container_name, $count, $bytes);
  1112. }
  1113. /**
  1114. * Set a user-supplied callback function to report upload progress
  1115. *
  1116. * The callback function is used to report incremental progress of a data
  1117. * upload functions (e.g. $obj->write() call). The specified function will
  1118. * be periodically called with the number of bytes transferred until the
  1119. * entire upload is complete. This callback function can be useful
  1120. * for implementing "progress bars" for large uploads/downloads.
  1121. *
  1122. * The specified callback function should take a single integer parameter.
  1123. *
  1124. * <code>
  1125. * function write_callback($bytes_transferred) {
  1126. * print ">> uploaded " . $bytes_transferred . " bytes.\n";
  1127. * # ... do other things ...
  1128. * return;
  1129. * }
  1130. *
  1131. * $conn = new AEUtilCFConnection($auth_obj);
  1132. * $conn->set_write_progress_function("write_callback");
  1133. * $container = $conn->create_container("stuff");
  1134. * $obj = $container->create_object("foo");
  1135. * $obj->write("The callback function will be called during upload.");
  1136. *
  1137. * # output would look like this:
  1138. * # >> uploaded 51 bytes.
  1139. * #
  1140. * </code>
  1141. *
  1142. * @param string $func_name the name of the user callback function
  1143. */
  1144. function set_write_progress_function($func_name)
  1145. {
  1146. $this->cfs_http->setWriteProgressFunc($func_name);
  1147. }
  1148. }
  1149. /**
  1150. * Container operations
  1151. *
  1152. * Containers are storage compartments where you put your data (objects).
  1153. * A container is similar to a directory or folder on a conventional filesystem
  1154. * with the exception that they exist in a flat namespace, you can not create
  1155. * containers inside of containers.
  1156. *
  1157. * You also have the option of marking a Container as "public" so that the
  1158. * Objects stored in the Container are publicly available via the CDN.
  1159. *
  1160. * @package php-cloudfiles
  1161. */
  1162. class AEUtilCFContainer
  1163. {
  1164. public $cfs_auth;
  1165. public $cfs_http;
  1166. public $name;
  1167. public $object_count;
  1168. public $bytes_used;
  1169. public $cdn_enabled;
  1170. public $cdn_uri;
  1171. public $cdn_ttl;
  1172. public $cdn_log_retention;
  1173. public $cdn_acl_user_agent;
  1174. public $cdn_acl_referrer;
  1175. /**
  1176. * Class constructor
  1177. *
  1178. * Constructor for Container
  1179. *
  1180. * @param obj $cfs_auth AEUtilCFAuthentication instance
  1181. * @param obj $cfs_http HTTP connection manager
  1182. * @param string $name name of Container
  1183. * @param int $count number of Objects stored in this Container
  1184. * @param int $bytes number of bytes stored in this Container
  1185. * @throws SyntaxException invalid Container name
  1186. */
  1187. function __construct(&$cfs_auth, &$cfs_http, $name, $count=0,
  1188. $bytes=0, $docdn=True)
  1189. {
  1190. if (strlen($name) > MAX_CONTAINER_NAME_LEN) {
  1191. throw new SyntaxException("Container name exceeds "
  1192. . "maximum allowed length.");
  1193. }
  1194. if (strpos($name, "/") !== False) {
  1195. throw new SyntaxException(
  1196. "Container names cannot contain a '/' character.");
  1197. }
  1198. $this->cfs_auth = $cfs_auth;
  1199. $this->cfs_http = $cfs_http;
  1200. $this->name = $name;
  1201. $this->object_count = $count;
  1202. $this->bytes_used = $bytes;
  1203. $this->cdn_enabled = NULL;
  1204. $this->cdn_uri = NULL;
  1205. $this->cdn_ttl = NULL;
  1206. $this->cdn_log_retention = NULL;
  1207. $this->cdn_acl_user_agent = NULL;
  1208. $this->cdn_acl_referrer = NULL;
  1209. if ($this->cfs_http->getCDNMUrl() != NULL && $docdn) {
  1210. $this->_cdn_initialize();
  1211. }
  1212. }
  1213. /**
  1214. * String representation of Container
  1215. *
  1216. * Pretty print the Container instance.
  1217. *
  1218. * @return string Container details
  1219. */
  1220. function __toString()
  1221. {
  1222. $me = sprintf("name: %s, count: %.0f, bytes: %.0f",
  1223. $this->name, $this->object_count, $this->bytes_used);
  1224. if ($this->cfs_http->getCDNMUrl() != NULL) {
  1225. $me .= sprintf(", cdn: %s, cdn uri: %s, cdn ttl: %.0f, logs retention: %s",
  1226. $this->is_public() ? "Yes" : "No",
  1227. $this->cdn_uri, $this->cdn_ttl,
  1228. $this->cdn_log_retention ? "Yes" : "No"
  1229. );
  1230. if ($this->cdn_acl_user_agent != NULL) {
  1231. $me .= ", cdn acl user agent: " . $this->cdn_acl_user_agent;
  1232. }
  1233. if ($this->cdn_acl_referrer != NULL) {
  1234. $me .= ", cdn acl referrer: " . $this->cdn_acl_referrer;
  1235. }
  1236. }
  1237. return $me;
  1238. }
  1239. function create_object($obj_name=NULL)
  1240. {
  1241. return new AEUtilCFObject($this, $obj_name);
  1242. }
  1243. /**
  1244. * Helper function to create "path" elements for a given Object name
  1245. *
  1246. * Given an Object whos name contains '/' path separators, this function
  1247. * will create the "directory marker" Objects of one byte with the
  1248. * Content-Type of "application/folder".
  1249. *
  1250. * It assumes the last element of the full path is the "real" Object
  1251. * and does NOT create a remote storage Object for that last element.
  1252. */
  1253. function create_paths($path_name)
  1254. {
  1255. if ($path_name[0] == '/') {
  1256. $path_name = mb_substr($path_name, 0, 1);
  1257. }
  1258. $elements = explode('/', $path_name, -1);
  1259. $build_path = "";
  1260. foreach ($elements as $idx => $val) {
  1261. if (!$build_path) {
  1262. $build_path = $val;
  1263. } else {
  1264. $build_path .= "/" . $val;
  1265. }
  1266. $obj = new AEUtilCFObject($this, $build_path);
  1267. $obj->content_type = "application/directory";
  1268. $obj->write(".", 1);
  1269. }
  1270. }
  1271. /**
  1272. * Delete a remote storage Object
  1273. *
  1274. * Given an Object instance or name, permanently remove the remote Object
  1275. * and all associated metadata.
  1276. *
  1277. * Example:
  1278. * <code>
  1279. * # ... authentication code excluded (see previous examples) ...
  1280. * #
  1281. * $conn = new CF_Authentication($auth);
  1282. *
  1283. * $images = $conn->get_container("my photos");
  1284. *
  1285. * # Delete specific object
  1286. * #
  1287. * $images->delete_object("disco_dancing.jpg");
  1288. * </code>
  1289. *
  1290. * @param obj $obj name or instance of Object to delete
  1291. * @return boolean <kbd>True</kbd> if successfully removed
  1292. * @throws SyntaxException invalid Object name
  1293. * @throws NoSuchObjectException remote Object does not exist
  1294. * @throws InvalidResponseException unexpected response
  1295. */
  1296. function delete_object($obj)
  1297. {
  1298. $obj_name = NULL;
  1299. if (is_object($obj)) {
  1300. if (get_class($obj) == "AEUtilCFObject") {
  1301. $obj_name = $obj->name;
  1302. }
  1303. }
  1304. if (is_string($obj)) {
  1305. $obj_name = $obj;
  1306. }
  1307. if (!$obj_name) {
  1308. throw new SyntaxException("Object name not set.");
  1309. }
  1310. $status = $this->cfs_http->delete_object($this->name, $obj_name);
  1311. #if ($status == 401 && $this->_re_auth()) {
  1312. # return $this->delete_object($obj);
  1313. #}
  1314. if ($status == 404) {
  1315. $m = "Specified object '".$this->name."/".$obj_name;
  1316. $m.= "' did not exist to delete.";
  1317. throw new NoSuchObjectException($m);
  1318. }
  1319. if ($status != 204) {
  1320. throw new InvalidResponseException(
  1321. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1322. }
  1323. return True;
  1324. }
  1325. /**
  1326. * Return an Object instance for the remote storage Object
  1327. *
  1328. * Given a name, return a Object instance representing the
  1329. * remote storage object.
  1330. *
  1331. * Example:
  1332. * <code>
  1333. * # ... authentication code excluded (see previous examples) ...
  1334. * #
  1335. * $conn = new CF_Authentication($auth);
  1336. *
  1337. * $public_container = $conn->get_container("public");
  1338. *
  1339. * # This call only fetches header information and not the content of
  1340. * # the storage object. Use the Object's read() or stream() methods
  1341. * # to obtain the object's data.
  1342. * #
  1343. * $pic = $public_container->get_object("baby.jpg");
  1344. * </code>
  1345. *
  1346. * @param string $obj_name name of storage Object
  1347. * @return obj CF_Object instance
  1348. */
  1349. function get_object($obj_name=NULL)
  1350. {
  1351. return new AEUtilCFObject($this, $obj_name, True);
  1352. }
  1353. /**
  1354. * Return a list of Objects
  1355. *
  1356. * Return an array of strings listing the Object names in this Container.
  1357. *
  1358. * Example:
  1359. * <code>
  1360. * # ... authentication code excluded (see previous examples) ...
  1361. * #
  1362. * $images = $conn->get_container("my photos");
  1363. *
  1364. * # Grab the list of all storage objects
  1365. * #
  1366. * $all_objects = $images->list_objects();
  1367. *
  1368. * # Grab subsets of all storage objects
  1369. * #
  1370. * $first_ten = $images->list_objects(10);
  1371. *
  1372. * # Note the use of the previous result's last object name being
  1373. * # used as the 'marker' parameter to fetch the next 10 objects
  1374. * #
  1375. * $next_ten = $imag…

Large files files are truncated, but you can click here to view the full file