PageRenderTime 62ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/Microsoft/WindowsAzure/Storage/Blob.php

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