PageRenderTime 142ms CodeModel.GetById 85ms app.highlight 34ms RepoModel.GetById 14ms app.codeStats 1ms

/app/lib/core/Zend/Service/WindowsAzure/Storage/Blob.php

https://bitbucket.org/Sinfin/pawtucket
PHP | 2001 lines | 1188 code | 198 blank | 615 comment | 292 complexity | bfc3a00361d0401d4c81e2225b6fd36b MD5 | raw file

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

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

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