PageRenderTime 71ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/branches/v2.1.0/library/Microsoft/WindowsAzure/Storage/Blob.php

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