PageRenderTime 69ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/backwpup/libs/rackspace/cloudfiles.php

https://bitbucket.org/ssellek/saywhatnation.bitbucket
PHP | 2592 lines | 962 code | 114 blank | 1516 comment | 219 complexity | 1c42a73a72528717dc605d0fa7aa4faf MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, GPL-2.0, GPL-3.0
  1. <?php
  2. /**
  3. * This is the PHP Cloud Files API.
  4. *
  5. * <code>
  6. * # Authenticate to Cloud Files. The default is to automatically try
  7. * # to re-authenticate if an authentication token expires.
  8. * #
  9. * # NOTE: Some versions of cURL include an outdated certificate authority (CA)
  10. * # file. This API ships with a newer version obtained directly from
  11. * # cURL's web site (http://curl.haxx.se). To use the newer CA bundle,
  12. * # call the CF_Authentication instance's 'ssl_use_cabundle()' method.
  13. * #
  14. * $auth = new CF_Authentication($username, $api_key);
  15. * # $auth->ssl_use_cabundle(); # bypass cURL's old CA bundle
  16. * $auth->authenticate();
  17. *
  18. * # Establish a connection to the storage system
  19. * #
  20. * # NOTE: Some versions of cURL include an outdated certificate authority (CA)
  21. * # file. This API ships with a newer version obtained directly from
  22. * # cURL's web site (http://curl.haxx.se). To use the newer CA bundle,
  23. * # call the CF_Connection instance's 'ssl_use_cabundle()' method.
  24. * #
  25. * $conn = new CF_Connection($auth);
  26. * # $conn->ssl_use_cabundle(); # bypass cURL's old CA bundle
  27. *
  28. * # Create a remote Container and storage Object
  29. * #
  30. * $images = $conn->create_container("photos");
  31. * $bday = $images->create_object("first_birthday.jpg");
  32. *
  33. * # Upload content from a local file by streaming it. Note that we use
  34. * # a "float" for the file size to overcome PHP's 32-bit integer limit for
  35. * # very large files.
  36. * #
  37. * $fname = "/home/user/photos/birthdays/birthday1.jpg"; # filename to upload
  38. * $size = (float) sprintf("%u", filesize($fname));
  39. * $fp = open($fname, "r");
  40. * $bday->write($fp, $size);
  41. *
  42. * # Or... use a convenience function instead
  43. * #
  44. * $bday->load_from_filename("/home/user/photos/birthdays/birthday1.jpg");
  45. *
  46. * # Now, publish the "photos" container to serve the images by CDN.
  47. * # Use the "$uri" value to put in your web pages or send the link in an
  48. * # email message, etc.
  49. * #
  50. * $uri = $images->make_public();
  51. *
  52. * # Or... print out the Object's public URI
  53. * #
  54. * print $bday->public_uri();
  55. * </code>
  56. *
  57. * See the included tests directory for additional sample code.
  58. *
  59. * Requres PHP 5.x (for Exceptions and OO syntax) and PHP's cURL module.
  60. *
  61. * It uses the supporting "cloudfiles_http.php" module for HTTP(s) support and
  62. * allows for connection re-use and streaming of content into/out of Cloud Files
  63. * via PHP's cURL module.
  64. *
  65. * See COPYING for license information.
  66. *
  67. * @author Eric "EJ" Johnson <ej@racklabs.com>
  68. * @copyright Copyright (c) 2008, Rackspace US, Inc.
  69. * @package php-cloudfiles
  70. */
  71. /**
  72. */
  73. require_once("cloudfiles_exceptions.php");
  74. require("cloudfiles_http.php");
  75. define("DEFAULT_CF_API_VERSION", 1);
  76. define("MAX_CONTAINER_NAME_LEN", 256);
  77. define("MAX_OBJECT_NAME_LEN", 1024);
  78. define("MAX_OBJECT_SIZE", 5*1024*1024*1024+1);
  79. define("US_AUTHURL", "https://auth.api.rackspacecloud.com");
  80. define("UK_AUTHURL", "https://lon.auth.api.rackspacecloud.com");
  81. /**
  82. * Class for handling Cloud Files Authentication, call it's {@link authenticate()}
  83. * method to obtain authorized service urls and an authentication token.
  84. *
  85. * Example:
  86. * <code>
  87. * # Create the authentication instance
  88. * #
  89. * $auth = new CF_Authentication("username", "api_key");
  90. *
  91. * # NOTE: For UK Customers please specify your AuthURL Manually
  92. * # There is a Predfined constant to use EX:
  93. * #
  94. * # $auth = new CF_Authentication("username, "api_key", NULL, UK_AUTHURL);
  95. * # Using the UK_AUTHURL keyword will force the api to use the UK AuthUrl.
  96. * # rather then the US one. The NULL Is passed for legacy purposes and must
  97. * # be passed to function correctly.
  98. *
  99. * # NOTE: Some versions of cURL include an outdated certificate authority (CA)
  100. * # file. This API ships with a newer version obtained directly from
  101. * # cURL's web site (http://curl.haxx.se). To use the newer CA bundle,
  102. * # call the CF_Authentication instance's 'ssl_use_cabundle()' method.
  103. * #
  104. * # $auth->ssl_use_cabundle(); # bypass cURL's old CA bundle
  105. *
  106. * # Perform authentication request
  107. * #
  108. * $auth->authenticate();
  109. * </code>
  110. *
  111. * @package php-cloudfiles
  112. */
  113. class CF_Authentication
  114. {
  115. public $dbug;
  116. public $username;
  117. public $api_key;
  118. public $auth_host;
  119. public $account;
  120. /**
  121. * Instance variables that are set after successful authentication
  122. */
  123. public $storage_url;
  124. public $cdnm_url;
  125. public $auth_token;
  126. /**
  127. * Class constructor (PHP 5 syntax)
  128. *
  129. * @param string $username Mosso username
  130. * @param string $api_key Mosso API Access Key
  131. * @param string $account <i>Account name</i>
  132. * @param string $auth_host <i>Authentication service URI</i>
  133. */
  134. function __construct($username=NULL, $api_key=NULL, $account=NULL, $auth_host=US_AUTHURL)
  135. {
  136. $this->dbug = False;
  137. $this->username = $username;
  138. $this->api_key = $api_key;
  139. $this->account_name = $account;
  140. $this->auth_host = $auth_host;
  141. $this->storage_url = NULL;
  142. $this->cdnm_url = NULL;
  143. $this->auth_token = NULL;
  144. $this->cfs_http = new CF_Http(DEFAULT_CF_API_VERSION);
  145. }
  146. /**
  147. * Use the Certificate Authority bundle included with this API
  148. *
  149. * Most versions of PHP with cURL support include an outdated Certificate
  150. * Authority (CA) bundle (the file that lists all valid certificate
  151. * signing authorities). The SSL certificates used by the Cloud Files
  152. * storage system are perfectly valid but have been created/signed by
  153. * a CA not listed in these outdated cURL distributions.
  154. *
  155. * As a work-around, we've included an updated CA bundle obtained
  156. * directly from cURL's web site (http://curl.haxx.se). You can direct
  157. * the API to use this CA bundle by calling this method prior to making
  158. * any remote calls. The best place to use this method is right after
  159. * the CF_Authentication instance has been instantiated.
  160. *
  161. * You can specify your own CA bundle by passing in the full pathname
  162. * to the bundle. You can use the included CA bundle by leaving the
  163. * argument blank.
  164. *
  165. * @param string $path Specify path to CA bundle (default to included)
  166. */
  167. function ssl_use_cabundle($path=NULL)
  168. {
  169. $this->cfs_http->ssl_use_cabundle($path);
  170. }
  171. /**
  172. * Attempt to validate Username/API Access Key
  173. *
  174. * Attempts to validate credentials with the authentication service. It
  175. * either returns <kbd>True</kbd> or throws an Exception. Accepts a single
  176. * (optional) argument for the storage system API version.
  177. *
  178. * Example:
  179. * <code>
  180. * # Create the authentication instance
  181. * #
  182. * $auth = new CF_Authentication("username", "api_key");
  183. *
  184. * # Perform authentication request
  185. * #
  186. * $auth->authenticate();
  187. * </code>
  188. *
  189. * @param string $version API version for Auth service (optional)
  190. * @return boolean <kbd>True</kbd> if successfully authenticated
  191. * @throws AuthenticationException invalid credentials
  192. * @throws InvalidResponseException invalid response
  193. */
  194. function authenticate($version=DEFAULT_CF_API_VERSION)
  195. {
  196. list($status,$reason,$surl,$curl,$atoken) =
  197. $this->cfs_http->authenticate($this->username, $this->api_key,
  198. $this->account_name, $this->auth_host);
  199. if ($status == 401) {
  200. throw new AuthenticationException("Invalid username or access key.");
  201. }
  202. if ($status < 200 || $status > 299) {
  203. throw new InvalidResponseException(
  204. "Unexpected response (".$status."): ".$reason);
  205. }
  206. if (!($surl || $curl) || !$atoken) {
  207. throw new InvalidResponseException(
  208. "Expected headers missing from auth service.");
  209. }
  210. $this->storage_url = $surl;
  211. $this->cdnm_url = $curl;
  212. $this->auth_token = $atoken;
  213. return True;
  214. }
  215. /**
  216. * Use Cached Token and Storage URL's rather then grabbing from the Auth System
  217. *
  218. * Example:
  219. * <code>
  220. * #Create an Auth instance
  221. * $auth = new CF_Authentication();
  222. * #Pass Cached URL's and Token as Args
  223. * $auth->load_cached_credentials("auth_token", "storage_url", "cdn_management_url");
  224. * </code>
  225. *
  226. * @param string $auth_token A Cloud Files Auth Token (Required)
  227. * @param string $storage_url The Cloud Files Storage URL (Required)
  228. * @param string $cdnm_url CDN Management URL (Required)
  229. * @return boolean <kbd>True</kbd> if successful
  230. * @throws SyntaxException If any of the Required Arguments are missing
  231. */
  232. function load_cached_credentials($auth_token, $storage_url, $cdnm_url)
  233. {
  234. if(!$storage_url || !$cdnm_url)
  235. {
  236. throw new SyntaxException("Missing Required Interface URL's!");
  237. return False;
  238. }
  239. if(!$auth_token)
  240. {
  241. throw new SyntaxException("Missing Auth Token!");
  242. return False;
  243. }
  244. $this->storage_url = $storage_url;
  245. $this->cdnm_url = $cdnm_url;
  246. $this->auth_token = $auth_token;
  247. return True;
  248. }
  249. /**
  250. * Grab Cloud Files info to be Cached for later use with the load_cached_credentials method.
  251. *
  252. * Example:
  253. * <code>
  254. * #Create an Auth instance
  255. * $auth = new CF_Authentication("UserName","API_Key");
  256. * $auth->authenticate();
  257. * $array = $auth->export_credentials();
  258. * </code>
  259. *
  260. * @return array of url's and an auth token.
  261. */
  262. function export_credentials()
  263. {
  264. $arr = array();
  265. $arr['storage_url'] = $this->storage_url;
  266. $arr['cdnm_url'] = $this->cdnm_url;
  267. $arr['auth_token'] = $this->auth_token;
  268. return $arr;
  269. }
  270. /**
  271. * Make sure the CF_Authentication instance has authenticated.
  272. *
  273. * Ensures that the instance variables necessary to communicate with
  274. * Cloud Files have been set from a previous authenticate() call.
  275. *
  276. * @return boolean <kbd>True</kbd> if successfully authenticated
  277. */
  278. function authenticated()
  279. {
  280. if (!($this->storage_url || $this->cdnm_url) || !$this->auth_token) {
  281. return False;
  282. }
  283. return True;
  284. }
  285. /**
  286. * Toggle debugging - set cURL verbose flag
  287. */
  288. function setDebug($bool)
  289. {
  290. $this->dbug = $bool;
  291. $this->cfs_http->setDebug($bool);
  292. }
  293. }
  294. /**
  295. * Class for establishing connections to the Cloud Files storage system.
  296. * Connection instances are used to communicate with the storage system at
  297. * the account level; listing and deleting Containers and returning Container
  298. * instances.
  299. *
  300. * Example:
  301. * <code>
  302. * # Create the authentication instance
  303. * #
  304. * $auth = new CF_Authentication("username", "api_key");
  305. *
  306. * # Perform authentication request
  307. * #
  308. * $auth->authenticate();
  309. *
  310. * # Create a connection to the storage/cdn system(s) and pass in the
  311. * # validated CF_Authentication instance.
  312. * #
  313. * $conn = new CF_Connection($auth);
  314. *
  315. * # NOTE: Some versions of cURL include an outdated certificate authority (CA)
  316. * # file. This API ships with a newer version obtained directly from
  317. * # cURL's web site (http://curl.haxx.se). To use the newer CA bundle,
  318. * # call the CF_Authentication instance's 'ssl_use_cabundle()' method.
  319. * #
  320. * # $conn->ssl_use_cabundle(); # bypass cURL's old CA bundle
  321. * </code>
  322. *
  323. * @package php-cloudfiles
  324. */
  325. class CF_Connection
  326. {
  327. public $dbug;
  328. public $cfs_http;
  329. public $cfs_auth;
  330. /**
  331. * Pass in a previously authenticated CF_Authentication instance.
  332. *
  333. * Example:
  334. * <code>
  335. * # Create the authentication instance
  336. * #
  337. * $auth = new CF_Authentication("username", "api_key");
  338. *
  339. * # Perform authentication request
  340. * #
  341. * $auth->authenticate();
  342. *
  343. * # Create a connection to the storage/cdn system(s) and pass in the
  344. * # validated CF_Authentication instance.
  345. * #
  346. * $conn = new CF_Connection($auth);
  347. *
  348. * # If you are connecting via Rackspace servers and have access
  349. * # to the servicenet network you can set the $servicenet to True
  350. * # like this.
  351. *
  352. * $conn = new CF_Connection($auth, $servicenet=True);
  353. *
  354. * </code>
  355. *
  356. * If the environement variable RACKSPACE_SERVICENET is defined it will
  357. * force to connect via the servicenet.
  358. *
  359. * @param obj $cfs_auth previously authenticated CF_Authentication instance
  360. * @param boolean $servicenet enable/disable access via Rackspace servicenet.
  361. * @throws AuthenticationException not authenticated
  362. */
  363. function __construct($cfs_auth, $servicenet=False)
  364. {
  365. if (isset($_ENV['RACKSPACE_SERVICENET']))
  366. $servicenet=True;
  367. $this->cfs_http = new CF_Http(DEFAULT_CF_API_VERSION);
  368. $this->cfs_auth = $cfs_auth;
  369. if (!$this->cfs_auth->authenticated()) {
  370. $e = "Need to pass in a previously authenticated ";
  371. $e .= "CF_Authentication instance.";
  372. throw new AuthenticationException($e);
  373. }
  374. $this->cfs_http->setCFAuth($this->cfs_auth, $servicenet=$servicenet);
  375. $this->dbug = False;
  376. }
  377. /**
  378. * Toggle debugging of instance and back-end HTTP module
  379. *
  380. * @param boolean $bool enable/disable cURL debugging
  381. */
  382. function setDebug($bool)
  383. {
  384. $this->dbug = (boolean) $bool;
  385. $this->cfs_http->setDebug($this->dbug);
  386. }
  387. /**
  388. * Close a connection
  389. *
  390. * Example:
  391. * <code>
  392. *
  393. * $conn->close();
  394. *
  395. * </code>
  396. *
  397. * Will close all current cUrl active connections.
  398. *
  399. */
  400. public function close()
  401. {
  402. $this->cfs_http->close();
  403. }
  404. /**
  405. * Cloud Files account information
  406. *
  407. * Return an array of two floats (since PHP only supports 32-bit integers);
  408. * number of containers on the account and total bytes used for the account.
  409. *
  410. * Example:
  411. * <code>
  412. * # ... authentication code excluded (see previous examples) ...
  413. * #
  414. * $conn = new CF_Authentication($auth);
  415. *
  416. * list($quantity, $bytes) = $conn->get_info();
  417. * print "Number of containers: " . $quantity . "\n";
  418. * print "Bytes stored in container: " . $bytes . "\n";
  419. * </code>
  420. *
  421. * @return array (number of containers, total bytes stored)
  422. * @throws InvalidResponseException unexpected response
  423. */
  424. function get_info()
  425. {
  426. list($status, $reason, $container_count, $total_bytes) =
  427. $this->cfs_http->head_account();
  428. #if ($status == 401 && $this->_re_auth()) {
  429. # return $this->get_info();
  430. #}
  431. if ($status < 200 || $status > 299) {
  432. throw new InvalidResponseException(
  433. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  434. }
  435. return array($container_count, $total_bytes);
  436. }
  437. /**
  438. * Create a Container
  439. *
  440. * Given a Container name, return a Container instance, creating a new
  441. * remote Container if it does not exit.
  442. *
  443. * Example:
  444. * <code>
  445. * # ... authentication code excluded (see previous examples) ...
  446. * #
  447. * $conn = new CF_Authentication($auth);
  448. *
  449. * $images = $conn->create_container("my photos");
  450. * </code>
  451. *
  452. * @param string $container_name container name
  453. * @return CF_Container
  454. * @throws SyntaxException invalid name
  455. * @throws InvalidResponseException unexpected response
  456. */
  457. function create_container($container_name=NULL)
  458. {
  459. if ($container_name != "0" and !isset($container_name))
  460. throw new SyntaxException("Container name not set.");
  461. if (!isset($container_name) or $container_name == "")
  462. throw new SyntaxException("Container name not set.");
  463. if (strpos($container_name, "/") !== False) {
  464. $r = "Container name '".$container_name;
  465. $r .= "' cannot contain a '/' character.";
  466. throw new SyntaxException($r);
  467. }
  468. if (strlen($container_name) > MAX_CONTAINER_NAME_LEN) {
  469. throw new SyntaxException(sprintf(
  470. "Container name exeeds %d bytes.",
  471. MAX_CONTAINER_NAME_LEN));
  472. }
  473. $return_code = $this->cfs_http->create_container($container_name);
  474. if (!$return_code) {
  475. throw new InvalidResponseException("Invalid response ("
  476. . $return_code. "): " . $this->cfs_http->get_error());
  477. }
  478. #if ($status == 401 && $this->_re_auth()) {
  479. # return $this->create_container($container_name);
  480. #}
  481. if ($return_code != 201 && $return_code != 202) {
  482. throw new InvalidResponseException(
  483. "Invalid response (".$return_code."): "
  484. . $this->cfs_http->get_error());
  485. }
  486. return new CF_Container($this->cfs_auth, $this->cfs_http, $container_name);
  487. }
  488. /**
  489. * Delete a Container
  490. *
  491. * Given either a Container instance or name, remove the remote Container.
  492. * The Container must be empty prior to removing it.
  493. *
  494. * Example:
  495. * <code>
  496. * # ... authentication code excluded (see previous examples) ...
  497. * #
  498. * $conn = new CF_Authentication($auth);
  499. *
  500. * $conn->delete_container("my photos");
  501. * </code>
  502. *
  503. * @param string|obj $container container name or instance
  504. * @return boolean <kbd>True</kbd> if successfully deleted
  505. * @throws SyntaxException missing proper argument
  506. * @throws InvalidResponseException invalid response
  507. * @throws NonEmptyContainerException container not empty
  508. * @throws NoSuchContainerException remote container does not exist
  509. */
  510. function delete_container($container=NULL)
  511. {
  512. $container_name = NULL;
  513. if (is_object($container)) {
  514. if (get_class($container) == "CF_Container") {
  515. $container_name = $container->name;
  516. }
  517. }
  518. if (is_string($container)) {
  519. $container_name = $container;
  520. }
  521. if ($container_name != "0" and !isset($container_name))
  522. throw new SyntaxException("Must specify container object or name.");
  523. $return_code = $this->cfs_http->delete_container($container_name);
  524. if (!$return_code) {
  525. throw new InvalidResponseException("Failed to obtain http response");
  526. }
  527. #if ($status == 401 && $this->_re_auth()) {
  528. # return $this->delete_container($container);
  529. #}
  530. if ($return_code == 409) {
  531. throw new NonEmptyContainerException(
  532. "Container must be empty prior to removing it.");
  533. }
  534. if ($return_code == 404) {
  535. throw new NoSuchContainerException(
  536. "Specified container did not exist to delete.");
  537. }
  538. if ($return_code != 204) {
  539. throw new InvalidResponseException(
  540. "Invalid response (".$return_code."): "
  541. . $this->cfs_http->get_error());
  542. }
  543. return True;
  544. }
  545. /**
  546. * Return a Container instance
  547. *
  548. * For the given name, return a Container instance if the remote Container
  549. * exists, otherwise throw a Not Found exception.
  550. *
  551. * Example:
  552. * <code>
  553. * # ... authentication code excluded (see previous examples) ...
  554. * #
  555. * $conn = new CF_Authentication($auth);
  556. *
  557. * $images = $conn->get_container("my photos");
  558. * print "Number of Objects: " . $images->count . "\n";
  559. * print "Bytes stored in container: " . $images->bytes . "\n";
  560. * </code>
  561. *
  562. * @param string $container_name name of the remote Container
  563. * @return container CF_Container instance
  564. * @throws NoSuchContainerException thrown if no remote Container
  565. * @throws InvalidResponseException unexpected response
  566. */
  567. function get_container($container_name=NULL)
  568. {
  569. list($status, $reason, $count, $bytes) =
  570. $this->cfs_http->head_container($container_name);
  571. #if ($status == 401 && $this->_re_auth()) {
  572. # return $this->get_container($container_name);
  573. #}
  574. if ($status == 404) {
  575. throw new NoSuchContainerException("Container not found.");
  576. }
  577. if ($status < 200 || $status > 299) {
  578. throw new InvalidResponseException(
  579. "Invalid response: ".$this->cfs_http->get_error());
  580. }
  581. return new CF_Container($this->cfs_auth, $this->cfs_http,
  582. $container_name, $count, $bytes);
  583. }
  584. /**
  585. * Return array of Container instances
  586. *
  587. * Return an array of CF_Container instances on the account. The instances
  588. * will be fully populated with Container attributes (bytes stored and
  589. * Object count)
  590. *
  591. * Example:
  592. * <code>
  593. * # ... authentication code excluded (see previous examples) ...
  594. * #
  595. * $conn = new CF_Authentication($auth);
  596. *
  597. * $clist = $conn->get_containers();
  598. * foreach ($clist as $cont) {
  599. * print "Container name: " . $cont->name . "\n";
  600. * print "Number of Objects: " . $cont->count . "\n";
  601. * print "Bytes stored in container: " . $cont->bytes . "\n";
  602. * }
  603. * </code>
  604. *
  605. * @return array An array of CF_Container instances
  606. * @throws InvalidResponseException unexpected response
  607. */
  608. function get_containers($limit=0, $marker=NULL)
  609. {
  610. list($status, $reason, $container_info) =
  611. $this->cfs_http->list_containers_info($limit, $marker);
  612. #if ($status == 401 && $this->_re_auth()) {
  613. # return $this->get_containers();
  614. #}
  615. if ($status < 200 || $status > 299) {
  616. throw new InvalidResponseException(
  617. "Invalid response: ".$this->cfs_http->get_error());
  618. }
  619. $containers = array();
  620. foreach ($container_info as $name => $info) {
  621. $containers[] = new CF_Container($this->cfs_auth, $this->cfs_http,
  622. $info['name'], $info["count"], $info["bytes"], False);
  623. }
  624. return $containers;
  625. }
  626. /**
  627. * Return list of remote Containers
  628. *
  629. * Return an array of strings containing the names of all remote Containers.
  630. *
  631. * Example:
  632. * <code>
  633. * # ... authentication code excluded (see previous examples) ...
  634. * #
  635. * $conn = new CF_Authentication($auth);
  636. *
  637. * $container_list = $conn->list_containers();
  638. * print_r($container_list);
  639. * Array
  640. * (
  641. * [0] => "my photos",
  642. * [1] => "my docs"
  643. * )
  644. * </code>
  645. *
  646. * @param integer $limit restrict results to $limit Containers
  647. * @param string $marker return results greater than $marker
  648. * @return array list of remote Containers
  649. * @throws InvalidResponseException unexpected response
  650. */
  651. function list_containers($limit=0, $marker=NULL)
  652. {
  653. list($status, $reason, $containers) =
  654. $this->cfs_http->list_containers($limit, $marker);
  655. #if ($status == 401 && $this->_re_auth()) {
  656. # return $this->list_containers($limit, $marker);
  657. #}
  658. if ($status < 200 || $status > 299) {
  659. throw new InvalidResponseException(
  660. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  661. }
  662. return $containers;
  663. }
  664. /**
  665. * Return array of information about remote Containers
  666. *
  667. * Return a nested array structure of Container info.
  668. *
  669. * Example:
  670. * <code>
  671. * # ... authentication code excluded (see previous examples) ...
  672. * #
  673. *
  674. * $container_info = $conn->list_containers_info();
  675. * print_r($container_info);
  676. * Array
  677. * (
  678. * ["my photos"] =>
  679. * Array
  680. * (
  681. * ["bytes"] => 78,
  682. * ["count"] => 2
  683. * )
  684. * ["docs"] =>
  685. * Array
  686. * (
  687. * ["bytes"] => 37323,
  688. * ["count"] => 12
  689. * )
  690. * )
  691. * </code>
  692. *
  693. * @param integer $limit restrict results to $limit Containers
  694. * @param string $marker return results greater than $marker
  695. * @return array nested array structure of Container info
  696. * @throws InvalidResponseException unexpected response
  697. */
  698. function list_containers_info($limit=0, $marker=NULL)
  699. {
  700. list($status, $reason, $container_info) =
  701. $this->cfs_http->list_containers_info($limit, $marker);
  702. #if ($status == 401 && $this->_re_auth()) {
  703. # return $this->list_containers_info($limit, $marker);
  704. #}
  705. if ($status < 200 || $status > 299) {
  706. throw new InvalidResponseException(
  707. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  708. }
  709. return $container_info;
  710. }
  711. /**
  712. * Return list of Containers that have been published to the CDN.
  713. *
  714. * Return an array of strings containing the names of published Containers.
  715. * Note that this function returns the list of any Container that has
  716. * ever been CDN-enabled regardless of it's existence in the storage
  717. * system.
  718. *
  719. * Example:
  720. * <code>
  721. * # ... authentication code excluded (see previous examples) ...
  722. * #
  723. * $conn = new CF_Authentication($auth);
  724. *
  725. * $public_containers = $conn->list_public_containers();
  726. * print_r($public_containers);
  727. * Array
  728. * (
  729. * [0] => "images",
  730. * [1] => "css",
  731. * [2] => "javascript"
  732. * )
  733. * </code>
  734. *
  735. * @param bool $enabled_only Will list all containers ever CDN enabled if * set to false or only currently enabled CDN containers if set to true. * Defaults to false.
  736. * @return array list of published Container names
  737. * @throws InvalidResponseException unexpected response
  738. */
  739. function list_public_containers($enabled_only=False)
  740. {
  741. list($status, $reason, $containers) =
  742. $this->cfs_http->list_cdn_containers($enabled_only);
  743. #if ($status == 401 && $this->_re_auth()) {
  744. # return $this->list_public_containers();
  745. #}
  746. if ($status < 200 || $status > 299) {
  747. throw new InvalidResponseException(
  748. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  749. }
  750. return $containers;
  751. }
  752. /**
  753. * Set a user-supplied callback function to report download progress
  754. *
  755. * The callback function is used to report incremental progress of a data
  756. * download functions (e.g. $container->list_objects(), $obj->read(), etc).
  757. * The specified function will be periodically called with the number of
  758. * bytes transferred until the entire download is complete. This callback
  759. * function can be useful for implementing "progress bars" for large
  760. * downloads.
  761. *
  762. * The specified callback function should take a single integer parameter.
  763. *
  764. * <code>
  765. * function read_callback($bytes_transferred) {
  766. * print ">> downloaded " . $bytes_transferred . " bytes.\n";
  767. * # ... do other things ...
  768. * return;
  769. * }
  770. *
  771. * $conn = new CF_Connection($auth_obj);
  772. * $conn->set_read_progress_function("read_callback");
  773. * print_r($conn->list_containers());
  774. *
  775. * # output would look like this:
  776. * #
  777. * >> downloaded 10 bytes.
  778. * >> downloaded 11 bytes.
  779. * Array
  780. * (
  781. * [0] => fuzzy.txt
  782. * [1] => space name
  783. * )
  784. * </code>
  785. *
  786. * @param string $func_name the name of the user callback function
  787. */
  788. function set_read_progress_function($func_name)
  789. {
  790. $this->cfs_http->setReadProgressFunc($func_name);
  791. }
  792. /**
  793. * Set a user-supplied callback function to report upload progress
  794. *
  795. * The callback function is used to report incremental progress of a data
  796. * upload functions (e.g. $obj->write() call). The specified function will
  797. * be periodically called with the number of bytes transferred until the
  798. * entire upload is complete. This callback function can be useful
  799. * for implementing "progress bars" for large uploads/downloads.
  800. *
  801. * The specified callback function should take a single integer parameter.
  802. *
  803. * <code>
  804. * function write_callback($bytes_transferred) {
  805. * print ">> uploaded " . $bytes_transferred . " bytes.\n";
  806. * # ... do other things ...
  807. * return;
  808. * }
  809. *
  810. * $conn = new CF_Connection($auth_obj);
  811. * $conn->set_write_progress_function("write_callback");
  812. * $container = $conn->create_container("stuff");
  813. * $obj = $container->create_object("foo");
  814. * $obj->write("The callback function will be called during upload.");
  815. *
  816. * # output would look like this:
  817. * # >> uploaded 51 bytes.
  818. * #
  819. * </code>
  820. *
  821. * @param string $func_name the name of the user callback function
  822. */
  823. function set_write_progress_function($func_name)
  824. {
  825. $this->cfs_http->setWriteProgressFunc($func_name);
  826. }
  827. /**
  828. * Use the Certificate Authority bundle included with this API
  829. *
  830. * Most versions of PHP with cURL support include an outdated Certificate
  831. * Authority (CA) bundle (the file that lists all valid certificate
  832. * signing authorities). The SSL certificates used by the Cloud Files
  833. * storage system are perfectly valid but have been created/signed by
  834. * a CA not listed in these outdated cURL distributions.
  835. *
  836. * As a work-around, we've included an updated CA bundle obtained
  837. * directly from cURL's web site (http://curl.haxx.se). You can direct
  838. * the API to use this CA bundle by calling this method prior to making
  839. * any remote calls. The best place to use this method is right after
  840. * the CF_Authentication instance has been instantiated.
  841. *
  842. * You can specify your own CA bundle by passing in the full pathname
  843. * to the bundle. You can use the included CA bundle by leaving the
  844. * argument blank.
  845. *
  846. * @param string $path Specify path to CA bundle (default to included)
  847. */
  848. function ssl_use_cabundle($path=NULL)
  849. {
  850. $this->cfs_http->ssl_use_cabundle($path);
  851. }
  852. #private function _re_auth()
  853. #{
  854. # $new_auth = new CF_Authentication(
  855. # $this->cfs_auth->username,
  856. # $this->cfs_auth->api_key,
  857. # $this->cfs_auth->auth_host,
  858. # $this->cfs_auth->account);
  859. # $new_auth->authenticate();
  860. # $this->cfs_auth = $new_auth;
  861. # $this->cfs_http->setCFAuth($this->cfs_auth);
  862. # return True;
  863. #}
  864. }
  865. /**
  866. * Container operations
  867. *
  868. * Containers are storage compartments where you put your data (objects).
  869. * A container is similar to a directory or folder on a conventional filesystem
  870. * with the exception that they exist in a flat namespace, you can not create
  871. * containers inside of containers.
  872. *
  873. * You also have the option of marking a Container as "public" so that the
  874. * Objects stored in the Container are publicly available via the CDN.
  875. *
  876. * @package php-cloudfiles
  877. */
  878. class CF_Container
  879. {
  880. public $cfs_auth;
  881. public $cfs_http;
  882. public $name;
  883. public $object_count;
  884. public $bytes_used;
  885. public $cdn_enabled;
  886. public $cdn_streaming_uri;
  887. public $cdn_ssl_uri;
  888. public $cdn_uri;
  889. public $cdn_ttl;
  890. public $cdn_log_retention;
  891. public $cdn_acl_user_agent;
  892. public $cdn_acl_referrer;
  893. /**
  894. * Class constructor
  895. *
  896. * Constructor for Container
  897. *
  898. * @param obj $cfs_auth CF_Authentication instance
  899. * @param obj $cfs_http HTTP connection manager
  900. * @param string $name name of Container
  901. * @param int $count number of Objects stored in this Container
  902. * @param int $bytes number of bytes stored in this Container
  903. * @throws SyntaxException invalid Container name
  904. */
  905. function __construct(&$cfs_auth, &$cfs_http, $name, $count=0,
  906. $bytes=0, $docdn=True)
  907. {
  908. if (strlen($name) > MAX_CONTAINER_NAME_LEN) {
  909. throw new SyntaxException("Container name exceeds "
  910. . "maximum allowed length.");
  911. }
  912. if (strpos($name, "/") !== False) {
  913. throw new SyntaxException(
  914. "Container names cannot contain a '/' character.");
  915. }
  916. $this->cfs_auth = $cfs_auth;
  917. $this->cfs_http = $cfs_http;
  918. $this->name = $name;
  919. $this->object_count = $count;
  920. $this->bytes_used = $bytes;
  921. $this->cdn_enabled = NULL;
  922. $this->cdn_uri = NULL;
  923. $this->cdn_ssl_uri = NULL;
  924. $this->cdn_streaming_uri = NULL;
  925. $this->cdn_ttl = NULL;
  926. $this->cdn_log_retention = NULL;
  927. $this->cdn_acl_user_agent = NULL;
  928. $this->cdn_acl_referrer = NULL;
  929. if ($this->cfs_http->getCDNMUrl() != NULL && $docdn) {
  930. $this->_cdn_initialize();
  931. }
  932. }
  933. /**
  934. * String representation of Container
  935. *
  936. * Pretty print the Container instance.
  937. *
  938. * @return string Container details
  939. */
  940. function __toString()
  941. {
  942. $me = sprintf("name: %s, count: %.0f, bytes: %.0f",
  943. $this->name, $this->object_count, $this->bytes_used);
  944. if ($this->cfs_http->getCDNMUrl() != NULL) {
  945. $me .= sprintf(", cdn: %s, cdn uri: %s, cdn ttl: %.0f, logs retention: %s",
  946. $this->is_public() ? "Yes" : "No",
  947. $this->cdn_uri, $this->cdn_ttl,
  948. $this->cdn_log_retention ? "Yes" : "No"
  949. );
  950. if ($this->cdn_acl_user_agent != NULL) {
  951. $me .= ", cdn acl user agent: " . $this->cdn_acl_user_agent;
  952. }
  953. if ($this->cdn_acl_referrer != NULL) {
  954. $me .= ", cdn acl referrer: " . $this->cdn_acl_referrer;
  955. }
  956. }
  957. return $me;
  958. }
  959. /**
  960. * Enable Container content to be served via CDN or modify CDN attributes
  961. *
  962. * Either enable this Container's content to be served via CDN or
  963. * adjust its CDN attributes. This Container will always return the
  964. * same CDN-enabled URI each time it is toggled public/private/public.
  965. *
  966. * Example:
  967. * <code>
  968. * # ... authentication code excluded (see previous examples) ...
  969. * #
  970. * $conn = new CF_Authentication($auth);
  971. *
  972. * $public_container = $conn->create_container("public");
  973. *
  974. * # CDN-enable the container and set it's TTL for a month
  975. * #
  976. * $public_container->make_public(86400/2); # 12 hours (86400 seconds/day)
  977. * </code>
  978. *
  979. * @param int $ttl the time in seconds content will be cached in the CDN
  980. * @returns string the CDN enabled Container's URI
  981. * @throws CDNNotEnabledException CDN functionality not returned during auth
  982. * @throws AuthenticationException if auth token is not valid/expired
  983. * @throws InvalidResponseException unexpected response
  984. */
  985. function make_public($ttl=86400)
  986. {
  987. if ($this->cfs_http->getCDNMUrl() == NULL) {
  988. throw new CDNNotEnabledException(
  989. "Authentication response did not indicate CDN availability");
  990. }
  991. if ($this->cdn_uri != NULL) {
  992. # previously published, assume we're setting new attributes
  993. list($status, $reason, $cdn_uri, $cdn_ssl_uri) =
  994. $this->cfs_http->update_cdn_container($this->name,$ttl,
  995. $this->cdn_log_retention,
  996. $this->cdn_acl_user_agent,
  997. $this->cdn_acl_referrer);
  998. #if ($status == 401 && $this->_re_auth()) {
  999. # return $this->make_public($ttl);
  1000. #}
  1001. if ($status == 404) {
  1002. # this instance _thinks_ the container was published, but the
  1003. # cdn management system thinks otherwise - try again with a PUT
  1004. list($status, $reason, $cdn_uri, $cdn_ssl_uri) =
  1005. $this->cfs_http->add_cdn_container($this->name,$ttl);
  1006. }
  1007. } else {
  1008. # publish it for first time
  1009. list($status, $reason, $cdn_uri, $cdn_ssl_uri) =
  1010. $this->cfs_http->add_cdn_container($this->name,$ttl);
  1011. }
  1012. #if ($status == 401 && $this->_re_auth()) {
  1013. # return $this->make_public($ttl);
  1014. #}
  1015. if (!in_array($status, array(201,202))) {
  1016. throw new InvalidResponseException(
  1017. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1018. }
  1019. $this->cdn_enabled = True;
  1020. $this->cdn_ttl = $ttl;
  1021. $this->cdn_ssl_uri = $cdn_ssl_uri;
  1022. $this->cdn_uri = $cdn_uri;
  1023. $this->cdn_log_retention = False;
  1024. $this->cdn_acl_user_agent = "";
  1025. $this->cdn_acl_referrer = "";
  1026. return $this->cdn_uri;
  1027. }
  1028. /**
  1029. * Purge Containers objects from CDN Cache.
  1030. * Example:
  1031. * <code>
  1032. * # ... authentication code excluded (see previous examples) ...
  1033. * #
  1034. * $conn = new CF_Authentication($auth);
  1035. * $container = $conn->get_container("cdn_enabled");
  1036. * $container->purge_from_cdn("user@domain.com");
  1037. * # or
  1038. * $container->purge_from_cdn();
  1039. * # or
  1040. * $container->purge_from_cdn("user1@domain.com,user2@domain.com");
  1041. * @returns boolean True if successful
  1042. * @throws CDNNotEnabledException if CDN Is not enabled on this connection
  1043. * @throws InvalidResponseException if the response expected is not returned
  1044. */
  1045. function purge_from_cdn($email=null)
  1046. {
  1047. if (!$this->cfs_http->getCDNMUrl())
  1048. {
  1049. throw new CDNNotEnabledException(
  1050. "Authentication response did not indicate CDN availability");
  1051. }
  1052. $status = $this->cfs_http->purge_from_cdn($this->name, $email);
  1053. if ($status < 199 or $status > 299) {
  1054. throw new InvalidResponseException(
  1055. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1056. }
  1057. return True;
  1058. }
  1059. /**
  1060. * Enable ACL restriction by User Agent for this container.
  1061. *
  1062. * Example:
  1063. * <code>
  1064. * # ... authentication code excluded (see previous examples) ...
  1065. * #
  1066. * $conn = new CF_Authentication($auth);
  1067. *
  1068. * $public_container = $conn->get_container("public");
  1069. *
  1070. * # Enable ACL by Referrer
  1071. * $public_container->acl_referrer("Mozilla");
  1072. * </code>
  1073. *
  1074. * @returns boolean True if successful
  1075. * @throws CDNNotEnabledException CDN functionality not returned during auth
  1076. * @throws AuthenticationException if auth token is not valid/expired
  1077. * @throws InvalidResponseException unexpected response
  1078. */
  1079. function acl_user_agent($cdn_acl_user_agent="") {
  1080. if ($this->cfs_http->getCDNMUrl() == NULL) {
  1081. throw new CDNNotEnabledException(
  1082. "Authentication response did not indicate CDN availability");
  1083. }
  1084. list($status,$reason) =
  1085. $this->cfs_http->update_cdn_container($this->name,
  1086. $this->cdn_ttl,
  1087. $this->cdn_log_retention,
  1088. $cdn_acl_user_agent,
  1089. $this->cdn_acl_referrer
  1090. );
  1091. if (!in_array($status, array(202,404))) {
  1092. throw new InvalidResponseException(
  1093. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1094. }
  1095. $this->cdn_acl_user_agent = $cdn_acl_user_agent;
  1096. return True;
  1097. }
  1098. /**
  1099. * Enable ACL restriction by referer for this container.
  1100. *
  1101. * Example:
  1102. * <code>
  1103. * # ... authentication code excluded (see previous examples) ...
  1104. * #
  1105. * $conn = new CF_Authentication($auth);
  1106. *
  1107. * $public_container = $conn->get_container("public");
  1108. *
  1109. * # Enable Referrer
  1110. * $public_container->acl_referrer("http://www.example.com/gallery.php");
  1111. * </code>
  1112. *
  1113. * @returns boolean True if successful
  1114. * @throws CDNNotEnabledException CDN functionality not returned during auth
  1115. * @throws AuthenticationException if auth token is not valid/expired
  1116. * @throws InvalidResponseException unexpected response
  1117. */
  1118. function acl_referrer($cdn_acl_referrer="") {
  1119. if ($this->cfs_http->getCDNMUrl() == NULL) {
  1120. throw new CDNNotEnabledException(
  1121. "Authentication response did not indicate CDN availability");
  1122. }
  1123. list($status,$reason) =
  1124. $this->cfs_http->update_cdn_container($this->name,
  1125. $this->cdn_ttl,
  1126. $this->cdn_log_retention,
  1127. $this->cdn_acl_user_agent,
  1128. $cdn_acl_referrer
  1129. );
  1130. if (!in_array($status, array(202,404))) {
  1131. throw new InvalidResponseException(
  1132. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1133. }
  1134. $this->cdn_acl_referrer = $cdn_acl_referrer;
  1135. return True;
  1136. }
  1137. /**
  1138. * Enable log retention for this CDN container.
  1139. *
  1140. * Enable CDN log retention on the container. If enabled logs will
  1141. * be periodically (at unpredictable intervals) compressed and
  1142. * uploaded to a ".CDN_ACCESS_LOGS" container in the form of
  1143. * "container_name.YYYYMMDDHH-XXXX.gz". Requires CDN be enabled on
  1144. * the account.
  1145. *
  1146. * Example:
  1147. * <code>
  1148. * # ... authentication code excluded (see previous examples) ...
  1149. * #
  1150. * $conn = new CF_Authentication($auth);
  1151. *
  1152. * $public_container = $conn->get_container("public");
  1153. *
  1154. * # Enable logs retention.
  1155. * $public_container->log_retention(True);
  1156. * </code>
  1157. *
  1158. * @returns boolean True if successful
  1159. * @throws CDNNotEnabledException CDN functionality not returned during auth
  1160. * @throws AuthenticationException if auth token is not valid/expired
  1161. * @throws InvalidResponseException unexpected response
  1162. */
  1163. function log_retention($cdn_log_retention=False) {
  1164. if ($this->cfs_http->getCDNMUrl() == NULL) {
  1165. throw new CDNNotEnabledException(
  1166. "Authentication response did not indicate CDN availability");
  1167. }
  1168. list($status,$reason) =
  1169. $this->cfs_http->update_cdn_container($this->name,
  1170. $this->cdn_ttl,
  1171. $cdn_log_retention,
  1172. $this->cdn_acl_user_agent,
  1173. $this->cdn_acl_referrer
  1174. );
  1175. if (!in_array($status, array(202,404))) {
  1176. throw new InvalidResponseException(
  1177. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1178. }
  1179. $this->cdn_log_retention = $cdn_log_retention;
  1180. return True;
  1181. }
  1182. /**
  1183. * Disable the CDN sharing for this container
  1184. *
  1185. * Use this method to disallow distribution into the CDN of this Container's
  1186. * content.
  1187. *
  1188. * NOTE: Any content already cached in the CDN will continue to be served
  1189. * from its cache until the TTL expiration transpires. The default
  1190. * TTL is typically one day, so "privatizing" the Container will take
  1191. * up to 24 hours before the content is purged from the CDN cache.
  1192. *
  1193. * Example:
  1194. * <code>
  1195. * # ... authentication code excluded (see previous examples) ...
  1196. * #
  1197. * $conn = new CF_Authentication($auth);
  1198. *
  1199. * $public_container = $conn->get_container("public");
  1200. *
  1201. * # Disable CDN accessability
  1202. * # ... still cached up to a month based on previous example
  1203. * #
  1204. * $public_container->make_private();
  1205. * </code>
  1206. *
  1207. * @returns boolean True if successful
  1208. * @throws CDNNotEnabledException CDN functionality not returned during auth
  1209. * @throws AuthenticationException if auth token is not valid/expired
  1210. * @throws InvalidResponseException unexpected response
  1211. */
  1212. function make_private()
  1213. {
  1214. if ($this->cfs_http->getCDNMUrl() == NULL) {
  1215. throw new CDNNotEnabledException(
  1216. "Authentication response did not indicate CDN availability");
  1217. }
  1218. list($status,$reason) = $this->cfs_http->remove_cdn_container($this->name);
  1219. #if ($status == 401 && $this->_re_auth()) {
  1220. # return $this->make_private();
  1221. #}
  1222. if (!in_array($status, array(202,404))) {
  1223. throw new InvalidResponseException(
  1224. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1225. }
  1226. $this->cdn_enabled = False;
  1227. $this->cdn_ttl = NULL;
  1228. $this->cdn_uri = NULL;
  1229. $this->cdn_ssl_uri = NULL;
  1230. $this->cdn_streaming_uri - NULL;
  1231. $this->cdn_log_retention = NULL;
  1232. $this->cdn_acl_user_agent = NULL;
  1233. $this->cdn_acl_referrer = NULL;
  1234. return True;
  1235. }
  1236. /**
  1237. * Check if this Container is being publicly served via CDN
  1238. *
  1239. * Use this method to determine if the Container's content is currently
  1240. * available through the CDN.
  1241. *
  1242. * Example:
  1243. * <code>
  1244. * # ... authentication code excluded (see previous examples) ...
  1245. * #
  1246. * $conn = new CF_Authentication($auth);
  1247. *
  1248. * $public_container = $conn->get_container("public");
  1249. *
  1250. * # Display CDN accessability
  1251. * #
  1252. * $public_container->is_public() ? print "Yes" : print "No";
  1253. * </code>
  1254. *
  1255. * @returns boolean True if enabled, False otherwise
  1256. */
  1257. function is_public()
  1258. {
  1259. return $this->cdn_enabled == True ? True : False;
  1260. }
  1261. /**
  1262. * Create a new remote storage Object
  1263. *
  1264. * Return a new Object instance. If the remote storage Object exists,
  1265. * the instance's attributes are populated.
  1266. *
  1267. * Example:
  1268. * <code>
  1269. * # ... authentication code excluded (see previous examples) ...
  1270. * #
  1271. * $conn = new CF_Authentication($auth);
  1272. *
  1273. * $public_container = $conn->get_container("public");
  1274. *
  1275. * # This creates a local instance of a storage object but only creates
  1276. * # it in the storage system when the object's write() method is called.
  1277. * #
  1278. * $pic = $public_container->create_object("baby.jpg");
  1279. * </code>
  1280. *
  1281. * @param string $obj_name name of storage Object
  1282. * @return obj CF_Object instance
  1283. */
  1284. function create_object($obj_name=NULL)
  1285. {
  1286. return new CF_Object($this, $obj_name);
  1287. }
  1288. /**
  1289. * Return an Object instance for the remote storage Object
  1290. *
  1291. * Given a name, return a Object instance representing the
  1292. * remote storage object.
  1293. *
  1294. * Example:
  1295. * <code>
  1296. * # ... authentication code excluded (see previous examples) ...
  1297. * #
  1298. * $conn = new CF_Authentication($auth);
  1299. *
  1300. * $public_container = $conn->get_container("public");
  1301. *
  1302. * # This call only fetches header information and not the content of
  1303. * # the storage object. Use the Object's read() or stream() methods
  1304. * # to obtain the object's data.
  1305. * #
  1306. * $pic = $public_container->get_object("baby.jpg");
  1307. * </code>
  1308. *
  1309. * @param string $obj_name name of storage Object
  1310. * @return obj CF_Object instance
  1311. */
  1312. function get_object($obj_name=NULL)
  1313. {
  1314. return new CF_Object($this, $obj_name, True);
  1315. }
  1316. /**
  1317. * Return a list of Objects
  1318. *
  1319. * Return an array of strings listing the Object names in this Container.
  1320. *
  1321. * Example:
  1322. * <code>
  1323. * # ... authentication code excluded (see previous examples) ...
  1324. * #
  1325. * $images = $conn->get_container("my photos");
  1326. *
  1327. * # Grab the list of all storage objects
  1328. * #
  1329. * $all_objects = $images->list_objects();
  1330. *
  1331. * # Grab subsets of all storage objects
  1332. * #
  1333. * $first_ten = $images->list_objects(10);
  1334. *
  1335. * # Note the use of the previous result's last object name being
  1336. * # used as the 'marker' parameter to fetch the next 10 objects
  1337. * #
  1338. * $next_ten = $images->list_objects(10, $first_ten[count($first_ten)-1]);
  1339. *
  1340. * # Grab images starting with "birthday_party" and default limit/marker
  1341. * # to match all photos with that prefix
  1342. * #
  1343. * $prefixed = $images->list_objects(0, NULL, "birthday");
  1344. *
  1345. * # Assuming you have created the appropriate directory marker Objects,
  1346. * # you can traverse your pseudo-hierarchical containers
  1347. * # with the "path" argument.
  1348. * #
  1349. * $animals = $images->list_objects(0,NULL,NULL,"pictures/animals");
  1350. * $dogs = $images->list_objects(0,NULL,NULL,"pictures/animals/dogs");
  1351. * </code>
  1352. *
  1353. * @param int $limit <i>optional</i> only return $limit names
  1354. * @param int $marker <i>optional</i> subset of names starting at $marker
  1355. * @param string $prefix <i>optional</i> Objects whose names begin with $prefix
  1356. * @param string $path <i>optional</i> only return results under "pathname"
  1357. * @return array array of strings
  1358. * @throws InvalidResponseException unexpected response
  1359. */
  1360. function list_objects($limit=0, $marker=NULL, $prefix=NULL, $path=NULL)
  1361. {
  1362. list($status, $reason, $obj_list) =
  1363. $this->cfs_http->list_objects($this->name, $limit,
  1364. $marker, $prefix, $path);
  1365. #if ($status == 401 && $this->_re_auth()) {
  1366. # return $this->list_objects($limit, $marker, $prefix, $path);
  1367. #}
  1368. if ($status < 200 || $status > 299) {
  1369. throw new InvalidResponseException(
  1370. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1371. }
  1372. return $obj_list;
  1373. }
  1374. /**
  1375. * Return an array of Objects
  1376. *
  1377. * Return an array of Object instances in this Container.
  1378. *
  1379. * Example:
  1380. * <code>
  1381. * # ... authentication code excluded (see previous examples) ...
  1382. * #
  1383. * $images = $conn->get_container("my photos");
  1384. *
  1385. * # Grab the list of all storage objects
  1386. * #
  1387. * $all_objects = $images->get_objects();
  1388. *
  1389. * # Grab subsets of all storage objects
  1390. * #
  1391. * $first_ten = $images->get_objects(10);
  1392. *
  1393. * # Note the use of the previous result's last object name being
  1394. * # used as the 'marker' parameter to fetch the next 10 objects
  1395. * #
  1396. * $next_ten = $images->list_objects(10, $first_ten[count($first_ten)-1]);
  1397. *
  1398. * # Grab images starting with "birthday_party" and default limit/marker
  1399. * # to match all photos with that prefix
  1400. * #
  1401. * $prefixed = $images->get_objects(0, NULL, "birthday");
  1402. *
  1403. * # Assuming you have created the appropriate directory marker Objects,
  1404. * # you can traverse your pseudo-hierarchical containers
  1405. * # with the "path" argument.
  1406. * #
  1407. * $animals = $images->get_objects(0,NULL,NULL,"pictures/animals");
  1408. * $dogs = $images->get_objects(0,NULL,NULL,"pictures/animals/dogs");
  1409. * </code>
  1410. *
  1411. * @param int $limit <i>optional</i> only return $limit names
  1412. * @param int $marker <i>optional</i> subset of names starting at $marker
  1413. * @param string $prefix <i>optional</i> Objects whose names begin with $prefix
  1414. * @param string $path <i>optional</i> only return results under "pathname"
  1415. * @return array array of strings
  1416. * @throws InvalidResponseException unexpected response
  1417. */
  1418. function get_objects($limit=0, $marker=NULL, $prefix=NULL, $path=NULL)
  1419. {
  1420. list($status, $reason, $obj_array) =
  1421. $this->cfs_http->get_objects($this->name, $limit,
  1422. $marker, $prefix, $path);
  1423. #if ($status == 401 && $this->_re_auth()) {
  1424. # return $this->get_objects($limit, $marker, $prefix, $path);
  1425. #}
  1426. if ($status < 200 || $status > 299) {
  1427. throw new InvalidResponseException(
  1428. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1429. }
  1430. $objects = array();
  1431. foreach ($obj_array as $obj) {
  1432. $tmp = new CF_Object($this, $obj["name"], False, False);
  1433. $tmp->content_type = $obj["content_type"];
  1434. $tmp->content_length = (float) $obj["bytes"];
  1435. $tmp->set_etag($obj["hash"]);
  1436. $tmp->last_modified = $obj["last_modified"];
  1437. $objects[] = $tmp;
  1438. }
  1439. return $objects;
  1440. }
  1441. /**
  1442. * Copy a remote storage Object to a target Container
  1443. *
  1444. * Given an Object instance or name and a target Container instance or name, copy copies the remote Object
  1445. * and all associated metadata.
  1446. *
  1447. * Example:
  1448. * <code>
  1449. * # ... authentication code excluded (see previous examples) ...
  1450. * #
  1451. * $conn = new CF_Authentication($auth);
  1452. *
  1453. * $images = $conn->get_container("my photos");
  1454. *
  1455. * # Copy specific object
  1456. * #
  1457. * $images->copy_object_to("disco_dancing.jpg","container_target");
  1458. * </code>
  1459. *
  1460. * @param obj $obj name or instance of Object to copy
  1461. * @param obj $container_target name or instance of target Container
  1462. * @param string $dest_obj_name name of target object (optional - uses source name if omitted)
  1463. * @param array $metadata metadata array for new object (optional)
  1464. * @param array $headers header fields array for the new object (optional)
  1465. * @return boolean <kbd>true</kbd> if successfully copied
  1466. * @throws SyntaxException invalid Object/Container name
  1467. * @throws NoSuchObjectException remote Object does not exist
  1468. * @throws InvalidResponseException unexpected response
  1469. */
  1470. function copy_object_to($obj,$container_target,$dest_obj_name=NULL,$metadata=NULL,$headers=NULL)
  1471. {
  1472. $obj_name = NULL;
  1473. if (is_object($obj)) {
  1474. if (get_class($obj) == "CF_Object") {
  1475. $obj_name = $obj->name;
  1476. }
  1477. }
  1478. if (is_string($obj)) {
  1479. $obj_name = $obj;
  1480. }
  1481. if (!$obj_name) {
  1482. throw new SyntaxException("Object name not set.");
  1483. }
  1484. if ($dest_obj_name === NULL) {
  1485. $dest_obj_name = $obj_name;
  1486. }
  1487. $container_name_target = NULL;
  1488. if (is_object($container_target)) {
  1489. if (get_class($container_target) == "CF_Container") {
  1490. $container_name_target = $container_target->name;
  1491. }
  1492. }
  1493. if (is_string($container_target)) {
  1494. $container_name_target = $container_target;
  1495. }
  1496. if (!$container_name_target) {
  1497. throw new SyntaxException("Container name target not set.");
  1498. }
  1499. $status = $this->cfs_http->copy_object($obj_name,$dest_obj_name,$this->name,$container_name_target,$metadata,$headers);
  1500. if ($status == 404) {
  1501. $m = "Specified object '".$this->name."/".$obj_name;
  1502. $m.= "' did not exist as source to copy from or '".$container_name_target."' did not exist as target to copy to.";
  1503. throw new NoSuchObjectException($m);
  1504. }
  1505. if ($status < 200 || $status > 299) {
  1506. throw new InvalidResponseException(
  1507. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1508. }
  1509. return true;
  1510. }
  1511. /**
  1512. * Copy a remote storage Object from a source Container
  1513. *
  1514. * Given an Object instance or name and a source Container instance or name, copy copies the remote Object
  1515. * and all associated metadata.
  1516. *
  1517. * Example:
  1518. * <code>
  1519. * # ... authentication code excluded (see previous examples) ...
  1520. * #
  1521. * $conn = new CF_Authentication($auth);
  1522. *
  1523. * $images = $conn->get_container("my photos");
  1524. *
  1525. * # Copy specific object
  1526. * #
  1527. * $images->copy_object_from("disco_dancing.jpg","container_source");
  1528. * </code>
  1529. *
  1530. * @param obj $obj name or instance of Object to copy
  1531. * @param obj $container_source name or instance of source Container
  1532. * @param string $dest_obj_name name of target object (optional - uses source name if omitted)
  1533. * @param array $metadata metadata array for new object (optional)
  1534. * @param array $headers header fields array for the new object (optional)
  1535. * @return boolean <kbd>true</kbd> if successfully copied
  1536. * @throws SyntaxException invalid Object/Container name
  1537. * @throws NoSuchObjectException remote Object does not exist
  1538. * @throws InvalidResponseException unexpected response
  1539. */
  1540. function copy_object_from($obj,$container_source,$dest_obj_name=NULL,$metadata=NULL,$headers=NULL)
  1541. {
  1542. $obj_name = NULL;
  1543. if (is_object($obj)) {
  1544. if (get_class($obj) == "CF_Object") {
  1545. $obj_name = $obj->name;
  1546. }
  1547. }
  1548. if (is_string($obj)) {
  1549. $obj_name = $obj;
  1550. }
  1551. if (!$obj_name) {
  1552. throw new SyntaxException("Object name not set.");
  1553. }
  1554. if ($dest_obj_name === NULL) {
  1555. $dest_obj_name = $obj_name;
  1556. }
  1557. $container_name_source = NULL;
  1558. if (is_object($container_source)) {
  1559. if (get_class($container_source) == "CF_Container") {
  1560. $container_name_source = $container_source->name;
  1561. }
  1562. }
  1563. if (is_string($container_source)) {
  1564. $container_name_source = $container_source;
  1565. }
  1566. if (!$container_name_source) {
  1567. throw new SyntaxException("Container name source not set.");
  1568. }
  1569. $status = $this->cfs_http->copy_object($obj_name,$dest_obj_name,$container_name_source,$this->name,$metadata,$headers);
  1570. if ($status == 404) {
  1571. $m = "Specified object '".$container_name_source."/".$obj_name;
  1572. $m.= "' did not exist as source to copy from or '".$this->name."/".$obj_name."' did not exist as target to copy to.";
  1573. throw new NoSuchObjectException($m);
  1574. }
  1575. if ($status < 200 || $status > 299) {
  1576. throw new InvalidResponseException(
  1577. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1578. }
  1579. return true;
  1580. }
  1581. /**
  1582. * Move a remote storage Object to a target Container
  1583. *
  1584. * Given an Object instance or name and a target Container instance or name, move copies the remote Object
  1585. * and all associated metadata and deletes the source Object afterwards
  1586. *
  1587. * Example:
  1588. * <code>
  1589. * # ... authentication code excluded (see previous examples) ...
  1590. * #
  1591. * $conn = new CF_Authentication($auth);
  1592. *
  1593. * $images = $conn->get_container("my photos");
  1594. *
  1595. * # Move specific object
  1596. * #
  1597. * $images->move_object_to("disco_dancing.jpg","container_target");
  1598. * </code>
  1599. *
  1600. * @param obj $obj name or instance of Object to move
  1601. * @param obj $container_target name or instance of target Container
  1602. * @param string $dest_obj_name name of target object (optional - uses source name if omitted)
  1603. * @param array $metadata metadata array for new object (optional)
  1604. * @param array $headers header fields array for the new object (optional)
  1605. * @return boolean <kbd>true</kbd> if successfully moved
  1606. * @throws SyntaxException invalid Object/Container name
  1607. * @throws NoSuchObjectException remote Object does not exist
  1608. * @throws InvalidResponseException unexpected response
  1609. */
  1610. function move_object_to($obj,$container_target,$dest_obj_name=NULL,$metadata=NULL,$headers=NULL)
  1611. {
  1612. $retVal = false;
  1613. if(self::copy_object_to($obj,$container_target,$dest_obj_name,$metadata,$headers)) {
  1614. $retVal = self::delete_object($obj,$this->name);
  1615. }
  1616. return $retVal;
  1617. }
  1618. /**
  1619. * Move a remote storage Object from a source Container
  1620. *
  1621. * Given an Object instance or name and a source Container instance or name, move copies the remote Object
  1622. * and all associated metadata and deletes the source Object afterwards
  1623. *
  1624. * Example:
  1625. * <code>
  1626. * # ... authentication code excluded (see previous examples) ...
  1627. * #
  1628. * $conn = new CF_Authentication($auth);
  1629. *
  1630. * $images = $conn->get_container("my photos");
  1631. *
  1632. * # Move specific object
  1633. * #
  1634. * $images->move_object_from("disco_dancing.jpg","container_target");
  1635. * </code>
  1636. *
  1637. * @param obj $obj name or instance of Object to move
  1638. * @param obj $container_source name or instance of target Container
  1639. * @param string $dest_obj_name name of target object (optional - uses source name if omitted)
  1640. * @param array $metadata metadata array for new object (optional)
  1641. * @param array $headers header fields array for the new object (optional)
  1642. * @return boolean <kbd>true</kbd> if successfully moved
  1643. * @throws SyntaxException invalid Object/Container name
  1644. * @throws NoSuchObjectException remote Object does not exist
  1645. * @throws InvalidResponseException unexpected response
  1646. */
  1647. function move_object_from($obj,$container_source,$dest_obj_name=NULL,$metadata=NULL,$headers=NULL)
  1648. {
  1649. $retVal = false;
  1650. if(self::copy_object_from($obj,$container_source,$dest_obj_name,$metadata,$headers)) {
  1651. $retVal = self::delete_object($obj,$container_source);
  1652. }
  1653. return $retVal;
  1654. }
  1655. /**
  1656. * Delete a remote storage Object
  1657. *
  1658. * Given an Object instance or name, permanently remove the remote Object
  1659. * and all associated metadata.
  1660. *
  1661. * Example:
  1662. * <code>
  1663. * # ... authentication code excluded (see previous examples) ...
  1664. * #
  1665. * $conn = new CF_Authentication($auth);
  1666. *
  1667. * $images = $conn->get_container("my photos");
  1668. *
  1669. * # Delete specific object
  1670. * #
  1671. * $images->delete_object("disco_dancing.jpg");
  1672. * </code>
  1673. *
  1674. * @param obj $obj name or instance of Object to delete
  1675. * @param obj $container name or instance of Container in which the object resides (optional)
  1676. * @return boolean <kbd>True</kbd> if successfully removed
  1677. * @throws SyntaxException invalid Object name
  1678. * @throws NoSuchObjectException remote Object does not exist
  1679. * @throws InvalidResponseException unexpected response
  1680. */
  1681. function delete_object($obj,$container=NULL)
  1682. {
  1683. $obj_name = NULL;
  1684. if (is_object($obj)) {
  1685. if (get_class($obj) == "CF_Object") {
  1686. $obj_name = $obj->name;
  1687. }
  1688. }
  1689. if (is_string($obj)) {
  1690. $obj_name = $obj;
  1691. }
  1692. if (!$obj_name) {
  1693. throw new SyntaxException("Object name not set.");
  1694. }
  1695. $container_name = NULL;
  1696. if($container === NULL) {
  1697. $container_name = $this->name;
  1698. }
  1699. else {
  1700. if (is_object($container)) {
  1701. if (get_class($container) == "CF_Container") {
  1702. $container_name = $container->name;
  1703. }
  1704. }
  1705. if (is_string($container)) {
  1706. $container_name = $container;
  1707. }
  1708. if (!$container_name) {
  1709. throw new SyntaxException("Container name source not set.");
  1710. }
  1711. }
  1712. $status = $this->cfs_http->delete_object($container_name, $obj_name);
  1713. #if ($status == 401 && $this->_re_auth()) {
  1714. # return $this->delete_object($obj);
  1715. #}
  1716. if ($status == 404) {
  1717. $m = "Specified object '".$container_name."/".$obj_name;
  1718. $m.= "' did not exist to delete.";
  1719. throw new NoSuchObjectException($m);
  1720. }
  1721. if ($status != 204) {
  1722. throw new InvalidResponseException(
  1723. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1724. }
  1725. return True;
  1726. }
  1727. /**
  1728. * Helper function to create "path" elements for a given Object name
  1729. *
  1730. * Given an Object whos name contains '/' path separators, this function
  1731. * will create the "directory marker" Objects of one byte with the
  1732. * Content-Type of "application/directory".
  1733. *
  1734. * It assumes the last element of the full path is the "real" Object
  1735. * and does NOT create a remote storage Object for that last element.
  1736. */
  1737. function create_paths($path_name)
  1738. {
  1739. if ($path_name[0] == '/') {
  1740. $path_name = mb_substr($path_name, 0, 1);
  1741. }
  1742. $elements = explode('/', $path_name, -1);
  1743. $build_path = "";
  1744. foreach ($elements as $idx => $val) {
  1745. if (!$build_path) {
  1746. $build_path = $val;
  1747. } else {
  1748. $build_path .= "/" . $val;
  1749. }
  1750. $obj = new CF_Object($this, $build_path);
  1751. $obj->content_type = "application/directory";
  1752. $obj->write(".", 1);
  1753. }
  1754. }
  1755. /**
  1756. * Internal method to grab CDN/Container info if appropriate to do so
  1757. *
  1758. * @throws InvalidResponseException unexpected response
  1759. */
  1760. private function _cdn_initialize()
  1761. {
  1762. list($status, $reason, $cdn_enabled, $cdn_ssl_uri, $cdn_streaming_uri, $cdn_uri, $cdn_ttl,
  1763. $cdn_log_retention, $cdn_acl_user_agent, $cdn_acl_referrer) =
  1764. $this->cfs_http->head_cdn_container($this->name);
  1765. #if ($status == 401 && $this->_re_auth()) {
  1766. # return $this->_cdn_initialize();
  1767. #}
  1768. if (!in_array($status, array(204,404))) {
  1769. throw new InvalidResponseException(
  1770. "Invalid response (".$status."): ".$this->cfs_http->get_error());
  1771. }
  1772. $this->cdn_enabled = $cdn_enabled;
  1773. $this->cdn_streaming_uri = $cdn_streaming_uri;
  1774. $this->cdn_ssl_uri = $cdn_ssl_uri;
  1775. $this->cdn_uri = $cdn_uri;
  1776. $this->cdn_ttl = $cdn_ttl;
  1777. $this->cdn_log_retention = $cdn_log_retention;
  1778. $this->cdn_acl_user_agent = $cdn_acl_user_agent;
  1779. $this->cdn_acl_referrer = $cdn_acl_referrer;
  1780. }
  1781. #private function _re_auth()
  1782. #{
  1783. # $new_auth = new CF_Authentication(
  1784. # $this->cfs_auth->username,
  1785. # $this->cfs_auth->api_key,
  1786. # $this->cfs_auth->auth_host,
  1787. # $this->cfs_auth->account);
  1788. # $new_auth->authenticate();
  1789. # $this->cfs_auth = $new_auth;
  1790. # $this->cfs_http->setCFAuth($this->cfs_auth);
  1791. # return True;
  1792. #}
  1793. }
  1794. /**
  1795. * Object operations
  1796. *
  1797. * An Object is analogous to a file on a conventional filesystem. You can
  1798. * read data from, or write data to your Objects. You can also associate
  1799. * arbitrary metadata with them.
  1800. *
  1801. * @package php-cloudfiles
  1802. */
  1803. class CF_Object
  1804. {
  1805. public $container;
  1806. public $name;
  1807. public $last_modified;
  1808. public $content_type;
  1809. public $content_length;
  1810. public $metadata;
  1811. public $headers;
  1812. public $manifest;
  1813. private $etag;
  1814. /**
  1815. * Class constructor
  1816. *
  1817. * @param obj $container CF_Container instance
  1818. * @param string $name name of Object
  1819. * @param boolean $force_exists if set, throw an error if Object doesn't exist
  1820. */
  1821. function __construct(&$container, $name, $force_exists=False, $dohead=True)
  1822. {
  1823. if ($name[0] == "/") {
  1824. $r = "Object name '".$name;
  1825. $r .= "' cannot contain begin with a '/' character.";
  1826. throw new SyntaxException($r);
  1827. }
  1828. if (strlen($name) > MAX_OBJECT_NAME_LEN) {
  1829. throw new SyntaxException("Object name exceeds "
  1830. . "maximum allowed length.");
  1831. }
  1832. $this->container = $container;
  1833. $this->name = $name;
  1834. $this->etag = NULL;
  1835. $this->_etag_override = False;
  1836. $this->last_modified = NULL;
  1837. $this->content_type = NULL;
  1838. $this->content_length = 0;
  1839. $this->metadata = array();
  1840. $this->headers = array();
  1841. $this->manifest = NULL;
  1842. if ($dohead) {
  1843. if (!$this->_initialize() && $force_exists) {
  1844. throw new NoSuchObjectException("No such object '".$name."'");
  1845. }
  1846. }
  1847. }
  1848. /**
  1849. * String representation of Object
  1850. *
  1851. * Pretty print the Object's location and name
  1852. *
  1853. * @return string Object information
  1854. */
  1855. function __toString()
  1856. {
  1857. return $this->container->name . "/" . $this->name;
  1858. }
  1859. /**
  1860. * Internal check to get the proper mimetype.
  1861. *
  1862. * This function would go over the available PHP methods to get
  1863. * the MIME type.
  1864. *
  1865. * By default it will try to use the PHP fileinfo library which is
  1866. * available from PHP 5.3 or as an PECL extension
  1867. * (http://pecl.php.net/package/Fileinfo).
  1868. *
  1869. * It will get the magic file by default from the system wide file
  1870. * which is usually available in /usr/share/magic on Unix or try
  1871. * to use the file specified in the source directory of the API
  1872. * (share directory).
  1873. *
  1874. * if fileinfo is not available it will try to use the internal
  1875. * mime_content_type function.
  1876. *
  1877. * @param string $handle name of file or buffer to guess the type from
  1878. * @return boolean <kbd>True</kbd> if successful
  1879. * @throws BadContentTypeException
  1880. */
  1881. function _guess_content_type($handle) {
  1882. if ($this->content_type)
  1883. return;
  1884. if (function_exists("finfo_open")) {
  1885. $local_magic = dirname(__FILE__) . "/share/magic";
  1886. $finfo = @finfo_open(FILEINFO_MIME, $local_magic);
  1887. if (!$finfo)
  1888. $finfo = @finfo_open(FILEINFO_MIME);
  1889. if ($finfo) {
  1890. if (is_file((string)$handle))
  1891. $ct = @finfo_file($finfo, $handle);
  1892. else
  1893. $ct = @finfo_buffer($finfo, $handle);
  1894. /* PHP 5.3 fileinfo display extra information like
  1895. charset so we remove everything after the ; since
  1896. we are not into that stuff */
  1897. if ($ct) {
  1898. $extra_content_type_info = strpos($ct, "; ");
  1899. if ($extra_content_type_info)
  1900. $ct = substr($ct, 0, $extra_content_type_info);
  1901. }
  1902. if ($ct && $ct != 'application/octet-stream')
  1903. $this->content_type = $ct;
  1904. @finfo_close($finfo);
  1905. }
  1906. }
  1907. if (!$this->content_type && (string)is_file($handle) && function_exists("mime_content_type")) {
  1908. $this->content_type = @mime_content_type($handle);
  1909. }
  1910. if (!$this->content_type) {
  1911. throw new BadContentTypeException("Required Content-Type not set");
  1912. }
  1913. return True;
  1914. }
  1915. /**
  1916. * String representation of the Object's public URI
  1917. *
  1918. * A string representing the Object's public URI assuming that it's
  1919. * parent Container is CDN-enabled.
  1920. *
  1921. * Example:
  1922. * <code>
  1923. * # ... authentication/connection/container code excluded
  1924. * # ... see previous examples
  1925. *
  1926. * # Print out the Object's CDN URI (if it has one) in an HTML img-tag
  1927. * #
  1928. * print "<img src='$pic->public_uri()' />\n";
  1929. * </code>
  1930. *
  1931. * @return string Object's public URI or NULL
  1932. */
  1933. function public_uri()
  1934. {
  1935. if ($this->container->cdn_enabled) {
  1936. return $this->container->cdn_uri . "/" . $this->name;
  1937. }
  1938. return NULL;
  1939. }
  1940. /**
  1941. * String representation of the Object's public SSL URI
  1942. *
  1943. * A string representing the Object's public SSL URI assuming that it's
  1944. * parent Container is CDN-enabled.
  1945. *
  1946. * Example:
  1947. * <code>
  1948. * # ... authentication/connection/container code excluded
  1949. * # ... see previous examples
  1950. *
  1951. * # Print out the Object's CDN SSL URI (if it has one) in an HTML img-tag
  1952. * #
  1953. * print "<img src='$pic->public_ssl_uri()' />\n";
  1954. * </code>
  1955. *
  1956. * @return string Object's public SSL URI or NULL
  1957. */
  1958. function public_ssl_uri()
  1959. {
  1960. if ($this->container->cdn_enabled) {
  1961. return $this->container->cdn_ssl_uri . "/" . $this->name;
  1962. }
  1963. return NULL;
  1964. }
  1965. /**
  1966. * String representation of the Object's public Streaming URI
  1967. *
  1968. * A string representing the Object's public Streaming URI assuming that it's
  1969. * parent Container is CDN-enabled.
  1970. *
  1971. * Example:
  1972. * <code>
  1973. * # ... authentication/connection/container code excluded
  1974. * # ... see previous examples
  1975. *
  1976. * # Print out the Object's CDN Streaming URI (if it has one) in an HTML img-tag
  1977. * #
  1978. * print "<img src='$pic->public_streaming_uri()' />\n";
  1979. * </code>
  1980. *
  1981. * @return string Object's public Streaming URI or NULL
  1982. */
  1983. function public_streaming_uri()
  1984. {
  1985. if ($this->container->cdn_enabled) {
  1986. return $this->container->cdn_streaming_uri . "/" . $this->name;
  1987. }
  1988. return NULL;
  1989. }
  1990. /**
  1991. * Read the remote Object's data
  1992. *
  1993. * Returns the Object's data. This is useful for smaller Objects such
  1994. * as images or office documents. Object's with larger content should use
  1995. * the stream() method below.
  1996. *
  1997. * Pass in $hdrs array to set specific custom HTTP headers such as
  1998. * If-Match, If-None-Match, If-Modified-Since, Range, etc.
  1999. *
  2000. * Example:
  2001. * <code>
  2002. * # ... authentication/connection/container code excluded
  2003. * # ... see previous examples
  2004. *
  2005. * $my_docs = $conn->get_container("documents");
  2006. * $doc = $my_docs->get_object("README");
  2007. * $data = $doc->read(); # read image content into a string variable
  2008. * print $data;
  2009. *
  2010. * # Or see stream() below for a different example.
  2011. * #
  2012. * </code>
  2013. *
  2014. * @param array $hdrs user-defined headers (Range, If-Match, etc.)
  2015. * @return string Object's data
  2016. * @throws InvalidResponseException unexpected response
  2017. */
  2018. function read($hdrs=array())
  2019. {
  2020. list($status, $reason, $data) =
  2021. $this->container->cfs_http->get_object_to_string($this, $hdrs);
  2022. #if ($status == 401 && $this->_re_auth()) {
  2023. # return $this->read($hdrs);
  2024. #}
  2025. if (($status < 200) || ($status > 299
  2026. && $status != 412 && $status != 304)) {
  2027. throw new InvalidResponseException("Invalid response (".$status."): "
  2028. . $this->container->cfs_http->get_error());
  2029. }
  2030. return $data;
  2031. }
  2032. /**
  2033. * Streaming read of Object's data
  2034. *
  2035. * Given an open PHP resource (see PHP's fopen() method), fetch the Object's
  2036. * data and write it to the open resource handle. This is useful for
  2037. * streaming an Object's content to the browser (videos, images) or for
  2038. * fetching content to a local file.
  2039. *
  2040. * Pass in $hdrs array to set specific custom HTTP headers such as
  2041. * If-Match, If-None-Match, If-Modified-Since, Range, etc.
  2042. *
  2043. * Example:
  2044. * <code>
  2045. * # ... authentication/connection/container code excluded
  2046. * # ... see previous examples
  2047. *
  2048. * # Assuming this is a web script to display the README to the
  2049. * # user's browser:
  2050. * #
  2051. * <?php
  2052. * // grab README from storage system
  2053. * //
  2054. * $my_docs = $conn->get_container("documents");
  2055. * $doc = $my_docs->get_object("README");
  2056. *
  2057. * // Hand it back to user's browser with appropriate content-type
  2058. * //
  2059. * header("Content-Type: " . $doc->content_type);
  2060. * $output = fopen("php://output", "w");
  2061. * $doc->stream($output); # stream object content to PHP's output buffer
  2062. * fclose($output);
  2063. * ?>
  2064. *
  2065. * # See read() above for a more simple example.
  2066. * #
  2067. * </code>
  2068. *
  2069. * @param resource $fp open resource for writing data to
  2070. * @param array $hdrs user-defined headers (Range, If-Match, etc.)
  2071. * @return string Object's data
  2072. * @throws InvalidResponseException unexpected response
  2073. */
  2074. function stream(&$fp, $hdrs=array())
  2075. {
  2076. list($status, $reason) =
  2077. $this->container->cfs_http->get_object_to_stream($this,$fp,$hdrs);
  2078. #if ($status == 401 && $this->_re_auth()) {
  2079. # return $this->stream($fp, $hdrs);
  2080. #}
  2081. if (($status < 200) || ($status > 299
  2082. && $status != 412 && $status != 304)) {
  2083. throw new InvalidResponseException("Invalid response (".$status."): "
  2084. .$reason);
  2085. }
  2086. return True;
  2087. }
  2088. /**
  2089. * Store new Object metadata
  2090. *
  2091. * Write's an Object's metadata to the remote Object. This will overwrite
  2092. * an prior Object metadata.
  2093. *
  2094. * Example:
  2095. * <code>
  2096. * # ... authentication/connection/container code excluded
  2097. * # ... see previous examples
  2098. *
  2099. * $my_docs = $conn->get_container("documents");
  2100. * $doc = $my_docs->get_object("README");
  2101. *
  2102. * # Define new metadata for the object
  2103. * #
  2104. * $doc->metadata = array(
  2105. * "Author" => "EJ",
  2106. * "Subject" => "How to use the PHP tests",
  2107. * "Version" => "1.2.2"
  2108. * );
  2109. *
  2110. * # Define additional headers for the object
  2111. * #
  2112. * $doc->headers = array(
  2113. * "Content-Disposition" => "attachment",
  2114. * );
  2115. *
  2116. * # Push the new metadata up to the storage system
  2117. * #
  2118. * $doc->sync_metadata();
  2119. * </code>
  2120. *
  2121. * @return boolean <kbd>True</kbd> if successful, <kbd>False</kbd> otherwise
  2122. * @throws InvalidResponseException unexpected response
  2123. */
  2124. function sync_metadata()
  2125. {
  2126. if (!empty($this->metadata) || !empty($this->headers) || $this->manifest) {
  2127. $status = $this->container->cfs_http->update_object($this);
  2128. #if ($status == 401 && $this->_re_auth()) {
  2129. # return $this->sync_metadata();
  2130. #}
  2131. if ($status != 202) {
  2132. throw new InvalidResponseException("Invalid response ("
  2133. .$status."): ".$this->container->cfs_http->get_error());
  2134. }
  2135. return True;
  2136. }
  2137. return False;
  2138. }
  2139. /**
  2140. * Store new Object manifest
  2141. *
  2142. * Write's an Object's manifest to the remote Object. This will overwrite
  2143. * an prior Object manifest.
  2144. *
  2145. * Example:
  2146. * <code>
  2147. * # ... authentication/connection/container code excluded
  2148. * # ... see previous examples
  2149. *
  2150. * $my_docs = $conn->get_container("documents");
  2151. * $doc = $my_docs->get_object("README");
  2152. *
  2153. * # Define new manifest for the object
  2154. * #
  2155. * $doc->manifest = "container/prefix";
  2156. *
  2157. * # Push the new manifest up to the storage system
  2158. * #
  2159. * $doc->sync_manifest();
  2160. * </code>
  2161. *
  2162. * @return boolean <kbd>True</kbd> if successful, <kbd>False</kbd> otherwise
  2163. * @throws InvalidResponseException unexpected response
  2164. */
  2165. function sync_manifest()
  2166. {
  2167. return $this->sync_metadata();
  2168. }
  2169. /**
  2170. * Upload Object's data to Cloud Files
  2171. *
  2172. * Write data to the remote Object. The $data argument can either be a
  2173. * PHP resource open for reading (see PHP's fopen() method) or an in-memory
  2174. * variable. If passing in a PHP resource, you must also include the $bytes
  2175. * parameter.
  2176. *
  2177. * Example:
  2178. * <code>
  2179. * # ... authentication/connection/container code excluded
  2180. * # ... see previous examples
  2181. *
  2182. * $my_docs = $conn->get_container("documents");
  2183. * $doc = $my_docs->get_object("README");
  2184. *
  2185. * # Upload placeholder text in my README
  2186. * #
  2187. * $doc->write("This is just placeholder text for now...");
  2188. * </code>
  2189. *
  2190. * @param string|resource $data string or open resource
  2191. * @param float $bytes amount of data to upload (required for resources)
  2192. * @param boolean $verify generate, send, and compare MD5 checksums
  2193. * @return boolean <kbd>True</kbd> when data uploaded successfully
  2194. * @throws SyntaxException missing required parameters
  2195. * @throws BadContentTypeException if no Content-Type was/could be set
  2196. * @throws MisMatchedChecksumException $verify is set and checksums unequal
  2197. * @throws InvalidResponseException unexpected response
  2198. */
  2199. function write($data=NULL, $bytes=0, $verify=True)
  2200. {
  2201. if (!$data && !is_string($data)) {
  2202. throw new SyntaxException("Missing data source.");
  2203. }
  2204. if ($bytes > MAX_OBJECT_SIZE) {
  2205. throw new SyntaxException("Bytes exceeds maximum object size.");
  2206. }
  2207. if ($verify) {
  2208. if (!$this->_etag_override) {
  2209. $this->etag = $this->compute_md5sum($data);
  2210. }
  2211. } else {
  2212. $this->etag = NULL;
  2213. }
  2214. $close_fh = False;
  2215. if (!is_resource($data)) {
  2216. # A hack to treat string data as a file handle. php://memory feels
  2217. # like a better option, but it seems to break on Windows so use
  2218. # a temporary file instead.
  2219. #
  2220. $fp = fopen("php://temp", "wb+");
  2221. #$fp = fopen("php://memory", "wb+");
  2222. fwrite($fp, $data, strlen($data));
  2223. rewind($fp);
  2224. $close_fh = True;
  2225. $this->content_length = (float) strlen($data);
  2226. if ($this->content_length > MAX_OBJECT_SIZE) {
  2227. throw new SyntaxException("Data exceeds maximum object size");
  2228. }
  2229. $ct_data = substr($data, 0, 64);
  2230. } else {
  2231. $this->content_length = $bytes;
  2232. $fp = $data;
  2233. $ct_data = fread($data, 64);
  2234. rewind($data);
  2235. }
  2236. $this->_guess_content_type($ct_data);
  2237. list($status, $reason, $etag) =
  2238. $this->container->cfs_http->put_object($this, $fp);
  2239. #if ($status == 401 && $this->_re_auth()) {
  2240. # return $this->write($data, $bytes, $verify);
  2241. #}
  2242. if ($status == 412) {
  2243. if ($close_fh) { fclose($fp); }
  2244. throw new SyntaxException("Missing Content-Type header");
  2245. }
  2246. if ($status == 422) {
  2247. if ($close_fh) { fclose($fp); }
  2248. throw new MisMatchedChecksumException(
  2249. "Supplied and computed checksums do not match.");
  2250. }
  2251. if ($status != 201) {
  2252. if ($close_fh) { fclose($fp); }
  2253. throw new InvalidResponseException("Invalid response (".$status."): "
  2254. . $this->container->cfs_http->get_error());
  2255. }
  2256. if (!$verify) {
  2257. $this->etag = $etag;
  2258. }
  2259. if ($close_fh) { fclose($fp); }
  2260. return True;
  2261. }
  2262. /**
  2263. * Upload Object data from local filename
  2264. *
  2265. * This is a convenience function to upload the data from a local file. A
  2266. * True value for $verify will cause the method to compute the Object's MD5
  2267. * checksum prior to uploading.
  2268. *
  2269. * Example:
  2270. * <code>
  2271. * # ... authentication/connection/container code excluded
  2272. * # ... see previous examples
  2273. *
  2274. * $my_docs = $conn->get_container("documents");
  2275. * $doc = $my_docs->get_object("README");
  2276. *
  2277. * # Upload my local README's content
  2278. * #
  2279. * $doc->load_from_filename("/home/ej/cloudfiles/readme");
  2280. * </code>
  2281. *
  2282. * @param string $filename full path to local file
  2283. * @param boolean $verify enable local/remote MD5 checksum validation
  2284. * @return boolean <kbd>True</kbd> if data uploaded successfully
  2285. * @throws SyntaxException missing required parameters
  2286. * @throws BadContentTypeException if no Content-Type was/could be set
  2287. * @throws MisMatchedChecksumException $verify is set and checksums unequal
  2288. * @throws InvalidResponseException unexpected response
  2289. * @throws IOException error opening file
  2290. */
  2291. function load_from_filename($filename, $verify=True)
  2292. {
  2293. $fp = @fopen($filename, "r");
  2294. if (!$fp) {
  2295. throw new IOException("Could not open file for reading: ".$filename);
  2296. }
  2297. clearstatcache();
  2298. $size = (float) sprintf("%u", filesize($filename));
  2299. if ($size > MAX_OBJECT_SIZE) {
  2300. throw new SyntaxException("File size exceeds maximum object size.");
  2301. }
  2302. $this->_guess_content_type($filename);
  2303. $this->write($fp, $size, $verify);
  2304. fclose($fp);
  2305. return True;
  2306. }
  2307. /**
  2308. * Save Object's data to local filename
  2309. *
  2310. * Given a local filename, the Object's data will be written to the newly
  2311. * created file.
  2312. *
  2313. * Example:
  2314. * <code>
  2315. * # ... authentication/connection/container code excluded
  2316. * # ... see previous examples
  2317. *
  2318. * # Whoops! I deleted my local README, let me download/save it
  2319. * #
  2320. * $my_docs = $conn->get_container("documents");
  2321. * $doc = $my_docs->get_object("README");
  2322. *
  2323. * $doc->save_to_filename("/home/ej/cloudfiles/readme.restored");
  2324. * </code>
  2325. *
  2326. * @param string $filename name of local file to write data to
  2327. * @return boolean <kbd>True</kbd> if successful
  2328. * @throws IOException error opening file
  2329. * @throws InvalidResponseException unexpected response
  2330. */
  2331. function save_to_filename($filename)
  2332. {
  2333. $fp = @fopen($filename, "wb");
  2334. if (!$fp) {
  2335. throw new IOException("Could not open file for writing: ".$filename);
  2336. }
  2337. $result = $this->stream($fp);
  2338. fclose($fp);
  2339. return $result;
  2340. }
  2341. /**
  2342. * Purge this Object from CDN Cache.
  2343. * Example:
  2344. * <code>
  2345. * # ... authentication code excluded (see previous examples) ...
  2346. * #
  2347. * $conn = new CF_Authentication($auth);
  2348. * $container = $conn->get_container("cdn_enabled");
  2349. * $obj = $container->get_object("object");
  2350. * $obj->purge_from_cdn("user@domain.com");
  2351. * # or
  2352. * $obj->purge_from_cdn();
  2353. * # or
  2354. * $obj->purge_from_cdn("user1@domain.com,user2@domain.com");
  2355. * @returns boolean True if successful
  2356. * @throws CDNNotEnabledException if CDN Is not enabled on this connection
  2357. * @throws InvalidResponseException if the response expected is not returned
  2358. */
  2359. function purge_from_cdn($email=null)
  2360. {
  2361. if (!$this->container->cfs_http->getCDNMUrl())
  2362. {
  2363. throw new CDNNotEnabledException(
  2364. "Authentication response did not indicate CDN availability");
  2365. }
  2366. $status = $this->container->cfs_http->purge_from_cdn($this->container->name . "/" . $this->name, $email);
  2367. if ($status < 199 or $status > 299) {
  2368. throw new InvalidResponseException(
  2369. "Invalid response (".$status."): ".$this->container->cfs_http->get_error());
  2370. }
  2371. return True;
  2372. }
  2373. /**
  2374. * Set Object's MD5 checksum
  2375. *
  2376. * Manually set the Object's ETag. Including the ETag is mandatory for
  2377. * Cloud Files to perform end-to-end verification. Omitting the ETag forces
  2378. * the user to handle any data integrity checks.
  2379. *
  2380. * @param string $etag MD5 checksum hexidecimal string
  2381. */
  2382. function set_etag($etag)
  2383. {
  2384. $this->etag = $etag;
  2385. $this->_etag_override = True;
  2386. }
  2387. /**
  2388. * Object's MD5 checksum
  2389. *
  2390. * Accessor method for reading Object's private ETag attribute.
  2391. *
  2392. * @return string MD5 checksum hexidecimal string
  2393. */
  2394. function getETag()
  2395. {
  2396. return $this->etag;
  2397. }
  2398. /**
  2399. * Compute the MD5 checksum
  2400. *
  2401. * Calculate the MD5 checksum on either a PHP resource or data. The argument
  2402. * may either be a local filename, open resource for reading, or a string.
  2403. *
  2404. * <b>WARNING:</b> if you are uploading a big file over a stream
  2405. * it could get very slow to compute the md5 you probably want to
  2406. * set the $verify parameter to False in the write() method and
  2407. * compute yourself the md5 before if you have it.
  2408. *
  2409. * @param filename|obj|string $data filename, open resource, or string
  2410. * @return string MD5 checksum hexidecimal string
  2411. */
  2412. function compute_md5sum(&$data)
  2413. {
  2414. if (function_exists("hash_init") && is_resource($data)) {
  2415. $ctx = hash_init('md5');
  2416. while (!feof($data)) {
  2417. $buffer = fgets($data, 65536);
  2418. hash_update($ctx, $buffer);
  2419. }
  2420. $md5 = hash_final($ctx, false);
  2421. rewind($data);
  2422. } elseif ((string)is_file($data)) {
  2423. $md5 = md5_file($data);
  2424. } else {
  2425. $md5 = md5($data);
  2426. }
  2427. return $md5;
  2428. }
  2429. /**
  2430. * PRIVATE: fetch information about the remote Object if it exists
  2431. */
  2432. private function _initialize()
  2433. {
  2434. list($status, $reason, $etag, $last_modified, $content_type,
  2435. $content_length, $metadata, $manifest, $headers) =
  2436. $this->container->cfs_http->head_object($this);
  2437. #if ($status == 401 && $this->_re_auth()) {
  2438. # return $this->_initialize();
  2439. #}
  2440. if ($status == 404) {
  2441. return False;
  2442. }
  2443. if ($status < 200 || $status > 299) {
  2444. throw new InvalidResponseException("Invalid response (".$status."): "
  2445. . $this->container->cfs_http->get_error());
  2446. }
  2447. $this->etag = $etag;
  2448. $this->last_modified = $last_modified;
  2449. $this->content_type = $content_type;
  2450. $this->content_length = $content_length;
  2451. $this->metadata = $metadata;
  2452. $this->headers = $headers;
  2453. $this->manifest = $manifest;
  2454. return True;
  2455. }
  2456. #private function _re_auth()
  2457. #{
  2458. # $new_auth = new CF_Authentication(
  2459. # $this->cfs_auth->username,
  2460. # $this->cfs_auth->api_key,
  2461. # $this->cfs_auth->auth_host,
  2462. # $this->cfs_auth->account);
  2463. # $new_auth->authenticate();
  2464. # $this->container->cfs_auth = $new_auth;
  2465. # $this->container->cfs_http->setCFAuth($this->cfs_auth);
  2466. # return True;
  2467. #}
  2468. }
  2469. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  2470. /*
  2471. * Local variables:
  2472. * tab-width: 4
  2473. * c-basic-offset: 4
  2474. * c-hanging-comment-ender-p: nil
  2475. * End:
  2476. */
  2477. ?>