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

/blog/wp-content/plugins/w3-total-cache/lib/Microsoft/WindowsAzure/Storage/Blob.php

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