PageRenderTime 80ms CodeModel.GetById 3ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 1ms

/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

Large files files are truncated, but you can click here to view the full file

   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/**
  37 * @see Microsoft_WindowsAzure_Credentials_CredentialsAbstract_SharedKey
  38 */
  39require_once 'Microsoft/WindowsAzure/Credentials/SharedKey.php';
  40
  41/**
  42 * @see Microsoft_WindowsAzure_Credentials_SharedAccessSignature
  43 */
  44require_once 'Microsoft/WindowsAzure/Credentials/SharedAccessSignature.php';
  45
  46/**
  47 * @see Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract
  48 */
  49require_once 'Microsoft/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php';
  50
  51/**
  52 * @see Microsoft_Http_Client
  53 */
  54require_once 'Microsoft/Http/Client.php';
  55
  56/**
  57 * @see Microsoft_Http_Response
  58 */
  59require_once 'Microsoft/Http/Response.php';
  60
  61/**
  62 * @see Microsoft_WindowsAzure_Storage
  63 */
  64require_once 'Microsoft/WindowsAzure/Storage.php';
  65
  66/**
  67 * @see Microsoft_WindowsAzure_Storage_BlobContainer
  68 */
  69require_once 'Microsoft/WindowsAzure/Storage/BlobContainer.php';
  70
  71/**
  72 * @see Microsoft_WindowsAzure_Storage_BlobInstance
  73 */
  74require_once 'Microsoft/WindowsAzure/Storage/BlobInstance.php';
  75
  76/**
  77 * @see Microsoft_WindowsAzure_Storage_PageRegionInstance
  78 */
  79require_once 'Microsoft/WindowsAzure/Storage/PageRegionInstance.php';
  80
  81/**
  82 * @see Microsoft_WindowsAzure_Storage_LeaseInstance
  83 */
  84require_once 'Microsoft/WindowsAzure/Storage/LeaseInstance.php';
  85
  86/**
  87 * @see Microsoft_WindowsAzure_Storage_SignedIdentifier
  88 */
  89require_once 'Microsoft/WindowsAzure/Storage/SignedIdentifier.php';
  90
  91/**
  92 * @see Microsoft_WindowsAzure_Exception
  93 */
  94require_once 'Microsoft/WindowsAzure/Exception.php';
  95
  96
  97/**
  98 * @category   Microsoft
  99 * @package    Microsoft_WindowsAzure
 100 * @subpackage Storage
 101 * @copyright  Copyright (c) 2009 - 2010, RealDolmen (http://www.realdolmen.com)
 102 * @license    http://phpazure.codeplex.com/license
 103 */
 104class Microsoft_WindowsAzure_Storage_Blob extends Microsoft_WindowsAzure_Storage
 105{
 106	/**
 107	 * ACL - Private access
 108	 */
 109	const ACL_PRIVATE = null;
 110
 111	/**
 112	 * ACL - Public access (read all blobs)
 113	 *
 114	 * @deprecated Use ACL_PUBLIC_CONTAINER or ACL_PUBLIC_BLOB instead.
 115	 */
 116	const ACL_PUBLIC = 'container';
 117	
 118	/**
 119	 * ACL - Blob Public access (read all blobs)
 120	 */
 121	const ACL_PUBLIC_BLOB = 'blob';
 122
 123	/**
 124	 * ACL - Container Public access (enumerate and read all blobs)
 125	 */
 126	const ACL_PUBLIC_CONTAINER = 'container';
 127
 128	/**
 129	 * Blob lease constants
 130	 */
 131	const LEASE_ACQUIRE = 'acquire';
 132	const LEASE_RENEW   = 'renew';
 133	const LEASE_RELEASE = 'release';
 134	const LEASE_BREAK   = 'break';
 135
 136	/**
 137	 * Maximal blob size (in bytes)
 138	 */
 139	const MAX_BLOB_SIZE = 67108864;
 140
 141	/**
 142	 * Maximal blob transfer size (in bytes)
 143	 */
 144	const MAX_BLOB_TRANSFER_SIZE = 4194304;
 145
 146	/**
 147	 * Blob types
 148	 */
 149	const BLOBTYPE_BLOCK = 'BlockBlob';
 150	const BLOBTYPE_PAGE  = 'PageBlob';
 151
 152	/**
 153	 * Put page write options
 154	 */
 155	const PAGE_WRITE_UPDATE = 'update';
 156	const PAGE_WRITE_CLEAR  = 'clear';
 157
 158	/**
 159	 * Stream wrapper clients
 160	 *
 161	 * @var array
 162	 */
 163	protected static $_wrapperClients = array();
 164
 165	/**
 166	 * SharedAccessSignature credentials
 167	 *
 168	 * @var Microsoft_WindowsAzure_Credentials_SharedAccessSignature
 169	 */
 170	private $_sharedAccessSignatureCredentials = null;
 171
 172	/**
 173	 * Creates a new Microsoft_WindowsAzure_Storage_Blob instance
 174	 *
 175	 * @param string $host Storage host name
 176	 * @param string $accountName Account name for Windows Azure
 177	 * @param string $accountKey Account key for Windows Azure
 178	 * @param boolean $usePathStyleUri Use path-style URI's
 179	 * @param Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
 180	 */
 181	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)
 182	{
 183		parent::__construct($host, $accountName, $accountKey, $usePathStyleUri, $retryPolicy);
 184
 185		// API version
 186		$this->_apiVersion = '2009-09-19';
 187
 188		// SharedAccessSignature credentials
 189		$this->_sharedAccessSignatureCredentials = new Microsoft_WindowsAzure_Credentials_SharedAccessSignature($accountName, $accountKey, $usePathStyleUri);
 190	}
 191
 192	/**
 193	 * Check if a blob exists
 194	 *
 195	 * @param string $containerName Container name
 196	 * @param string $blobName      Blob name
 197	 * @param string $snapshotId    Snapshot identifier
 198	 * @return boolean
 199	 */
 200	public function blobExists($containerName = '', $blobName = '', $snapshotId = null)
 201	{
 202		if ($containerName === '') {
 203			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 204		}
 205		if (!self::isValidContainerName($containerName)) {
 206			throw new Microsoft_WindowsAzure_Exception('Container name does not adhere to container naming conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
 207		}
 208		if ($blobName === '') {
 209			throw new Microsoft_WindowsAzure_Exception('Blob name is not specified.');
 210		}
 211
 212		// Get blob instance
 213		try {
 214			$this->getBlobInstance($containerName, $blobName, $snapshotId);
 215		} catch (Microsoft_WindowsAzure_Exception $e) {
 216			return false;
 217		}
 218
 219		return true;
 220	}
 221
 222	/**
 223	 * Check if a container exists
 224	 *
 225	 * @param string $containerName Container name
 226	 * @return boolean
 227	 */
 228	public function containerExists($containerName = '')
 229	{
 230		if ($containerName === '') {
 231			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 232		}
 233		if (!self::isValidContainerName($containerName)) {
 234			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.');
 235		}
 236			
 237		// List containers
 238		$containers = $this->listContainers($containerName, 1);
 239		foreach ($containers as $container) {
 240			if ($container->Name == $containerName) {
 241				return true;
 242			}
 243		}
 244
 245		return false;
 246	}
 247
 248	/**
 249	 * Create container
 250	 *
 251	 * @param string $containerName Container name
 252	 * @param array  $metadata      Key/value pairs of meta data
 253	 * @return object Container properties
 254	 * @throws Microsoft_WindowsAzure_Exception
 255	 */
 256	public function createContainer($containerName = '', $metadata = array())
 257	{
 258		if ($containerName === '') {
 259			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 260		}
 261		if (!self::isValidContainerName($containerName)) {
 262			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.');
 263		}
 264		if (!is_array($metadata)) {
 265			throw new Microsoft_WindowsAzure_Exception('Meta data should be an array of key and value pairs.');
 266		}
 267			
 268		// Create metadata headers
 269		$headers = array();
 270		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
 271
 272		// Perform request
 273		$response = $this->_performRequest($containerName, '?restype=container', Microsoft_Http_Client::PUT, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
 274		if ($response->isSuccessful()) {
 275			return new Microsoft_WindowsAzure_Storage_BlobContainer(
 276			$containerName,
 277			$response->getHeader('Etag'),
 278			$response->getHeader('Last-modified'),
 279			$metadata
 280			);
 281		} else {
 282			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
 283		}
 284	}
 285	
 286	/**
 287	 * Create container if it does not exist
 288	 *
 289	 * @param string $containerName Container name
 290	 * @param array  $metadata      Key/value pairs of meta data
 291	 * @throws Microsoft_WindowsAzure_Exception
 292	 */
 293	public function createContainerIfNotExists($containerName = '', $metadata = array())
 294	{
 295		if (!$this->containerExists($containerName)) {
 296			$this->createContainer($containerName, $metadata);
 297		}
 298	}
 299
 300	/**
 301	 * Get container ACL
 302	 *
 303	 * @param string $containerName Container name
 304	 * @param bool   $signedIdentifiers Display only private/blob/container or display signed identifiers?
 305	 * @return string Acl, to be compared with Microsoft_WindowsAzure_Storage_Blob::ACL_*
 306	 * @throws Microsoft_WindowsAzure_Exception
 307	 */
 308	public function getContainerAcl($containerName = '', $signedIdentifiers = false)
 309	{
 310		if ($containerName === '') {
 311			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 312		}
 313		if (!self::isValidContainerName($containerName)) {
 314			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.');
 315		}
 316
 317		// Perform request
 318		$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);
 319		if ($response->isSuccessful()) {
 320			if ($signedIdentifiers == false)  {
 321				// Only private/blob/container
 322				$accessType = $response->getHeader(Microsoft_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-public-access');
 323				if (strtolower($accessType) == 'true') {
 324					$accessType = self::ACL_PUBLIC_CONTAINER;
 325				}
 326				return $accessType;
 327			} else {
 328				// Parse result
 329				$result = $this->_parseResponse($response);
 330				if (!$result) {
 331					return array();
 332				}
 333
 334				$entries = null;
 335				if ($result->SignedIdentifier) {
 336					if (count($result->SignedIdentifier) > 1) {
 337						$entries = $result->SignedIdentifier;
 338					} else {
 339						$entries = array($result->SignedIdentifier);
 340					}
 341				}
 342
 343				// Return value
 344				$returnValue = array();
 345				foreach ($entries as $entry) {
 346					$returnValue[] = new Microsoft_WindowsAzure_Storage_SignedIdentifier(
 347					$entry->Id,
 348					$entry->AccessPolicy ? $entry->AccessPolicy->Start ? $entry->AccessPolicy->Start : '' : '',
 349					$entry->AccessPolicy ? $entry->AccessPolicy->Expiry ? $entry->AccessPolicy->Expiry : '' : '',
 350					$entry->AccessPolicy ? $entry->AccessPolicy->Permission ? $entry->AccessPolicy->Permission : '' : ''
 351					);
 352				}
 353
 354				// Return
 355				return $returnValue;
 356			}
 357		} else {
 358			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
 359		}
 360	}
 361
 362	/**
 363	 * Set container ACL
 364	 *
 365	 * @param string $containerName Container name
 366	 * @param bool $acl Microsoft_WindowsAzure_Storage_Blob::ACL_*
 367	 * @param array $signedIdentifiers Signed identifiers
 368	 * @throws Microsoft_WindowsAzure_Exception
 369	 */
 370	public function setContainerAcl($containerName = '', $acl = self::ACL_PRIVATE, $signedIdentifiers = array())
 371	{
 372		if ($containerName === '') {
 373			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 374		}
 375		if (!self::isValidContainerName($containerName)) {
 376			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.');
 377		}
 378
 379		// Headers
 380		$headers = array();
 381
 382		// Acl specified?
 383		if ($acl != self::ACL_PRIVATE && !is_null($acl) && $acl != '') {
 384			$headers[Microsoft_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-public-access'] = $acl;
 385		}
 386
 387		// Policies
 388		$policies = null;
 389		if (is_array($signedIdentifiers) && count($signedIdentifiers) > 0) {
 390			$policies  = '';
 391			$policies .= '<?xml version="1.0" encoding="utf-8"?>' . "\r\n";
 392			$policies .= '<SignedIdentifiers>' . "\r\n";
 393			foreach ($signedIdentifiers as $signedIdentifier) {
 394				$policies .= '  <SignedIdentifier>' . "\r\n";
 395				$policies .= '    <Id>' . $signedIdentifier->Id . '</Id>' . "\r\n";
 396				$policies .= '    <AccessPolicy>' . "\r\n";
 397				if ($signedIdentifier->Start != '')
 398				$policies .= '      <Start>' . $signedIdentifier->Start . '</Start>' . "\r\n";
 399				if ($signedIdentifier->Expiry != '')
 400				$policies .= '      <Expiry>' . $signedIdentifier->Expiry . '</Expiry>' . "\r\n";
 401				if ($signedIdentifier->Permissions != '')
 402				$policies .= '      <Permission>' . $signedIdentifier->Permissions . '</Permission>' . "\r\n";
 403				$policies .= '    </AccessPolicy>' . "\r\n";
 404				$policies .= '  </SignedIdentifier>' . "\r\n";
 405			}
 406			$policies .= '</SignedIdentifiers>' . "\r\n";
 407		}
 408
 409		// Perform request
 410		$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);
 411		if (!$response->isSuccessful()) {
 412			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
 413		}
 414	}
 415
 416	/**
 417	 * Get container
 418	 *
 419	 * @param string $containerName  Container name
 420	 * @return Microsoft_WindowsAzure_Storage_BlobContainer
 421	 * @throws Microsoft_WindowsAzure_Exception
 422	 */
 423	public function getContainer($containerName = '')
 424	{
 425		if ($containerName === '') {
 426			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 427		}
 428		if (!self::isValidContainerName($containerName)) {
 429			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.');
 430		}
 431
 432		// Perform request
 433		$response = $this->_performRequest($containerName, '?restype=container', Microsoft_Http_Client::GET, array(), false, null, Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
 434		if ($response->isSuccessful()) {
 435			// Parse metadata
 436			$metadata = $this->_parseMetadataHeaders($response->getHeaders());
 437
 438			// Return container
 439			return new Microsoft_WindowsAzure_Storage_BlobContainer(
 440			$containerName,
 441			$response->getHeader('Etag'),
 442			$response->getHeader('Last-modified'),
 443			$metadata
 444			);
 445		} else {
 446			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
 447		}
 448	}
 449
 450	/**
 451	 * Get container metadata
 452	 *
 453	 * @param string $containerName  Container name
 454	 * @return array Key/value pairs of meta data
 455	 * @throws Microsoft_WindowsAzure_Exception
 456	 */
 457	public function getContainerMetadata($containerName = '')
 458	{
 459		if ($containerName === '') {
 460			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 461		}
 462		if (!self::isValidContainerName($containerName)) {
 463			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.');
 464		}
 465
 466		return $this->getContainer($containerName)->Metadata;
 467	}
 468
 469	/**
 470	 * Set container metadata
 471	 *
 472	 * 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.
 473	 *
 474	 * @param string $containerName      Container name
 475	 * @param array  $metadata           Key/value pairs of meta data
 476	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
 477	 * @throws Microsoft_WindowsAzure_Exception
 478	 */
 479	public function setContainerMetadata($containerName = '', $metadata = array(), $additionalHeaders = array())
 480	{
 481		if ($containerName === '') {
 482			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 483		}
 484		if (!self::isValidContainerName($containerName)) {
 485			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.');
 486		}
 487		if (!is_array($metadata)) {
 488			throw new Microsoft_WindowsAzure_Exception('Meta data should be an array of key and value pairs.');
 489		}
 490		if (count($metadata) == 0) {
 491			return;
 492		}
 493
 494		// Create metadata headers
 495		$headers = array();
 496		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
 497
 498		// Additional headers?
 499		foreach ($additionalHeaders as $key => $value) {
 500			$headers[$key] = $value;
 501		}
 502
 503		// Perform request
 504		$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);
 505		if (!$response->isSuccessful()) {
 506			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
 507		}
 508	}
 509
 510	/**
 511	 * Delete container
 512	 *
 513	 * @param string $containerName      Container name
 514	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
 515	 * @throws Microsoft_WindowsAzure_Exception
 516	 */
 517	public function deleteContainer($containerName = '', $additionalHeaders = array())
 518	{
 519		if ($containerName === '') {
 520			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 521		}
 522		if (!self::isValidContainerName($containerName)) {
 523			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.');
 524		}
 525			
 526		// Additional headers?
 527		$headers = array();
 528		foreach ($additionalHeaders as $key => $value) {
 529			$headers[$key] = $value;
 530		}
 531
 532		// Perform request
 533		$response = $this->_performRequest($containerName, '?restype=container', Microsoft_Http_Client::DELETE, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
 534		if (!$response->isSuccessful()) {
 535			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
 536		}
 537	}
 538
 539	/**
 540	 * List containers
 541	 *
 542	 * @param string $prefix     Optional. Filters the results to return only containers whose name begins with the specified prefix.
 543	 * @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)
 544	 * @param string $marker     Optional string value that identifies the portion of the list to be returned with the next list operation.
 545	 * @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')
 546	 * @param int    $currentResultCount Current result count (internal use)
 547	 * @return array
 548	 * @throws Microsoft_WindowsAzure_Exception
 549	 */
 550	public function listContainers($prefix = null, $maxResults = null, $marker = null, $include = null, $currentResultCount = 0)
 551	{
 552		// Build query string
 553		$queryString = array('comp=list');
 554		if (!is_null($prefix)) {
 555			$queryString[] = 'prefix=' . $prefix;
 556		}
 557		if (!is_null($maxResults)) {
 558			$queryString[] = 'maxresults=' . $maxResults;
 559		}
 560		if (!is_null($marker)) {
 561			$queryString[] = 'marker=' . $marker;
 562		}
 563		if (!is_null($include)) {
 564			$queryString[] = 'include=' . $include;
 565		}
 566		$queryString = self::createQueryStringFromArray($queryString);
 567		 
 568		// Perform request
 569		$response = $this->_performRequest('', $queryString, Microsoft_Http_Client::GET, array(), false, null, Microsoft_WindowsAzure_Storage::RESOURCE_CONTAINER, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_LIST);
 570		if ($response->isSuccessful()) {
 571			$xmlContainers = $this->_parseResponse($response)->Containers->Container;
 572			$xmlMarker = (string)$this->_parseResponse($response)->NextMarker;
 573
 574			$containers = array();
 575			if (!is_null($xmlContainers)) {
 576				for ($i = 0; $i < count($xmlContainers); $i++) {
 577					$containers[] = new Microsoft_WindowsAzure_Storage_BlobContainer(
 578					(string)$xmlContainers[$i]->Name,
 579					(string)$xmlContainers[$i]->Etag,
 580					(string)$xmlContainers[$i]->LastModified,
 581					$this->_parseMetadataElement($xmlContainers[$i])
 582					);
 583				}
 584			}
 585			$currentResultCount = $currentResultCount + count($containers);
 586			if (!is_null($maxResults) && $currentResultCount < $maxResults) {
 587				if (!is_null($xmlMarker) && $xmlMarker != '') {
 588					$containers = array_merge($containers, $this->listContainers($prefix, $maxResults, $xmlMarker, $include, $currentResultCount));
 589				}
 590			}
 591			if (!is_null($maxResults) && count($containers) > $maxResults) {
 592				$containers = array_slice($containers, 0, $maxResults);
 593			}
 594			 
 595			return $containers;
 596		} else {
 597			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
 598		}
 599	}
 600
 601	/**
 602	 * Put blob
 603	 *
 604	 * @param string $containerName      Container name
 605	 * @param string $blobName           Blob name
 606	 * @param string $localFileName      Local file name to be uploaded
 607	 * @param array  $metadata           Key/value pairs of meta data
 608	 * @param string $leaseId            Lease identifier
 609	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
 610	 * @return object Partial blob properties
 611	 * @throws Microsoft_WindowsAzure_Exception
 612	 */
 613	public function putBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
 614	{
 615		if ($containerName === '') {
 616			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 617		}
 618		if (!self::isValidContainerName($containerName)) {
 619			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.');
 620		}
 621		if ($blobName === '') {
 622			throw new Microsoft_WindowsAzure_Exception('Blob name is not specified.');
 623		}
 624		if ($localFileName === '') {
 625			throw new Microsoft_WindowsAzure_Exception('Local file name is not specified.');
 626		}
 627		if (!file_exists($localFileName)) {
 628			throw new Microsoft_WindowsAzure_Exception('Local file not found.');
 629		}
 630		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
 631			throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
 632		}
 633			
 634		// Check file size
 635		if (filesize($localFileName) >= self::MAX_BLOB_SIZE) {
 636			return $this->putLargeBlob($containerName, $blobName, $localFileName, $metadata, $leaseId, $additionalHeaders);
 637		}
 638
 639		// Put the data to Windows Azure Storage
 640		return $this->putBlobData($containerName, $blobName, file_get_contents($localFileName), $metadata, $leaseId, $additionalHeaders);
 641	}
 642
 643	/**
 644	 * Put blob data
 645	 *
 646	 * @param string $containerName      Container name
 647	 * @param string $blobName           Blob name
 648	 * @param mixed  $data      		 Data to store
 649	 * @param array  $metadata           Key/value pairs of meta data
 650	 * @param string $leaseId            Lease identifier
 651	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
 652	 * @return object Partial blob properties
 653	 * @throws Microsoft_WindowsAzure_Exception
 654	 */
 655	public function putBlobData($containerName = '', $blobName = '', $data = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
 656	{
 657		if ($containerName === '') {
 658			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 659		}
 660		if (!self::isValidContainerName($containerName)) {
 661			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.');
 662		}
 663		if ($blobName === '') {
 664			throw new Microsoft_WindowsAzure_Exception('Blob name is not specified.');
 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
 670		// Create metadata headers
 671		$headers = array();
 672		if (!is_null($leaseId)) {
 673			$headers['x-ms-lease-id'] = $leaseId;
 674		}
 675		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
 676
 677		// Additional headers?
 678		foreach ($additionalHeaders as $key => $value) {
 679			$headers[$key] = $value;
 680		}
 681
 682		// Specify blob type
 683		$headers[Microsoft_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_BLOCK;
 684
 685		// Resource name
 686		$resourceName = self::createResourceName($containerName , $blobName);
 687
 688		// Perform request
 689		$response = $this->_performRequest($resourceName, '', Microsoft_Http_Client::PUT, $headers, false, $data, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
 690		if ($response->isSuccessful()) {
 691			return new Microsoft_WindowsAzure_Storage_BlobInstance(
 692			$containerName,
 693			$blobName,
 694			null,
 695			$response->getHeader('Etag'),
 696			$response->getHeader('Last-modified'),
 697			$this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
 698			strlen($data),
 699				'',
 700				'',
 701				'',
 702			false,
 703			$metadata
 704			);
 705		} else {
 706			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
 707		}
 708	}
 709
 710	/**
 711	 * Put large blob (> 64 MB)
 712	 *
 713	 * @param string $containerName Container name
 714	 * @param string $blobName Blob name
 715	 * @param string $localFileName Local file name to be uploaded
 716	 * @param array  $metadata      Key/value pairs of meta data
 717	 * @param string $leaseId       Lease identifier
 718	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
 719	 * @return object Partial blob properties
 720	 * @throws Microsoft_WindowsAzure_Exception
 721	 */
 722	public function putLargeBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
 723	{
 724		if ($containerName === '') {
 725			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 726		}
 727		if (!self::isValidContainerName($containerName)) {
 728			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.');
 729		}
 730		if ($blobName === '') {
 731			throw new Microsoft_WindowsAzure_Exception('Blob name is not specified.');
 732		}
 733		if ($localFileName === '') {
 734			throw new Microsoft_WindowsAzure_Exception('Local file name is not specified.');
 735		}
 736		if (!file_exists($localFileName)) {
 737			throw new Microsoft_WindowsAzure_Exception('Local file not found.');
 738		}
 739		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
 740			throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
 741		}
 742			
 743		// Check file size
 744		if (filesize($localFileName) < self::MAX_BLOB_SIZE) {
 745			return $this->putBlob($containerName, $blobName, $localFileName, $metadata, $leaseId, $additionalHeaders);
 746		}
 747			
 748		// Determine number of parts
 749		$numberOfParts = ceil( filesize($localFileName) / self::MAX_BLOB_TRANSFER_SIZE );
 750
 751		// Generate block id's
 752		$blockIdentifiers = array();
 753		for ($i = 0; $i < $numberOfParts; $i++) {
 754			$blockIdentifiers[] = $this->_generateBlockId($i);
 755		}
 756
 757		// Open file
 758		$fp = fopen($localFileName, 'r');
 759		if ($fp === false) {
 760			throw new Microsoft_WindowsAzure_Exception('Could not open local file.');
 761		}
 762			
 763		// Upload parts
 764		for ($i = 0; $i < $numberOfParts; $i++) {
 765			// Seek position in file
 766			fseek($fp, $i * self::MAX_BLOB_TRANSFER_SIZE);
 767				
 768			// Read contents
 769			$fileContents = fread($fp, self::MAX_BLOB_TRANSFER_SIZE);
 770				
 771			// Put block
 772			$this->putBlock($containerName, $blobName, $blockIdentifiers[$i], $fileContents, $leaseId);
 773				
 774			// Dispose file contents
 775			$fileContents = null;
 776			unset($fileContents);
 777		}
 778
 779		// Close file
 780		fclose($fp);
 781
 782		// Put block list
 783		$this->putBlockList($containerName, $blobName, $blockIdentifiers, $metadata, $leaseId, $additionalHeaders);
 784
 785		// Return information of the blob
 786		return $this->getBlobInstance($containerName, $blobName, null, $leaseId);
 787	}
 788		
 789	/**
 790	 * Put large blob block
 791	 *
 792	 * @param string $containerName Container name
 793	 * @param string $blobName      Blob name
 794	 * @param string $identifier    Block ID
 795	 * @param array  $contents      Contents of the block
 796	 * @param string $leaseId       Lease identifier
 797	 * @throws Microsoft_WindowsAzure_Exception
 798	 */
 799	public function putBlock($containerName = '', $blobName = '', $identifier = '', $contents = '', $leaseId = null)
 800	{
 801		if ($containerName === '') {
 802			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 803		}
 804		if (!self::isValidContainerName($containerName)) {
 805			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.');
 806		}
 807		if ($identifier === '') {
 808			throw new Microsoft_WindowsAzure_Exception('Block identifier is not specified.');
 809		}
 810		if (strlen($contents) > self::MAX_BLOB_TRANSFER_SIZE) {
 811			throw new Microsoft_WindowsAzure_Exception('Block size is too big.');
 812		}
 813		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
 814			throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
 815		}
 816
 817		// Headers
 818		$headers = array();
 819		if (!is_null($leaseId)) {
 820			$headers['x-ms-lease-id'] = $leaseId;
 821		}
 822			
 823		// Resource name
 824		$resourceName = self::createResourceName($containerName , $blobName);
 825
 826		// Upload
 827		$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);
 828		if (!$response->isSuccessful()) {
 829			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
 830		}
 831	}
 832
 833	/**
 834	 * Put block list
 835	 *
 836	 * @param string $containerName      Container name
 837	 * @param string $blobName           Blob name
 838	 * @param array $blockList           Array of block identifiers
 839	 * @param array  $metadata           Key/value pairs of meta data
 840	 * @param string $leaseId            Lease identifier
 841	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
 842	 * @throws Microsoft_WindowsAzure_Exception
 843	 */
 844	public function putBlockList($containerName = '', $blobName = '', $blockList = array(), $metadata = array(), $leaseId = null, $additionalHeaders = array())
 845	{
 846		if ($containerName === '') {
 847			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 848		}
 849		if (!self::isValidContainerName($containerName)) {
 850			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.');
 851		}
 852		if ($blobName === '') {
 853			throw new Microsoft_WindowsAzure_Exception('Blob name is not specified.');
 854		}
 855		if (count($blockList) == 0) {
 856			throw new Microsoft_WindowsAzure_Exception('Block list does not contain any elements.');
 857		}
 858		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
 859			throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
 860		}
 861
 862		// Generate block list
 863		$blocks = '';
 864		foreach ($blockList as $block) {
 865			$blocks .= '  <Latest>' . base64_encode($block) . '</Latest>' . "\n";
 866		}
 867
 868		// Generate block list request
 869		$fileContents = utf8_encode(implode("\n", array(
 870				'<?xml version="1.0" encoding="utf-8"?>',
 871				'<BlockList>',
 872				$blocks,
 873				'</BlockList>'
 874			)));
 875
 876			// Create metadata headers
 877			$headers = array();
 878			if (!is_null($leaseId)) {
 879				$headers['x-ms-lease-id'] = $leaseId;
 880			}
 881			$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
 882
 883			// Additional headers?
 884			foreach ($additionalHeaders as $key => $value) {
 885				$headers[$key] = $value;
 886			}
 887
 888			// Resource name
 889			$resourceName = self::createResourceName($containerName , $blobName);
 890
 891			// Perform request
 892			$response = $this->_performRequest($resourceName, '?comp=blocklist', Microsoft_Http_Client::PUT, $headers, false, $fileContents, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
 893			if (!$response->isSuccessful()) {
 894				throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
 895			}
 896	}
 897
 898	/**
 899	 * Get block list
 900	 *
 901	 * @param string $containerName Container name
 902	 * @param string $blobName      Blob name
 903	 * @param string $snapshotId    Snapshot identifier
 904	 * @param string $leaseId       Lease identifier
 905	 * @param integer $type         Type of block list to retrieve. 0 = all, 1 = committed, 2 = uncommitted
 906	 * @return array
 907	 * @throws Microsoft_WindowsAzure_Exception
 908	 */
 909	public function getBlockList($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $type = 0)
 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 ($type < 0 || $type > 2) {
 921			throw new Microsoft_WindowsAzure_Exception('Invalid type of block list to retrieve.');
 922		}
 923
 924		// Set $blockListType
 925		$blockListType = 'all';
 926		if ($type == 1) {
 927			$blockListType = 'committed';
 928		}
 929		if ($type == 2) {
 930			$blockListType = 'uncommitted';
 931		}
 932
 933		// Headers
 934		$headers = array();
 935		if (!is_null($leaseId)) {
 936			$headers['x-ms-lease-id'] = $leaseId;
 937		}
 938
 939		// Build query string
 940		$queryString = array('comp=blocklist', 'blocklisttype=' . $blockListType);
 941		if (!is_null($snapshotId)) {
 942			$queryString[] = 'snapshot=' . $snapshotId;
 943		}
 944		$queryString = self::createQueryStringFromArray($queryString);
 945
 946		// Resource name
 947		$resourceName = self::createResourceName($containerName , $blobName);
 948			
 949		// Perform request
 950		$response = $this->_performRequest($resourceName, $queryString, Microsoft_Http_Client::GET, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
 951		if ($response->isSuccessful()) {
 952			// Parse response
 953			$blockList = $this->_parseResponse($response);
 954
 955			// Create return value
 956			$returnValue = array();
 957			if ($blockList->CommittedBlocks) {
 958				foreach ($blockList->CommittedBlocks->Block as $block) {
 959					$returnValue['CommittedBlocks'][] = (object)array(
 960			            'Name' => (string)$block->Name,
 961			            'Size' => (string)$block->Size
 962					);
 963				}
 964			}
 965			if ($blockList->UncommittedBlocks)  {
 966				foreach ($blockList->UncommittedBlocks->Block as $block) {
 967					$returnValue['UncommittedBlocks'][] = (object)array(
 968			            'Name' => (string)$block->Name,
 969			            'Size' => (string)$block->Size
 970					);
 971				}
 972			}
 973
 974			return $returnValue;
 975		} else {
 976			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
 977		}
 978	}
 979
 980	/**
 981	 * Create page blob
 982	 *
 983	 * @param string $containerName      Container name
 984	 * @param string $blobName           Blob name
 985	 * @param int    $size      		 Size of the page blob in bytes
 986	 * @param array  $metadata           Key/value pairs of meta data
 987	 * @param string $leaseId            Lease identifier
 988	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
 989	 * @return object Partial blob properties
 990	 * @throws Microsoft_WindowsAzure_Exception
 991	 */
 992	public function createPageBlob($containerName = '', $blobName = '', $size = 0, $metadata = array(), $leaseId = null, $additionalHeaders = array())
 993	{
 994		if ($containerName === '') {
 995			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
 996		}
 997		if (!self::isValidContainerName($containerName)) {
 998			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.');
 999		}
1000		if ($blobName === '') {
1001			throw new Microsoft_WindowsAzure_Exception('Blob name is not specified.');
1002		}
1003		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
1004			throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
1005		}
1006		if ($size <= 0) {
1007			throw new Microsoft_WindowsAzure_Exception('Page blob size must be specified.');
1008		}
1009
1010		// Create metadata headers
1011		$headers = array();
1012		if (!is_null($leaseId)) {
1013			$headers['x-ms-lease-id'] = $leaseId;
1014		}
1015		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
1016
1017		// Additional headers?
1018		foreach ($additionalHeaders as $key => $value) {
1019			$headers[$key] = $value;
1020		}
1021
1022		// Specify blob type & blob length
1023		$headers[Microsoft_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_PAGE;
1024		$headers[Microsoft_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-content-length'] = $size;
1025		$headers['Content-Length'] = 0;
1026
1027		// Resource name
1028		$resourceName = self::createResourceName($containerName , $blobName);
1029
1030		// Perform request
1031		$response = $this->_performRequest($resourceName, '', Microsoft_Http_Client::PUT, $headers, false, '', Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
1032		if ($response->isSuccessful()) {
1033			return new Microsoft_WindowsAzure_Storage_BlobInstance(
1034			$containerName,
1035			$blobName,
1036			null,
1037			$response->getHeader('Etag'),
1038			$response->getHeader('Last-modified'),
1039			$this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
1040			$size,
1041				'',
1042				'',
1043				'',
1044			false,
1045			$metadata
1046			);
1047		} else {
1048			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
1049		}
1050	}
1051
1052	/**
1053	 * Put page in page blob
1054	 *
1055	 * @param string $containerName      Container name
1056	 * @param string $blobName           Blob name
1057	 * @param int    $startByteOffset    Start byte offset
1058	 * @param int    $endByteOffset      End byte offset
1059	 * @param mixed  $contents			 Page contents
1060	 * @param string $writeMethod        Write method (Microsoft_WindowsAzure_Storage_Blob::PAGE_WRITE_*)
1061	 * @param string $leaseId            Lease identifier
1062	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
1063	 * @throws Microsoft_WindowsAzure_Exception
1064	 */
1065	public function putPage($containerName = '', $blobName = '', $startByteOffset = 0, $endByteOffset = 0, $contents = '', $writeMethod = self::PAGE_WRITE_UPDATE, $leaseId = null, $additionalHeaders = array())
1066	{
1067		if ($containerName === '') {
1068			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
1069		}
1070		if (!self::isValidContainerName($containerName)) {
1071			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.');
1072		}
1073		if ($blobName === '') {
1074			throw new Microsoft_WindowsAzure_Exception('Blob name is not specified.');
1075		}
1076		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
1077			throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
1078		}
1079		if ($startByteOffset % 512 != 0) {
1080			throw new Microsoft_WindowsAzure_Exception('Start byte offset must be a modulus of 512.');
1081		}
1082		if (($endByteOffset + 1) % 512 != 0) {
1083			throw new Microsoft_WindowsAzure_Exception('End byte offset must be a modulus of 512 minus 1.');
1084		}
1085
1086		// Determine size
1087		$size = strlen($contents);
1088		if ($size >= self::MAX_BLOB_TRANSFER_SIZE) {
1089			throw new Microsoft_WindowsAzure_Exception('Page blob size must not be larger than ' + self::MAX_BLOB_TRANSFER_SIZE . ' bytes.');
1090		}
1091
1092		// Create metadata headers
1093		$headers = array();
1094		if (!is_null($leaseId)) {
1095			$headers['x-ms-lease-id'] = $leaseId;
1096		}
1097
1098		// Additional headers?
1099		foreach ($additionalHeaders as $key => $value) {
1100			$headers[$key] = $value;
1101		}
1102
1103		// Specify range
1104		$headers['Range'] = 'bytes=' . $startByteOffset . '-' . $endByteOffset;
1105
1106		// Write method
1107		$headers[Microsoft_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'page-write'] = $writeMethod;
1108
1109		// Resource name
1110		$resourceName = self::createResourceName($containerName , $blobName);
1111
1112		// Perform request
1113		$response = $this->_performRequest($resourceName, '?comp=page', Microsoft_Http_Client::PUT, $headers, false, $contents, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
1114		if (!$response->isSuccessful()) {
1115			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
1116		}
1117	}
1118
1119	/**
1120	 * Put page in page blob
1121	 *
1122	 * @param string $containerName      Container name
1123	 * @param string $blobName           Blob name
1124	 * @param int    $startByteOffset    Start byte offset
1125	 * @param int    $endByteOffset      End byte offset
1126	 * @param string $leaseId            Lease identifier
1127	 * @return array Array of page ranges
1128	 * @throws Microsoft_WindowsAzure_Exception
1129	 */
1130	public function getPageRegions($containerName = '', $blobName = '', $startByteOffset = 0, $endByteOffset = 0, $leaseId = null)
1131	{
1132		if ($containerName === '') {
1133			throw new Microsoft_WindowsAzure_Exception('Container name is not specified.');
1134		}
1135		if (!self::isValidContainerName($containerName)) {
1136			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.');
1137		}
1138		if ($blobName === '') {
1139			throw new Microsoft_WindowsAzure_Exception('Blob name is not specified.');
1140		}
1141		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
1142			throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
1143		}
1144		if ($startByteOffset % 512 != 0) {
1145			throw new Microsoft_WindowsAzure_Exception('Start byte offset must be a modulus of 512.');
1146		}
1147		if ($endByteOffset > 0 && ($endByteOffset + 1) % 512 != 0) {
1148			throw new Microsoft_WindowsAzure_Exception('End byte offset must be a modulus of 512 minus 1.');
1149		}
1150
1151		// Create metadata headers
1152		$headers = array();
1153		if (!is_null($leaseId)) {
1154			$headers['x-ms-lease-id'] = $leaseId;
1155		}
1156
1157		// Specify range?
1158		if ($endByteOffset > 0) {
1159			$headers['Range'] = 'bytes=' . $startByteOffset . '-' . $endByteOffset;
1160		}
1161
1162		// Resource name
1163		$resourceName = self::createResourceName($containerName , $blobName);
1164
1165		// Perform request
1166		$response = $this->_performRequest($resourceName, '?comp=pagelist', Microsoft_Http_Client::GET, $headers, false, null, Microsoft_WindowsAzure_Storage::RESOURCE_BLOB, Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
1167		if ($response->isSuccessful()) {
1168			$result = $this->_parseResponse($response);
1169			$xmlRanges = null;
1170			if (count($result->PageRange) > 1) {
1171				$xmlRanges = $result->PageRange;
1172			} else {
1173				$xmlRanges = array($result->PageRange);
1174			}
1175
1176			$ranges = array();
1177			for ($i = 0; $i < count($xmlRanges); $i++) {
1178				$ranges[] = new Microsoft_WindowsAzure_Storage_PageRegionInstance(
1179				(int)$xmlRanges[$i]->Start,
1180				(int)$xmlRanges[$i]->End
1181				);
1182			}
1183			 
1184			return $ranges;
1185		} else {
1186			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
1187		}
1188	}
1189		
1190	/**
1191	 * Copy blob
1192	 *
1193	 * @param string $sourceContainerName       Source container name
1194	 * @param string $sourceBlobName            Source blob name
1195	 * @param string $destinationContainerName  Destination container name
1196	 * @param string $destinationBlobName       Destination blob name
1197	 * @param array  $metadata                  Key/value pairs of meta data
1198	 * @param string $sourceSnapshotId          Source snapshot identifier
1199	 * @param string $destinationLeaseId        Destination lease identifier
1200	 * @param array  $additionalHeaders         Additional headers. See http://msdn.microsoft.com/en-us/library/dd894037.aspx for more information.
1201	 * @return object Partial blob properties
1202	 * @throws Microsoft_WindowsAzure_Exception
1203	 */
1204	public function copyBlob($sourceContainerName = '', $sourceBlobName = '', $destinationContainerName = '', $destinationBlobName = '', $metadata = array(), $sourceSnapshotId = null, $destinationLeaseId = null, $additionalHeaders = array())
1205	{
1206		if ($sourceContainerName === '') {
1207			throw new Microsoft_WindowsAzure_Exception('Source container name is not specified.');
1208		}
1209		if (!self::isValidContainerName($sourceContainerName)) {
1210			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.');
1211		}
1212		if ($sourceBlobName === '') {
1213			throw new Microsoft_WindowsAzure_Exception('Source blob name is not specified.');
1214		}
1215		if ($destinationContainerName === '') {
1216			throw new Microsoft_WindowsAzure_Exception('Destination container name is not specified.');
1217		}
1218		if (!self::isValidContainerName($destinationContainerName)) {
1219			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.');
1220		}
1221		if ($destinationBlobName === '') {
1222			throw new Microsoft_WindowsAzure_Exception('Destination blob name is not specified.');
1223		}
1224		if ($sourceContainerName === '$root' && strpos($sourceBlobName, '/') !== false) {
1225			throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
1226		}
1227		if ($destinationContainerName === '$root' && strpos($destinationBlobName, '/') !== false) {
1228			throw new Microsoft_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a fo…

Large files files are truncated, but you can click here to view the full file