PageRenderTime 86ms CodeModel.GetById 3ms app.highlight 58ms RepoModel.GetById 1ms app.codeStats 1ms

/Zend/Service/WindowsAzure/Storage/Blob.php

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

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