PageRenderTime 65ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/blog/wp-content/plugins/cdn-tools-mod/cdn_classes/cloudfiles/cloudfiles.php

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