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

/app/lib/core/Zend/Service/WindowsAzure/Storage/Blob.php

https://bitbucket.org/Sinfin/pawtucket
PHP | 2001 lines | 1188 code | 198 blank | 615 comment | 292 complexity | bfc3a00361d0401d4c81e2225b6fd36b MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Service_WindowsAzure
  17. * @subpackage Storage
  18. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://todo name_todo
  20. * @version $Id$
  21. */
  22. /**
  23. * @see Zend_Service_WindowsAzure_Credentials_CredentialsAbstract_SharedKey
  24. */
  25. require_once 'Zend/Service/WindowsAzure/Credentials/SharedKey.php';
  26. /**
  27. * @see Zend_Service_WindowsAzure_Credentials_SharedAccessSignature
  28. */
  29. require_once 'Zend/Service/WindowsAzure/Credentials/SharedAccessSignature.php';
  30. /**
  31. * @see Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
  32. */
  33. require_once 'Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php';
  34. /**
  35. * @see Zend_Http_Client
  36. */
  37. require_once 'Zend/Http/Client.php';
  38. /**
  39. * @see Zend_Http_Response
  40. */
  41. require_once 'Zend/Http/Response.php';
  42. /**
  43. * @see Zend_Service_WindowsAzure_Storage
  44. */
  45. require_once 'Zend/Service/WindowsAzure/Storage.php';
  46. /**
  47. * @see Zend_Service_WindowsAzure_Storage_BlobContainer
  48. */
  49. require_once 'Zend/Service/WindowsAzure/Storage/BlobContainer.php';
  50. /**
  51. * @see Zend_Service_WindowsAzure_Storage_BlobInstance
  52. */
  53. require_once 'Zend/Service/WindowsAzure/Storage/BlobInstance.php';
  54. /**
  55. * @see Zend_Service_WindowsAzure_Storage_PageRegionInstance
  56. */
  57. require_once 'Zend/Service/WindowsAzure/Storage/PageRegionInstance.php';
  58. /**
  59. * @see Zend_Service_WindowsAzure_Storage_LeaseInstance
  60. */
  61. require_once 'Zend/Service/WindowsAzure/Storage/LeaseInstance.php';
  62. /**
  63. * @see Zend_Service_WindowsAzure_Storage_SignedIdentifier
  64. */
  65. require_once 'Zend/Service/WindowsAzure/Storage/SignedIdentifier.php';
  66. /**
  67. * @see Zend_Service_WindowsAzure_Exception
  68. */
  69. require_once 'Zend/Service/WindowsAzure/Exception.php';
  70. /**
  71. * @category Zend
  72. * @package Zend_Service_WindowsAzure
  73. * @subpackage Storage
  74. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  75. * @license http://framework.zend.com/license/new-bsd New BSD License
  76. */
  77. class Zend_Service_WindowsAzure_Storage_Blob extends Zend_Service_WindowsAzure_Storage
  78. {
  79. /**
  80. * ACL - Private access
  81. */
  82. const ACL_PRIVATE = null;
  83. /**
  84. * ACL - Public access (read all blobs)
  85. *
  86. * @deprecated Use ACL_PUBLIC_CONTAINER or ACL_PUBLIC_BLOB instead.
  87. */
  88. const ACL_PUBLIC = 'container';
  89. /**
  90. * ACL - Blob Public access (read all blobs)
  91. */
  92. const ACL_PUBLIC_BLOB = 'blob';
  93. /**
  94. * ACL - Container Public access (enumerate and read all blobs)
  95. */
  96. const ACL_PUBLIC_CONTAINER = 'container';
  97. /**
  98. * Blob lease constants
  99. */
  100. const LEASE_ACQUIRE = 'acquire';
  101. const LEASE_RENEW = 'renew';
  102. const LEASE_RELEASE = 'release';
  103. const LEASE_BREAK = 'break';
  104. /**
  105. * Maximal blob size (in bytes)
  106. */
  107. const MAX_BLOB_SIZE = 67108864;
  108. /**
  109. * Maximal blob transfer size (in bytes)
  110. */
  111. const MAX_BLOB_TRANSFER_SIZE = 4194304;
  112. /**
  113. * Blob types
  114. */
  115. const BLOBTYPE_BLOCK = 'BlockBlob';
  116. const BLOBTYPE_PAGE = 'PageBlob';
  117. /**
  118. * Put page write options
  119. */
  120. const PAGE_WRITE_UPDATE = 'update';
  121. const PAGE_WRITE_CLEAR = 'clear';
  122. /**
  123. * Stream wrapper clients
  124. *
  125. * @var array
  126. */
  127. protected static $_wrapperClients = array();
  128. /**
  129. * SharedAccessSignature credentials
  130. *
  131. * @var Zend_Service_WindowsAzure_Credentials_SharedAccessSignature
  132. */
  133. private $_sharedAccessSignatureCredentials = null;
  134. /**
  135. * Creates a new Zend_Service_WindowsAzure_Storage_Blob instance
  136. *
  137. * @param string $host Storage host name
  138. * @param string $accountName Account name for Windows Azure
  139. * @param string $accountKey Account key for Windows Azure
  140. * @param boolean $usePathStyleUri Use path-style URI's
  141. * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
  142. */
  143. public function __construct($host = Zend_Service_WindowsAzure_Storage::URL_DEV_BLOB, $accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT, $accountKey = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY, $usePathStyleUri = false, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
  144. {
  145. parent::__construct($host, $accountName, $accountKey, $usePathStyleUri, $retryPolicy);
  146. // API version
  147. $this->_apiVersion = '2009-09-19';
  148. // SharedAccessSignature credentials
  149. $this->_sharedAccessSignatureCredentials = new Zend_Service_WindowsAzure_Credentials_SharedAccessSignature($accountName, $accountKey, $usePathStyleUri);
  150. }
  151. /**
  152. * Check if a blob exists
  153. *
  154. * @param string $containerName Container name
  155. * @param string $blobName Blob name
  156. * @param string $snapshotId Snapshot identifier
  157. * @return boolean
  158. */
  159. public function blobExists($containerName = '', $blobName = '', $snapshotId = null)
  160. {
  161. if ($containerName === '') {
  162. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  163. }
  164. if (!self::isValidContainerName($containerName)) {
  165. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  166. }
  167. if ($blobName === '') {
  168. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  169. }
  170. // Get blob instance
  171. try {
  172. $this->getBlobInstance($containerName, $blobName, $snapshotId);
  173. } catch (Zend_Service_WindowsAzure_Exception $e) {
  174. return false;
  175. }
  176. return true;
  177. }
  178. /**
  179. * Check if a container exists
  180. *
  181. * @param string $containerName Container name
  182. * @return boolean
  183. */
  184. public function containerExists($containerName = '')
  185. {
  186. if ($containerName === '') {
  187. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  188. }
  189. if (!self::isValidContainerName($containerName)) {
  190. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  191. }
  192. // List containers
  193. $containers = $this->listContainers($containerName, 1);
  194. foreach ($containers as $container) {
  195. if ($container->Name == $containerName) {
  196. return true;
  197. }
  198. }
  199. return false;
  200. }
  201. /**
  202. * Create container
  203. *
  204. * @param string $containerName Container name
  205. * @param array $metadata Key/value pairs of meta data
  206. * @return object Container properties
  207. * @throws Zend_Service_WindowsAzure_Exception
  208. */
  209. public function createContainer($containerName = '', $metadata = array())
  210. {
  211. if ($containerName === '') {
  212. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  213. }
  214. if (!self::isValidContainerName($containerName)) {
  215. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  216. }
  217. if (!is_array($metadata)) {
  218. throw new Zend_Service_WindowsAzure_Exception('Meta data should be an array of key and value pairs.');
  219. }
  220. // Create metadata headers
  221. $headers = array();
  222. $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
  223. // Perform request
  224. $response = $this->_performRequest($containerName, '?restype=container', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  225. if ($response->isSuccessful()) {
  226. return new Zend_Service_WindowsAzure_Storage_BlobContainer(
  227. $containerName,
  228. $response->getHeader('Etag'),
  229. $response->getHeader('Last-modified'),
  230. $metadata
  231. );
  232. } else {
  233. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  234. }
  235. }
  236. /**
  237. * Get container ACL
  238. *
  239. * @param string $containerName Container name
  240. * @param bool $signedIdentifiers Display only private/blob/container or display signed identifiers?
  241. * @return string Acl, to be compared with Zend_Service_WindowsAzure_Storage_Blob::ACL_*
  242. * @throws Zend_Service_WindowsAzure_Exception
  243. */
  244. public function getContainerAcl($containerName = '', $signedIdentifiers = false)
  245. {
  246. if ($containerName === '') {
  247. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  248. }
  249. if (!self::isValidContainerName($containerName)) {
  250. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  251. }
  252. // Perform request
  253. $response = $this->_performRequest($containerName, '?restype=container&comp=acl', Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
  254. if ($response->isSuccessful()) {
  255. if ($signedIdentifiers == false) {
  256. // Only private/blob/container
  257. $accessType = $response->getHeader(Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-public-access');
  258. if (strtolower($accessType) == 'true') {
  259. $accessType = self::ACL_PUBLIC_CONTAINER;
  260. }
  261. return $accessType;
  262. } else {
  263. // Parse result
  264. $result = $this->_parseResponse($response);
  265. if (!$result) {
  266. return array();
  267. }
  268. $entries = null;
  269. if ($result->SignedIdentifier) {
  270. if (count($result->SignedIdentifier) > 1) {
  271. $entries = $result->SignedIdentifier;
  272. } else {
  273. $entries = array($result->SignedIdentifier);
  274. }
  275. }
  276. // Return value
  277. $returnValue = array();
  278. foreach ($entries as $entry) {
  279. $returnValue[] = new Zend_Service_WindowsAzure_Storage_SignedIdentifier(
  280. $entry->Id,
  281. $entry->AccessPolicy ? $entry->AccessPolicy->Start ? $entry->AccessPolicy->Start : '' : '',
  282. $entry->AccessPolicy ? $entry->AccessPolicy->Expiry ? $entry->AccessPolicy->Expiry : '' : '',
  283. $entry->AccessPolicy ? $entry->AccessPolicy->Permission ? $entry->AccessPolicy->Permission : '' : ''
  284. );
  285. }
  286. // Return
  287. return $returnValue;
  288. }
  289. } else {
  290. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  291. }
  292. }
  293. /**
  294. * Set container ACL
  295. *
  296. * @param string $containerName Container name
  297. * @param bool $acl Zend_Service_WindowsAzure_Storage_Blob::ACL_*
  298. * @param array $signedIdentifiers Signed identifiers
  299. * @throws Zend_Service_WindowsAzure_Exception
  300. */
  301. public function setContainerAcl($containerName = '', $acl = self::ACL_PRIVATE, $signedIdentifiers = array())
  302. {
  303. if ($containerName === '') {
  304. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  305. }
  306. if (!self::isValidContainerName($containerName)) {
  307. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  308. }
  309. // Headers
  310. $headers = array();
  311. // Acl specified?
  312. if ($acl != self::ACL_PRIVATE && !is_null($acl) && $acl != '') {
  313. $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-public-access'] = $acl;
  314. }
  315. // Policies
  316. $policies = null;
  317. if (is_array($signedIdentifiers) && count($signedIdentifiers) > 0) {
  318. $policies = '';
  319. $policies .= '<?xml version="1.0" encoding="utf-8"?>' . "\r\n";
  320. $policies .= '<SignedIdentifiers>' . "\r\n";
  321. foreach ($signedIdentifiers as $signedIdentifier) {
  322. $policies .= ' <SignedIdentifier>' . "\r\n";
  323. $policies .= ' <Id>' . $signedIdentifier->Id . '</Id>' . "\r\n";
  324. $policies .= ' <AccessPolicy>' . "\r\n";
  325. if ($signedIdentifier->Start != '')
  326. $policies .= ' <Start>' . $signedIdentifier->Start . '</Start>' . "\r\n";
  327. if ($signedIdentifier->Expiry != '')
  328. $policies .= ' <Expiry>' . $signedIdentifier->Expiry . '</Expiry>' . "\r\n";
  329. if ($signedIdentifier->Permissions != '')
  330. $policies .= ' <Permission>' . $signedIdentifier->Permissions . '</Permission>' . "\r\n";
  331. $policies .= ' </AccessPolicy>' . "\r\n";
  332. $policies .= ' </SignedIdentifier>' . "\r\n";
  333. }
  334. $policies .= '</SignedIdentifiers>' . "\r\n";
  335. }
  336. // Perform request
  337. $response = $this->_performRequest($containerName, '?restype=container&comp=acl', Zend_Http_Client::PUT, $headers, false, $policies, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  338. if (!$response->isSuccessful()) {
  339. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  340. }
  341. }
  342. /**
  343. * Get container
  344. *
  345. * @param string $containerName Container name
  346. * @return Zend_Service_WindowsAzure_Storage_BlobContainer
  347. * @throws Zend_Service_WindowsAzure_Exception
  348. */
  349. public function getContainer($containerName = '')
  350. {
  351. if ($containerName === '') {
  352. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  353. }
  354. if (!self::isValidContainerName($containerName)) {
  355. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  356. }
  357. // Perform request
  358. $response = $this->_performRequest($containerName, '?restype=container', Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
  359. if ($response->isSuccessful()) {
  360. // Parse metadata
  361. $metadata = $this->_parseMetadataHeaders($response->getHeaders());
  362. // Return container
  363. return new Zend_Service_WindowsAzure_Storage_BlobContainer(
  364. $containerName,
  365. $response->getHeader('Etag'),
  366. $response->getHeader('Last-modified'),
  367. $metadata
  368. );
  369. } else {
  370. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  371. }
  372. }
  373. /**
  374. * Get container metadata
  375. *
  376. * @param string $containerName Container name
  377. * @return array Key/value pairs of meta data
  378. * @throws Zend_Service_WindowsAzure_Exception
  379. */
  380. public function getContainerMetadata($containerName = '')
  381. {
  382. if ($containerName === '') {
  383. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  384. }
  385. if (!self::isValidContainerName($containerName)) {
  386. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  387. }
  388. return $this->getContainer($containerName)->Metadata;
  389. }
  390. /**
  391. * Set container metadata
  392. *
  393. * Calling the Set Container Metadata operation overwrites all existing metadata that is associated with the container. It's not possible to modify an individual name/value pair.
  394. *
  395. * @param string $containerName Container name
  396. * @param array $metadata Key/value pairs of meta data
  397. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  398. * @throws Zend_Service_WindowsAzure_Exception
  399. */
  400. public function setContainerMetadata($containerName = '', $metadata = array(), $additionalHeaders = array())
  401. {
  402. if ($containerName === '') {
  403. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  404. }
  405. if (!self::isValidContainerName($containerName)) {
  406. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  407. }
  408. if (!is_array($metadata)) {
  409. throw new Zend_Service_WindowsAzure_Exception('Meta data should be an array of key and value pairs.');
  410. }
  411. if (count($metadata) == 0) {
  412. return;
  413. }
  414. // Create metadata headers
  415. $headers = array();
  416. $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
  417. // Additional headers?
  418. foreach ($additionalHeaders as $key => $value) {
  419. $headers[$key] = $value;
  420. }
  421. // Perform request
  422. $response = $this->_performRequest($containerName, '?restype=container&comp=metadata', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  423. if (!$response->isSuccessful()) {
  424. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  425. }
  426. }
  427. /**
  428. * Delete container
  429. *
  430. * @param string $containerName Container name
  431. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  432. * @throws Zend_Service_WindowsAzure_Exception
  433. */
  434. public function deleteContainer($containerName = '', $additionalHeaders = array())
  435. {
  436. if ($containerName === '') {
  437. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  438. }
  439. if (!self::isValidContainerName($containerName)) {
  440. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  441. }
  442. // Additional headers?
  443. $headers = array();
  444. foreach ($additionalHeaders as $key => $value) {
  445. $headers[$key] = $value;
  446. }
  447. // Perform request
  448. $response = $this->_performRequest($containerName, '?restype=container', Zend_Http_Client::DELETE, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  449. if (!$response->isSuccessful()) {
  450. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  451. }
  452. }
  453. /**
  454. * List containers
  455. *
  456. * @param string $prefix Optional. Filters the results to return only containers whose name begins with the specified prefix.
  457. * @param int $maxResults Optional. Specifies the maximum number of containers to return per call to Azure storage. This does NOT affect list size returned by this function. (maximum: 5000)
  458. * @param string $marker Optional string value that identifies the portion of the list to be returned with the next list operation.
  459. * @param string $include Optional. Include this parameter to specify that the container's metadata be returned as part of the response body. (allowed values: '', 'metadata')
  460. * @param int $currentResultCount Current result count (internal use)
  461. * @return array
  462. * @throws Zend_Service_WindowsAzure_Exception
  463. */
  464. public function listContainers($prefix = null, $maxResults = null, $marker = null, $include = null, $currentResultCount = 0)
  465. {
  466. // Build query string
  467. $queryString = array('comp=list');
  468. if (!is_null($prefix)) {
  469. $queryString[] = 'prefix=' . $prefix;
  470. }
  471. if (!is_null($maxResults)) {
  472. $queryString[] = 'maxresults=' . $maxResults;
  473. }
  474. if (!is_null($marker)) {
  475. $queryString[] = 'marker=' . $marker;
  476. }
  477. if (!is_null($include)) {
  478. $queryString[] = 'include=' . $include;
  479. }
  480. $queryString = self::createQueryStringFromArray($queryString);
  481. // Perform request
  482. $response = $this->_performRequest('', $queryString, Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_LIST);
  483. if ($response->isSuccessful()) {
  484. $xmlContainers = $this->_parseResponse($response)->Containers->Container;
  485. $xmlMarker = (string)$this->_parseResponse($response)->NextMarker;
  486. $containers = array();
  487. if (!is_null($xmlContainers)) {
  488. for ($i = 0; $i < count($xmlContainers); $i++) {
  489. $containers[] = new Zend_Service_WindowsAzure_Storage_BlobContainer(
  490. (string)$xmlContainers[$i]->Name,
  491. (string)$xmlContainers[$i]->Etag,
  492. (string)$xmlContainers[$i]->LastModified,
  493. $this->_parseMetadataElement($xmlContainers[$i])
  494. );
  495. }
  496. }
  497. $currentResultCount = $currentResultCount + count($containers);
  498. if (!is_null($maxResults) && $currentResultCount < $maxResults) {
  499. if (!is_null($xmlMarker) && $xmlMarker != '') {
  500. $containers = array_merge($containers, $this->listContainers($prefix, $maxResults, $xmlMarker, $include, $currentResultCount));
  501. }
  502. }
  503. if (!is_null($maxResults) && count($containers) > $maxResults) {
  504. $containers = array_slice($containers, 0, $maxResults);
  505. }
  506. return $containers;
  507. } else {
  508. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  509. }
  510. }
  511. /**
  512. * Put blob
  513. *
  514. * @param string $containerName Container name
  515. * @param string $blobName Blob name
  516. * @param string $localFileName Local file name to be uploaded
  517. * @param array $metadata Key/value pairs of meta data
  518. * @param string $leaseId Lease identifier
  519. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  520. * @return object Partial blob properties
  521. * @throws Zend_Service_WindowsAzure_Exception
  522. */
  523. public function putBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
  524. {
  525. if ($containerName === '') {
  526. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  527. }
  528. if (!self::isValidContainerName($containerName)) {
  529. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  530. }
  531. if ($blobName === '') {
  532. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  533. }
  534. if ($localFileName === '') {
  535. throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.');
  536. }
  537. if (!file_exists($localFileName)) {
  538. throw new Zend_Service_WindowsAzure_Exception('Local file not found.');
  539. }
  540. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  541. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  542. }
  543. // Check file size
  544. if (filesize($localFileName) >= self::MAX_BLOB_SIZE) {
  545. return $this->putLargeBlob($containerName, $blobName, $localFileName, $metadata, $leaseId);
  546. }
  547. // Put the data to Windows Azure Storage
  548. return $this->putBlobData($containerName, $blobName, file_get_contents($localFileName), $metadata, $leaseId, $additionalHeaders);
  549. }
  550. /**
  551. * Put blob data
  552. *
  553. * @param string $containerName Container name
  554. * @param string $blobName Blob name
  555. * @param mixed $data Data to store
  556. * @param array $metadata Key/value pairs of meta data
  557. * @param string $leaseId Lease identifier
  558. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  559. * @return object Partial blob properties
  560. * @throws Zend_Service_WindowsAzure_Exception
  561. */
  562. public function putBlobData($containerName = '', $blobName = '', $data = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
  563. {
  564. if ($containerName === '') {
  565. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  566. }
  567. if (!self::isValidContainerName($containerName)) {
  568. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  569. }
  570. if ($blobName === '') {
  571. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  572. }
  573. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  574. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  575. }
  576. // Create metadata headers
  577. $headers = array();
  578. if (!is_null($leaseId)) {
  579. $headers['x-ms-lease-id'] = $leaseId;
  580. }
  581. $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
  582. // Additional headers?
  583. foreach ($additionalHeaders as $key => $value) {
  584. $headers[$key] = $value;
  585. }
  586. // Specify blob type
  587. $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_BLOCK;
  588. // Resource name
  589. $resourceName = self::createResourceName($containerName , $blobName);
  590. // Perform request
  591. $response = $this->_performRequest($resourceName, '', Zend_Http_Client::PUT, $headers, false, $data, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  592. if ($response->isSuccessful()) {
  593. return new Zend_Service_WindowsAzure_Storage_BlobInstance(
  594. $containerName,
  595. $blobName,
  596. null,
  597. $response->getHeader('Etag'),
  598. $response->getHeader('Last-modified'),
  599. $this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
  600. strlen($data),
  601. '',
  602. '',
  603. '',
  604. false,
  605. $metadata
  606. );
  607. } else {
  608. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  609. }
  610. }
  611. /**
  612. * Put large blob (> 64 MB)
  613. *
  614. * @param string $containerName Container name
  615. * @param string $blobName Blob name
  616. * @param string $localFileName Local file name to be uploaded
  617. * @param array $metadata Key/value pairs of meta data
  618. * @param string $leaseId Lease identifier
  619. * @return object Partial blob properties
  620. * @throws Zend_Service_WindowsAzure_Exception
  621. */
  622. public function putLargeBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null)
  623. {
  624. if ($containerName === '') {
  625. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  626. }
  627. if (!self::isValidContainerName($containerName)) {
  628. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  629. }
  630. if ($blobName === '') {
  631. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  632. }
  633. if ($localFileName === '') {
  634. throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.');
  635. }
  636. if (!file_exists($localFileName)) {
  637. throw new Zend_Service_WindowsAzure_Exception('Local file not found.');
  638. }
  639. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  640. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  641. }
  642. // Check file size
  643. if (filesize($localFileName) < self::MAX_BLOB_SIZE) {
  644. return $this->putBlob($containerName, $blobName, $localFileName, $metadata);
  645. }
  646. // Determine number of parts
  647. $numberOfParts = ceil( filesize($localFileName) / self::MAX_BLOB_TRANSFER_SIZE );
  648. // Generate block id's
  649. $blockIdentifiers = array();
  650. for ($i = 0; $i < $numberOfParts; $i++) {
  651. $blockIdentifiers[] = $this->_generateBlockId($i);
  652. }
  653. // Open file
  654. $fp = fopen($localFileName, 'r');
  655. if ($fp === false) {
  656. throw new Zend_Service_WindowsAzure_Exception('Could not open local file.');
  657. }
  658. // Upload parts
  659. for ($i = 0; $i < $numberOfParts; $i++) {
  660. // Seek position in file
  661. fseek($fp, $i * self::MAX_BLOB_TRANSFER_SIZE);
  662. // Read contents
  663. $fileContents = fread($fp, self::MAX_BLOB_TRANSFER_SIZE);
  664. // Put block
  665. $this->putBlock($containerName, $blobName, $blockIdentifiers[$i], $fileContents, $leaseId);
  666. // Dispose file contents
  667. $fileContents = null;
  668. unset($fileContents);
  669. }
  670. // Close file
  671. fclose($fp);
  672. // Put block list
  673. $this->putBlockList($containerName, $blobName, $blockIdentifiers, $metadata, $leaseId);
  674. // Return information of the blob
  675. return $this->getBlobInstance($containerName, $blobName, null, $leaseId);
  676. }
  677. /**
  678. * Put large blob block
  679. *
  680. * @param string $containerName Container name
  681. * @param string $blobName Blob name
  682. * @param string $identifier Block ID
  683. * @param array $contents Contents of the block
  684. * @param string $leaseId Lease identifier
  685. * @throws Zend_Service_WindowsAzure_Exception
  686. */
  687. public function putBlock($containerName = '', $blobName = '', $identifier = '', $contents = '', $leaseId = null)
  688. {
  689. if ($containerName === '') {
  690. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  691. }
  692. if (!self::isValidContainerName($containerName)) {
  693. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  694. }
  695. if ($identifier === '') {
  696. throw new Zend_Service_WindowsAzure_Exception('Block identifier is not specified.');
  697. }
  698. if (strlen($contents) > self::MAX_BLOB_TRANSFER_SIZE) {
  699. throw new Zend_Service_WindowsAzure_Exception('Block size is too big.');
  700. }
  701. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  702. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  703. }
  704. // Headers
  705. $headers = array();
  706. if (!is_null($leaseId)) {
  707. $headers['x-ms-lease-id'] = $leaseId;
  708. }
  709. // Resource name
  710. $resourceName = self::createResourceName($containerName , $blobName);
  711. // Upload
  712. $response = $this->_performRequest($resourceName, '?comp=block&blockid=' . base64_encode($identifier), Zend_Http_Client::PUT, $headers, false, $contents, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  713. if (!$response->isSuccessful()) {
  714. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  715. }
  716. }
  717. /**
  718. * Put block list
  719. *
  720. * @param string $containerName Container name
  721. * @param string $blobName Blob name
  722. * @param array $blockList Array of block identifiers
  723. * @param array $metadata Key/value pairs of meta data
  724. * @param string $leaseId Lease identifier
  725. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  726. * @throws Zend_Service_WindowsAzure_Exception
  727. */
  728. public function putBlockList($containerName = '', $blobName = '', $blockList = array(), $metadata = array(), $leaseId = null, $additionalHeaders = array())
  729. {
  730. if ($containerName === '') {
  731. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  732. }
  733. if (!self::isValidContainerName($containerName)) {
  734. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  735. }
  736. if ($blobName === '') {
  737. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  738. }
  739. if (count($blockList) == 0) {
  740. throw new Zend_Service_WindowsAzure_Exception('Block list does not contain any elements.');
  741. }
  742. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  743. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  744. }
  745. // Generate block list
  746. $blocks = '';
  747. foreach ($blockList as $block) {
  748. $blocks .= ' <Latest>' . base64_encode($block) . '</Latest>' . "\n";
  749. }
  750. // Generate block list request
  751. $fileContents = utf8_encode(implode("\n", array(
  752. '<?xml version="1.0" encoding="utf-8"?>',
  753. '<BlockList>',
  754. $blocks,
  755. '</BlockList>'
  756. )));
  757. // Create metadata headers
  758. $headers = array();
  759. if (!is_null($leaseId)) {
  760. $headers['x-ms-lease-id'] = $leaseId;
  761. }
  762. $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
  763. // Additional headers?
  764. foreach ($additionalHeaders as $key => $value) {
  765. $headers[$key] = $value;
  766. }
  767. // Resource name
  768. $resourceName = self::createResourceName($containerName , $blobName);
  769. // Perform request
  770. $response = $this->_performRequest($resourceName, '?comp=blocklist', Zend_Http_Client::PUT, $headers, false, $fileContents, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  771. if (!$response->isSuccessful()) {
  772. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  773. }
  774. }
  775. /**
  776. * Get block list
  777. *
  778. * @param string $containerName Container name
  779. * @param string $blobName Blob name
  780. * @param string $snapshotId Snapshot identifier
  781. * @param string $leaseId Lease identifier
  782. * @param integer $type Type of block list to retrieve. 0 = all, 1 = committed, 2 = uncommitted
  783. * @return array
  784. * @throws Zend_Service_WindowsAzure_Exception
  785. */
  786. public function getBlockList($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $type = 0)
  787. {
  788. if ($containerName === '') {
  789. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  790. }
  791. if (!self::isValidContainerName($containerName)) {
  792. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  793. }
  794. if ($blobName === '') {
  795. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  796. }
  797. if ($type < 0 || $type > 2) {
  798. throw new Zend_Service_WindowsAzure_Exception('Invalid type of block list to retrieve.');
  799. }
  800. // Set $blockListType
  801. $blockListType = 'all';
  802. if ($type == 1) {
  803. $blockListType = 'committed';
  804. }
  805. if ($type == 2) {
  806. $blockListType = 'uncommitted';
  807. }
  808. // Headers
  809. $headers = array();
  810. if (!is_null($leaseId)) {
  811. $headers['x-ms-lease-id'] = $leaseId;
  812. }
  813. // Build query string
  814. $queryString = array('comp=blocklist', 'blocklisttype=' . $blockListType);
  815. if (!is_null($snapshotId)) {
  816. $queryString[] = 'snapshot=' . $snapshotId;
  817. }
  818. $queryString = self::createQueryStringFromArray($queryString);
  819. // Resource name
  820. $resourceName = self::createResourceName($containerName , $blobName);
  821. // Perform request
  822. $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
  823. if ($response->isSuccessful()) {
  824. // Parse response
  825. $blockList = $this->_parseResponse($response);
  826. // Create return value
  827. $returnValue = array();
  828. if ($blockList->CommittedBlocks) {
  829. foreach ($blockList->CommittedBlocks->Block as $block) {
  830. $returnValue['CommittedBlocks'][] = (object)array(
  831. 'Name' => (string)$block->Name,
  832. 'Size' => (string)$block->Size
  833. );
  834. }
  835. }
  836. if ($blockList->UncommittedBlocks) {
  837. foreach ($blockList->UncommittedBlocks->Block as $block) {
  838. $returnValue['UncommittedBlocks'][] = (object)array(
  839. 'Name' => (string)$block->Name,
  840. 'Size' => (string)$block->Size
  841. );
  842. }
  843. }
  844. return $returnValue;
  845. } else {
  846. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  847. }
  848. }
  849. /**
  850. * Create page blob
  851. *
  852. * @param string $containerName Container name
  853. * @param string $blobName Blob name
  854. * @param int $size Size of the page blob in bytes
  855. * @param array $metadata Key/value pairs of meta data
  856. * @param string $leaseId Lease identifier
  857. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  858. * @return object Partial blob properties
  859. * @throws Zend_Service_WindowsAzure_Exception
  860. */
  861. public function createPageBlob($containerName = '', $blobName = '', $size = 0, $metadata = array(), $leaseId = null, $additionalHeaders = array())
  862. {
  863. if ($containerName === '') {
  864. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  865. }
  866. if (!self::isValidContainerName($containerName)) {
  867. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  868. }
  869. if ($blobName === '') {
  870. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  871. }
  872. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  873. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  874. }
  875. if ($size <= 0) {
  876. throw new Zend_Service_WindowsAzure_Exception('Page blob size must be specified.');
  877. }
  878. // Create metadata headers
  879. $headers = array();
  880. if (!is_null($leaseId)) {
  881. $headers['x-ms-lease-id'] = $leaseId;
  882. }
  883. $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
  884. // Additional headers?
  885. foreach ($additionalHeaders as $key => $value) {
  886. $headers[$key] = $value;
  887. }
  888. // Specify blob type & blob length
  889. $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_PAGE;
  890. $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-content-length'] = $size;
  891. $headers['Content-Length'] = 0;
  892. // Resource name
  893. $resourceName = self::createResourceName($containerName , $blobName);
  894. // Perform request
  895. $response = $this->_performRequest($resourceName, '', Zend_Http_Client::PUT, $headers, false, '', Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  896. if ($response->isSuccessful()) {
  897. return new Zend_Service_WindowsAzure_Storage_BlobInstance(
  898. $containerName,
  899. $blobName,
  900. null,
  901. $response->getHeader('Etag'),
  902. $response->getHeader('Last-modified'),
  903. $this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
  904. $size,
  905. '',
  906. '',
  907. '',
  908. false,
  909. $metadata
  910. );
  911. } else {
  912. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  913. }
  914. }
  915. /**
  916. * Put page in page blob
  917. *
  918. * @param string $containerName Container name
  919. * @param string $blobName Blob name
  920. * @param int $startByteOffset Start byte offset
  921. * @param int $endByteOffset End byte offset
  922. * @param mixed $contents Page contents
  923. * @param string $writeMethod Write method (Zend_Service_WindowsAzure_Storage_Blob::PAGE_WRITE_*)
  924. * @param string $leaseId Lease identifier
  925. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  926. * @throws Zend_Service_WindowsAzure_Exception
  927. */
  928. public function putPage($containerName = '', $blobName = '', $startByteOffset = 0, $endByteOffset = 0, $contents = '', $writeMethod = self::PAGE_WRITE_UPDATE, $leaseId = null, $additionalHeaders = array())
  929. {
  930. if ($containerName === '') {
  931. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  932. }
  933. if (!self::isValidContainerName($containerName)) {
  934. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  935. }
  936. if ($blobName === '') {
  937. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  938. }
  939. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  940. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  941. }
  942. if ($startByteOffset % 512 != 0) {
  943. throw new Zend_Service_WindowsAzure_Exception('Start byte offset must be a modulus of 512.');
  944. }
  945. if (($endByteOffset + 1) % 512 != 0) {
  946. throw new Zend_Service_WindowsAzure_Exception('End byte offset must be a modulus of 512 minus 1.');
  947. }
  948. // Determine size
  949. $size = strlen($contents);
  950. if ($size >= self::MAX_BLOB_TRANSFER_SIZE) {
  951. throw new Zend_Service_WindowsAzure_Exception('Page blob size must not be larger than ' + self::MAX_BLOB_TRANSFER_SIZE . ' bytes.');
  952. }
  953. // Create metadata headers
  954. $headers = array();
  955. if (!is_null($leaseId)) {
  956. $headers['x-ms-lease-id'] = $leaseId;
  957. }
  958. // Additional headers?
  959. foreach ($additionalHeaders as $key => $value) {
  960. $headers[$key] = $value;
  961. }
  962. // Specify range
  963. $headers['Range'] = 'bytes=' . $startByteOffset . '-' . $endByteOffset;
  964. // Write method
  965. $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'page-write'] = $writeMethod;
  966. // Resource name
  967. $resourceName = self::createResourceName($containerName , $blobName);
  968. // Perform request
  969. $response = $this->_performRequest($resourceName, '?comp=page', Zend_Http_Client::PUT, $headers, false, $contents, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  970. if (!$response->isSuccessful()) {
  971. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  972. }
  973. }
  974. /**
  975. * Put page in page blob
  976. *
  977. * @param string $containerName Container name
  978. * @param string $blobName Blob name
  979. * @param int $startByteOffset Start byte offset
  980. * @param int $endByteOffset End byte offset
  981. * @param string $leaseId Lease identifier
  982. * @return array Array of page ranges
  983. * @throws Zend_Service_WindowsAzure_Exception
  984. */
  985. public function getPageRegions($containerName = '', $blobName = '', $startByteOffset = 0, $endByteOffset = 0, $leaseId = null)
  986. {
  987. if ($containerName === '') {
  988. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  989. }
  990. if (!self::isValidContainerName($containerName)) {
  991. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  992. }
  993. if ($blobName === '') {
  994. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  995. }
  996. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  997. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  998. }
  999. if ($startByteOffset % 512 != 0) {
  1000. throw new Zend_Service_WindowsAzure_Exception('Start byte offset must be a modulus of 512.');
  1001. }
  1002. if ($endByteOffset > 0 && ($endByteOffset + 1) % 512 != 0) {
  1003. throw new Zend_Service_WindowsAzure_Exception('End byte offset must be a modulus of 512 minus 1.');
  1004. }
  1005. // Create metadata headers
  1006. $headers = array();
  1007. if (!is_null($leaseId)) {
  1008. $headers['x-ms-lease-id'] = $leaseId;
  1009. }
  1010. // Specify range?
  1011. if ($endByteOffset > 0) {
  1012. $headers['Range'] = 'bytes=' . $startByteOffset . '-' . $endByteOffset;
  1013. }
  1014. // Resource name
  1015. $resourceName = self::createResourceName($containerName , $blobName);
  1016. // Perform request
  1017. $response = $this->_performRequest($resourceName, '?comp=pagelist', Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  1018. if ($response->isSuccessful()) {
  1019. $result = $this->_parseResponse($response);
  1020. $xmlRanges = null;
  1021. if (count($result->PageRange) > 1) {
  1022. $xmlRanges = $result->PageRange;
  1023. } else {
  1024. $xmlRanges = array($result->PageRange);
  1025. }
  1026. $ranges = array();
  1027. for ($i = 0; $i < count($xmlRanges); $i++) {
  1028. $ranges[] = new Zend_Service_WindowsAzure_Storage_PageRegionInstance(
  1029. (int)$xmlRanges[$i]->Start,
  1030. (int)$xmlRanges[$i]->End
  1031. );
  1032. }
  1033. return $ranges;
  1034. } else {
  1035. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  1036. }
  1037. }
  1038. /**
  1039. * Copy blob
  1040. *
  1041. * @param string $sourceContainerName Source container name
  1042. * @param string $sourceBlobName Source blob name
  1043. * @param string $destinationContainerName Destination container name
  1044. * @param string $destinationBlobName Destination blob name
  1045. * @param array $metadata Key/value pairs of meta data
  1046. * @param string $sourceSnapshotId Source snapshot identifier
  1047. * @param string $destinationLeaseId Destination lease identifier
  1048. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd894037.aspx for more information.
  1049. * @return object Partial blob properties
  1050. * @throws Zend_Service_WindowsAzure_Exception
  1051. */
  1052. public function copyBlob($sourceContainerName = '', $sourceBlobName = '', $destinationContainerName = '', $destinationBlobName = '', $metadata = array(), $sourceSnapshotId = null, $destinationLeaseId = null, $additionalHeaders = array())
  1053. {
  1054. if ($sourceContainerName === '') {
  1055. throw new Zend_Service_WindowsAzure_Exception('Source container name is not specified.');
  1056. }
  1057. if (!self::isValidContainerName($sourceContainerName)) {
  1058. throw new Zend_Service_WindowsAzure_Exception('Source container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1059. }
  1060. if ($sourceBlobName === '') {
  1061. throw new Zend_Service_WindowsAzure_Exception('Source blob name is not specified.');
  1062. }
  1063. if ($destinationContainerName === '') {
  1064. throw new Zend_Service_WindowsAzure_Exception('Destination container name is not specified.');
  1065. }
  1066. if (!self::isValidContainerName($destinationContainerName)) {
  1067. throw new Zend_Service_WindowsAzure_Exception('Destination container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1068. }
  1069. if ($destinationBlobName === '') {
  1070. throw new Zend_Service_WindowsAzure_Exception('Destination blob name is not specified.');
  1071. }
  1072. if ($sourceContainerName === '$root' && strpos($sourceBlobName, '/') !== false) {
  1073. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  1074. }
  1075. if ($destinationContainerName === '$root' && strpos($destinationBlobName, '/') !== false) {
  1076. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  1077. }
  1078. // Create metadata headers
  1079. $headers = array();
  1080. if (!is_null($destinationLeaseId)) {
  1081. $headers['x-ms-lease-id'] = $destinationLeaseId;
  1082. }
  1083. $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
  1084. // Additional headers?
  1085. foreach ($additionalHeaders as $key => $value) {
  1086. $headers[$key] = $value;
  1087. }
  1088. // Resource names
  1089. $sourceResourceName = self::createResourceName($sourceContainerName, $sourceBlobName);
  1090. if (!is_null($sourceSnapshotId)) {
  1091. $sourceResourceName .= '?snapshot=' . $sourceSnapshotId;
  1092. }
  1093. $destinationResourceName = self::createResourceName($destinationContainerName, $destinationBlobName);
  1094. // Set source blob
  1095. $headers["x-ms-copy-source"] = '/' . $this->_accountName . '/' . $sourceResourceName;
  1096. // Perform request
  1097. $response = $this->_performRequest($destinationResourceName, '', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  1098. if ($response->isSuccessful()) {
  1099. return new Zend_Service_WindowsAzure_Storage_BlobInstance(
  1100. $destinationContainerName,
  1101. $destinationBlobName,
  1102. null,
  1103. $response->getHeader('Etag'),
  1104. $response->getHeader('Last-modified'),
  1105. $this->getBaseUrl() . '/' . $destinationContainerName . '/' . $destinationBlobName,
  1106. 0,
  1107. '',
  1108. '',
  1109. '',
  1110. false,
  1111. $metadata
  1112. );
  1113. } else {
  1114. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  1115. }
  1116. }
  1117. /**
  1118. * Get blob
  1119. *
  1120. * @param string $containerName Container name
  1121. * @param string $blobName Blob name
  1122. * @param string $localFileName Local file name to store downloaded blob
  1123. * @param string $snapshotId Snapshot identifier
  1124. * @param string $leaseId Lease identifier
  1125. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  1126. * @throws Zend_Service_WindowsAzure_Exception
  1127. */
  1128. public function getBlob($containerName = '', $blobName = '', $localFileName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
  1129. {
  1130. if ($containerName === '') {
  1131. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1132. }
  1133. if (!self::isValidContainerName($containerName)) {
  1134. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1135. }
  1136. if ($blobName === '') {
  1137. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  1138. }
  1139. if ($localFileName === '') {
  1140. throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.');
  1141. }
  1142. // Fetch data
  1143. file_put_contents($localFileName, $this->getBlobData($containerName, $blobName, $snapshotId, $leaseId, $additionalHeaders));
  1144. }
  1145. /**
  1146. * Get blob data
  1147. *
  1148. * @param string $containerName Container name
  1149. * @param string $blobName Blob name
  1150. * @param string $snapshotId Snapshot identifier
  1151. * @param string $leaseId Lease identifier
  1152. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  1153. * @return mixed Blob contents
  1154. * @throws Zend_Service_WindowsAzure_Exception
  1155. */
  1156. public function getBlobData($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
  1157. {
  1158. if ($containerName === '') {
  1159. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1160. }
  1161. if (!self::isValidContainerName($containerName)) {
  1162. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1163. }
  1164. if ($blobName === '') {
  1165. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  1166. }
  1167. // Build query string
  1168. $queryString = array();
  1169. if (!is_null($snapshotId)) {
  1170. $queryString[] = 'snapshot=' . $snapshotId;
  1171. }
  1172. $queryString = self::createQueryStringFromArray($queryString);
  1173. // Additional headers?
  1174. $headers = array();
  1175. if (!is_null($leaseId)) {
  1176. $headers['x-ms-lease-id'] = $leaseId;
  1177. }
  1178. foreach ($additionalHeaders as $key => $value) {
  1179. $headers[$key] = $value;
  1180. }
  1181. // Resource name
  1182. $resourceName = self::createResourceName($containerName , $blobName);
  1183. // Perform request
  1184. $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
  1185. if ($response->isSuccessful()) {
  1186. return $response->getBody();
  1187. } else {
  1188. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  1189. }
  1190. }
  1191. /**
  1192. * Get blob instance
  1193. *
  1194. * @param string $containerName Container name
  1195. * @param string $blobName Blob name
  1196. * @param string $snapshotId Snapshot identifier
  1197. * @param string $leaseId Lease identifier
  1198. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  1199. * @return Zend_Service_WindowsAzure_Storage_BlobInstance
  1200. * @throws Zend_Service_WindowsAzure_Exception
  1201. */
  1202. public function getBlobInstance($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
  1203. {
  1204. if ($containerName === '') {
  1205. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1206. }
  1207. if (!self::isValidContainerName($containerName)) {
  1208. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1209. }
  1210. if ($blobName === '') {
  1211. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  1212. }
  1213. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  1214. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  1215. }
  1216. // Build query string
  1217. $queryString = array();
  1218. if (!is_null($snapshotId)) {
  1219. $queryString[] = 'snapshot=' . $snapshotId;
  1220. }
  1221. $queryString = self::createQueryStringFromArray($queryString);
  1222. // Additional headers?
  1223. $headers = array();
  1224. if (!is_null($leaseId)) {
  1225. $headers['x-ms-lease-id'] = $leaseId;
  1226. }
  1227. foreach ($additionalHeaders as $key => $value) {
  1228. $headers[$key] = $value;
  1229. }
  1230. // Resource name
  1231. $resourceName = self::createResourceName($containerName , $blobName);
  1232. // Perform request
  1233. $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::HEAD, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
  1234. if ($response->isSuccessful()) {
  1235. // Parse metadata
  1236. $metadata = $this->_parseMetadataHeaders($response->getHeaders());
  1237. // Return blob
  1238. return new Zend_Service_WindowsAzure_Storage_BlobInstance(
  1239. $containerName,
  1240. $blobName,
  1241. $snapshotId,
  1242. $response->getHeader('Etag'),
  1243. $response->getHeader('Last-modified'),
  1244. $this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
  1245. $response->getHeader('Content-Length'),
  1246. $response->getHeader('Content-Type'),
  1247. $response->getHeader('Content-Encoding'),
  1248. $response->getHeader('Content-Language'),
  1249. $response->getHeader('Cache-Control'),
  1250. $response->getHeader('x-ms-blob-type'),
  1251. $response->getHeader('x-ms-lease-status'),
  1252. false,
  1253. $metadata
  1254. );
  1255. } else {
  1256. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  1257. }
  1258. }
  1259. /**
  1260. * Get blob metadata
  1261. *
  1262. * @param string $containerName Container name
  1263. * @param string $blobName Blob name
  1264. * @param string $snapshotId Snapshot identifier
  1265. * @param string $leaseId Lease identifier
  1266. * @return array Key/value pairs of meta data
  1267. * @throws Zend_Service_WindowsAzure_Exception
  1268. */
  1269. public function getBlobMetadata($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null)
  1270. {
  1271. if ($containerName === '') {
  1272. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1273. }
  1274. if (!self::isValidContainerName($containerName)) {
  1275. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1276. }
  1277. if ($blobName === '') {
  1278. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  1279. }
  1280. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  1281. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  1282. }
  1283. return $this->getBlobInstance($containerName, $blobName, $snapshotId, $leaseId)->Metadata;
  1284. }
  1285. /**
  1286. * Set blob metadata
  1287. *
  1288. * Calling the Set Blob Metadata operation overwrites all existing metadata that is associated with the blob. It's not possible to modify an individual name/value pair.
  1289. *
  1290. * @param string $containerName Container name
  1291. * @param string $blobName Blob name
  1292. * @param array $metadata Key/value pairs of meta data
  1293. * @param string $leaseId Lease identifier
  1294. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  1295. * @throws Zend_Service_WindowsAzure_Exception
  1296. */
  1297. public function setBlobMetadata($containerName = '', $blobName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
  1298. {
  1299. if ($containerName === '') {
  1300. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1301. }
  1302. if (!self::isValidContainerName($containerName)) {
  1303. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1304. }
  1305. if ($blobName === '') {
  1306. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  1307. }
  1308. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  1309. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  1310. }
  1311. if (count($metadata) == 0) {
  1312. return;
  1313. }
  1314. // Create metadata headers
  1315. $headers = array();
  1316. if (!is_null($leaseId)) {
  1317. $headers['x-ms-lease-id'] = $leaseId;
  1318. }
  1319. $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
  1320. // Additional headers?
  1321. foreach ($additionalHeaders as $key => $value) {
  1322. $headers[$key] = $value;
  1323. }
  1324. // Perform request
  1325. $response = $this->_performRequest($containerName . '/' . $blobName, '?comp=metadata', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  1326. if (!$response->isSuccessful()) {
  1327. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  1328. }
  1329. }
  1330. /**
  1331. * Set blob properties
  1332. *
  1333. * All available properties are listed at http://msdn.microsoft.com/en-us/library/ee691966.aspx and should be provided in the $additionalHeaders parameter.
  1334. *
  1335. * @param string $containerName Container name
  1336. * @param string $blobName Blob name
  1337. * @param string $leaseId Lease identifier
  1338. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  1339. * @throws Zend_Service_WindowsAzure_Exception
  1340. */
  1341. public function setBlobProperties($containerName = '', $blobName = '', $leaseId = null, $additionalHeaders = array())
  1342. {
  1343. if ($containerName === '') {
  1344. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1345. }
  1346. if (!self::isValidContainerName($containerName)) {
  1347. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1348. }
  1349. if ($blobName === '') {
  1350. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  1351. }
  1352. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  1353. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  1354. }
  1355. if (count($additionalHeaders) == 0) {
  1356. throw new Zend_Service_WindowsAzure_Exception('No additional headers are specified.');
  1357. }
  1358. // Create headers
  1359. $headers = array();
  1360. // Lease set?
  1361. if (!is_null($leaseId)) {
  1362. $headers['x-ms-lease-id'] = $leaseId;
  1363. }
  1364. // Additional headers?
  1365. foreach ($additionalHeaders as $key => $value) {
  1366. $headers[$key] = $value;
  1367. }
  1368. // Perform request
  1369. $response = $this->_performRequest($containerName . '/' . $blobName, '?comp=properties', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  1370. if (!$response->isSuccessful()) {
  1371. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  1372. }
  1373. }
  1374. /**
  1375. * Get blob properties
  1376. *
  1377. * @param string $containerName Container name
  1378. * @param string $blobName Blob name
  1379. * @param string $snapshotId Snapshot identifier
  1380. * @param string $leaseId Lease identifier
  1381. * @return Zend_Service_WindowsAzure_Storage_BlobInstance
  1382. * @throws Zend_Service_WindowsAzure_Exception
  1383. */
  1384. public function getBlobProperties($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null)
  1385. {
  1386. if ($containerName === '') {
  1387. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1388. }
  1389. if (!self::isValidContainerName($containerName)) {
  1390. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1391. }
  1392. if ($blobName === '') {
  1393. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  1394. }
  1395. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  1396. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  1397. }
  1398. return $this->getBlobInstance($containerName, $blobName, $snapshotId, $leaseId);
  1399. }
  1400. /**
  1401. * Delete blob
  1402. *
  1403. * @param string $containerName Container name
  1404. * @param string $blobName Blob name
  1405. * @param string $snapshotId Snapshot identifier
  1406. * @param string $leaseId Lease identifier
  1407. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  1408. * @throws Zend_Service_WindowsAzure_Exception
  1409. */
  1410. public function deleteBlob($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
  1411. {
  1412. if ($containerName === '') {
  1413. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1414. }
  1415. if (!self::isValidContainerName($containerName)) {
  1416. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1417. }
  1418. if ($blobName === '') {
  1419. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  1420. }
  1421. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  1422. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  1423. }
  1424. // Build query string
  1425. $queryString = array();
  1426. if (!is_null($snapshotId)) {
  1427. $queryString[] = 'snapshot=' . $snapshotId;
  1428. }
  1429. $queryString = self::createQueryStringFromArray($queryString);
  1430. // Additional headers?
  1431. $headers = array();
  1432. if (!is_null($leaseId)) {
  1433. $headers['x-ms-lease-id'] = $leaseId;
  1434. }
  1435. foreach ($additionalHeaders as $key => $value) {
  1436. $headers[$key] = $value;
  1437. }
  1438. // Resource name
  1439. $resourceName = self::createResourceName($containerName , $blobName);
  1440. // Perform request
  1441. $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::DELETE, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  1442. if (!$response->isSuccessful()) {
  1443. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  1444. }
  1445. }
  1446. /**
  1447. * Snapshot blob
  1448. *
  1449. * @param string $containerName Container name
  1450. * @param string $blobName Blob name
  1451. * @param array $metadata Key/value pairs of meta data
  1452. * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
  1453. * @return string Date/Time value representing the snapshot identifier.
  1454. * @throws Zend_Service_WindowsAzure_Exception
  1455. */
  1456. public function snapshotBlob($containerName = '', $blobName = '', $metadata = array(), $additionalHeaders = array())
  1457. {
  1458. if ($containerName === '') {
  1459. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1460. }
  1461. if (!self::isValidContainerName($containerName)) {
  1462. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1463. }
  1464. if ($blobName === '') {
  1465. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  1466. }
  1467. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  1468. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  1469. }
  1470. // Additional headers?
  1471. $headers = array();
  1472. foreach ($additionalHeaders as $key => $value) {
  1473. $headers[$key] = $value;
  1474. }
  1475. // Resource name
  1476. $resourceName = self::createResourceName($containerName , $blobName);
  1477. // Perform request
  1478. $response = $this->_performRequest($resourceName, '?comp=snapshot', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  1479. if ($response->isSuccessful()) {
  1480. return $response->getHeader('x-ms-snapshot');
  1481. } else {
  1482. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  1483. }
  1484. }
  1485. /**
  1486. * Lease blob - See (http://msdn.microsoft.com/en-us/library/ee691972.aspx)
  1487. *
  1488. * @param string $containerName Container name
  1489. * @param string $blobName Blob name
  1490. * @param string $leaseAction Lease action (Zend_Service_WindowsAzure_Storage_Blob::LEASE_*)
  1491. * @param string $leaseId Lease identifier, required to renew the lease or to release the lease.
  1492. * @return Zend_Service_WindowsAzure_Storage_LeaseInstance Lease instance
  1493. * @throws Zend_Service_WindowsAzure_Exception
  1494. */
  1495. public function leaseBlob($containerName = '', $blobName = '', $leaseAction = self::LEASE_ACQUIRE, $leaseId = null)
  1496. {
  1497. if ($containerName === '') {
  1498. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1499. }
  1500. if (!self::isValidContainerName($containerName)) {
  1501. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1502. }
  1503. if ($blobName === '') {
  1504. throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
  1505. }
  1506. if ($containerName === '$root' && strpos($blobName, '/') !== false) {
  1507. throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
  1508. }
  1509. // Additional headers?
  1510. $headers = array();
  1511. $headers['x-ms-lease-action'] = strtolower($leaseAction);
  1512. if (!is_null($leaseId)) {
  1513. $headers['x-ms-lease-id'] = $leaseId;
  1514. }
  1515. // Resource name
  1516. $resourceName = self::createResourceName($containerName , $blobName);
  1517. // Perform request
  1518. $response = $this->_performRequest($resourceName, '?comp=lease', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
  1519. if ($response->isSuccessful()) {
  1520. return new Zend_Service_WindowsAzure_Storage_LeaseInstance(
  1521. $containerName,
  1522. $blobName,
  1523. $response->getHeader('x-ms-lease-id'),
  1524. $response->getHeader('x-ms-lease-time'));
  1525. } else {
  1526. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  1527. }
  1528. }
  1529. /**
  1530. * List blobs
  1531. *
  1532. * @param string $containerName Container name
  1533. * @param string $prefix Optional. Filters the results to return only blobs whose name begins with the specified prefix.
  1534. * @param string $delimiter Optional. Delimiter, i.e. '/', for specifying folder hierarchy
  1535. * @param int $maxResults Optional. Specifies the maximum number of blobs to return per call to Azure storage. This does NOT affect list size returned by this function. (maximum: 5000)
  1536. * @param string $marker Optional string value that identifies the portion of the list to be returned with the next list operation.
  1537. * @param string $include Optional. Specifies that the response should include one or more of the following subsets: '', 'metadata', 'snapshots', 'uncommittedblobs'). Multiple values can be added separated with a comma (,)
  1538. * @param int $currentResultCount Current result count (internal use)
  1539. * @return array
  1540. * @throws Zend_Service_WindowsAzure_Exception
  1541. */
  1542. public function listBlobs($containerName = '', $prefix = '', $delimiter = '', $maxResults = null, $marker = null, $include = null, $currentResultCount = 0)
  1543. {
  1544. if ($containerName === '') {
  1545. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1546. }
  1547. if (!self::isValidContainerName($containerName)) {
  1548. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1549. }
  1550. // Build query string
  1551. $queryString = array('restype=container', 'comp=list');
  1552. if (!is_null($prefix)) {
  1553. $queryString[] = 'prefix=' . $prefix;
  1554. }
  1555. if ($delimiter !== '') {
  1556. $queryString[] = 'delimiter=' . $delimiter;
  1557. }
  1558. if (!is_null($maxResults)) {
  1559. $queryString[] = 'maxresults=' . $maxResults;
  1560. }
  1561. if (!is_null($marker)) {
  1562. $queryString[] = 'marker=' . $marker;
  1563. }
  1564. if (!is_null($include)) {
  1565. $queryString[] = 'include=' . $include;
  1566. }
  1567. $queryString = self::createQueryStringFromArray($queryString);
  1568. // Perform request
  1569. $response = $this->_performRequest($containerName, $queryString, Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_LIST);
  1570. if ($response->isSuccessful()) {
  1571. // Return value
  1572. $blobs = array();
  1573. // Blobs
  1574. $xmlBlobs = $this->_parseResponse($response)->Blobs->Blob;
  1575. if (!is_null($xmlBlobs)) {
  1576. for ($i = 0; $i < count($xmlBlobs); $i++) {
  1577. $properties = (array)$xmlBlobs[$i]->Properties;
  1578. $blobs[] = new Zend_Service_WindowsAzure_Storage_BlobInstance(
  1579. $containerName,
  1580. (string)$xmlBlobs[$i]->Name,
  1581. (string)$xmlBlobs[$i]->Snapshot,
  1582. (string)$properties['Etag'],
  1583. (string)$properties['Last-Modified'],
  1584. (string)$xmlBlobs[$i]->Url,
  1585. (string)$properties['Content-Length'],
  1586. (string)$properties['Content-Type'],
  1587. (string)$properties['Content-Encoding'],
  1588. (string)$properties['Content-Language'],
  1589. (string)$properties['Cache-Control'],
  1590. (string)$properties['BlobType'],
  1591. (string)$properties['LeaseStatus'],
  1592. false,
  1593. $this->_parseMetadataElement($xmlBlobs[$i])
  1594. );
  1595. }
  1596. }
  1597. // Blob prefixes (folders)
  1598. $xmlBlobs = $this->_parseResponse($response)->Blobs->BlobPrefix;
  1599. if (!is_null($xmlBlobs)) {
  1600. for ($i = 0; $i < count($xmlBlobs); $i++) {
  1601. $blobs[] = new Zend_Service_WindowsAzure_Storage_BlobInstance(
  1602. $containerName,
  1603. (string)$xmlBlobs[$i]->Name,
  1604. null,
  1605. '',
  1606. '',
  1607. '',
  1608. 0,
  1609. '',
  1610. '',
  1611. '',
  1612. '',
  1613. '',
  1614. '',
  1615. true,
  1616. $this->_parseMetadataElement($xmlBlobs[$i])
  1617. );
  1618. }
  1619. }
  1620. // More blobs?
  1621. $xmlMarker = (string)$this->_parseResponse($response)->NextMarker;
  1622. $currentResultCount = $currentResultCount + count($blobs);
  1623. if (!is_null($maxResults) && $currentResultCount < $maxResults) {
  1624. if (!is_null($xmlMarker) && $xmlMarker != '') {
  1625. $blobs = array_merge($blobs, $this->listBlobs($containerName, $prefix, $delimiter, $maxResults, $marker, $include, $currentResultCount));
  1626. }
  1627. }
  1628. if (!is_null($maxResults) && count($blobs) > $maxResults) {
  1629. $blobs = array_slice($blobs, 0, $maxResults);
  1630. }
  1631. return $blobs;
  1632. } else {
  1633. throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
  1634. }
  1635. }
  1636. /**
  1637. * Generate shared access URL
  1638. *
  1639. * @param string $containerName Container name
  1640. * @param string $blobName Blob name
  1641. * @param string $resource Signed resource - container (c) - blob (b)
  1642. * @param string $permissions Signed permissions - read (r), write (w), delete (d) and list (l)
  1643. * @param string $start The time at which the Shared Access Signature becomes valid.
  1644. * @param string $expiry The time at which the Shared Access Signature becomes invalid.
  1645. * @param string $identifier Signed identifier
  1646. * @return string
  1647. */
  1648. public function generateSharedAccessUrl($containerName = '', $blobName = '', $resource = 'b', $permissions = 'r', $start = '', $expiry = '', $identifier = '')
  1649. {
  1650. if ($containerName === '') {
  1651. throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
  1652. }
  1653. if (!self::isValidContainerName($containerName)) {
  1654. throw new Zend_Service_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
  1655. }
  1656. // Resource name
  1657. $resourceName = self::createResourceName($containerName , $blobName);
  1658. // Generate URL
  1659. return $this->getBaseUrl() . '/' . $resourceName . '?' .
  1660. $this->_sharedAccessSignatureCredentials->createSignedQueryString(
  1661. $resourceName,
  1662. '',
  1663. $resource,
  1664. $permissions,
  1665. $start,
  1666. $expiry,
  1667. $identifier);
  1668. }
  1669. /**
  1670. * Register this object as stream wrapper client
  1671. *
  1672. * @param string $name Protocol name
  1673. * @return Zend_Service_WindowsAzure_Storage_Blob
  1674. */
  1675. public function registerAsClient($name)
  1676. {
  1677. self::$_wrapperClients[$name] = $this;
  1678. return $this;
  1679. }
  1680. /**
  1681. * Unregister this object as stream wrapper client
  1682. *
  1683. * @param string $name Protocol name
  1684. * @return Zend_Service_WindowsAzure_Storage_Blob
  1685. */
  1686. public function unregisterAsClient($name)
  1687. {
  1688. unset(self::$_wrapperClients[$name]);
  1689. return $this;
  1690. }
  1691. /**
  1692. * Get wrapper client for stream type
  1693. *
  1694. * @param string $name Protocol name
  1695. * @return Zend_Service_WindowsAzure_Storage_Blob
  1696. */
  1697. public static function getWrapperClient($name)
  1698. {
  1699. return self::$_wrapperClients[$name];
  1700. }
  1701. /**
  1702. * Register this object as stream wrapper
  1703. *
  1704. * @param string $name Protocol name
  1705. */
  1706. public function registerStreamWrapper($name = 'azure')
  1707. {
  1708. /**
  1709. * @see Zend_Service_WindowsAzure_Storage_Blob_Stream
  1710. */
  1711. require_once 'Zend/Service/WindowsAzure/Storage/Blob/Stream.php';
  1712. stream_register_wrapper($name, 'Zend_Service_WindowsAzure_Storage_Blob_Stream');
  1713. $this->registerAsClient($name);
  1714. }
  1715. /**
  1716. * Unregister this object as stream wrapper
  1717. *
  1718. * @param string $name Protocol name
  1719. * @return Zend_Service_WindowsAzure_Storage_Blob
  1720. */
  1721. public function unregisterStreamWrapper($name = 'azure')
  1722. {
  1723. stream_wrapper_unregister($name);
  1724. $this->unregisterAsClient($name);
  1725. }
  1726. /**
  1727. * Create resource name
  1728. *
  1729. * @param string $containerName Container name
  1730. * @param string $blobName Blob name
  1731. * @return string
  1732. */
  1733. public static function createResourceName($containerName = '', $blobName = '')
  1734. {
  1735. // Resource name
  1736. $resourceName = $containerName . '/' . $blobName;
  1737. if ($containerName === '' || $containerName === '$root') {
  1738. $resourceName = $blobName;
  1739. }
  1740. if ($blobName === '') {
  1741. $resourceName = $containerName;
  1742. }
  1743. return $resourceName;
  1744. }
  1745. /**
  1746. * Is valid container name?
  1747. *
  1748. * @param string $containerName Container name
  1749. * @return boolean
  1750. */
  1751. public static function isValidContainerName($containerName = '')
  1752. {
  1753. if ($containerName == '$root') {
  1754. return true;
  1755. }
  1756. if (preg_match("/^[a-z0-9][a-z0-9-]*$/", $containerName) === 0) {
  1757. return false;
  1758. }
  1759. if (strpos($containerName, '--') !== false) {
  1760. return false;
  1761. }
  1762. if (strtolower($containerName) != $containerName) {
  1763. return false;
  1764. }
  1765. if (strlen($containerName) < 3 || strlen($containerName) > 63) {
  1766. return false;
  1767. }
  1768. if (substr($containerName, -1) == '-') {
  1769. return false;
  1770. }
  1771. return true;
  1772. }
  1773. /**
  1774. * Get error message from Zend_Http_Response
  1775. *
  1776. * @param Zend_Http_Response $response Repsonse
  1777. * @param string $alternativeError Alternative error message
  1778. * @return string
  1779. */
  1780. protected function _getErrorMessage(Zend_Http_Response $response, $alternativeError = 'Unknown error.')
  1781. {
  1782. $response = $this->_parseResponse($response);
  1783. if ($response && $response->Message) {
  1784. return (string)$response->Message;
  1785. } else {
  1786. return $alternativeError;
  1787. }
  1788. }
  1789. /**
  1790. * Generate block id
  1791. *
  1792. * @param int $part Block number
  1793. * @return string Windows Azure Blob Storage block number
  1794. */
  1795. protected function _generateBlockId($part = 0)
  1796. {
  1797. $returnValue = $part;
  1798. while (strlen($returnValue) < 64) {
  1799. $returnValue = '0' . $returnValue;
  1800. }
  1801. return $returnValue;
  1802. }
  1803. }