PageRenderTime 464ms CodeModel.GetById 124ms app.highlight 152ms RepoModel.GetById 115ms app.codeStats 1ms

/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

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

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

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