web/lib/Zend/Service/WindowsAzure/Storage/Blob.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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: Blob.php 23167 2010-10-19 17:53:31Z mabe $
       
    21  */
       
    22 
       
    23 /**
       
    24  * @see Zend_Service_WindowsAzure_Credentials_CredentialsAbstract_SharedKey
       
    25  */
       
    26 require_once 'Zend/Service/WindowsAzure/Credentials/SharedKey.php';
       
    27 
       
    28 /**
       
    29  * @see Zend_Service_WindowsAzure_Credentials_SharedAccessSignature
       
    30  */
       
    31 require_once 'Zend/Service/WindowsAzure/Credentials/SharedAccessSignature.php';
       
    32 
       
    33 /**
       
    34  * @see Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
       
    35  */
       
    36 require_once 'Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php';
       
    37 
       
    38 /**
       
    39  * @see Zend_Http_Client
       
    40  */
       
    41 require_once 'Zend/Http/Client.php';
       
    42 
       
    43 /**
       
    44  * @see Zend_Http_Response
       
    45  */
       
    46 require_once 'Zend/Http/Response.php';
       
    47 
       
    48 /**
       
    49  * @see Zend_Service_WindowsAzure_Storage
       
    50  */
       
    51 require_once 'Zend/Service/WindowsAzure/Storage.php';
       
    52 
       
    53 /**
       
    54  * @see Zend_Service_WindowsAzure_Storage_BlobContainer
       
    55  */
       
    56 require_once 'Zend/Service/WindowsAzure/Storage/BlobContainer.php';
       
    57 
       
    58 /**
       
    59  * @see Zend_Service_WindowsAzure_Storage_BlobInstance
       
    60  */
       
    61 require_once 'Zend/Service/WindowsAzure/Storage/BlobInstance.php';
       
    62 
       
    63 /**
       
    64  * @see Zend_Service_WindowsAzure_Storage_PageRegionInstance
       
    65  */
       
    66 require_once 'Zend/Service/WindowsAzure/Storage/PageRegionInstance.php';
       
    67 
       
    68 /**
       
    69  * @see Zend_Service_WindowsAzure_Storage_LeaseInstance
       
    70  */
       
    71 require_once 'Zend/Service/WindowsAzure/Storage/LeaseInstance.php';
       
    72 
       
    73 /**
       
    74  * @see Zend_Service_WindowsAzure_Storage_SignedIdentifier
       
    75  */
       
    76 require_once 'Zend/Service/WindowsAzure/Storage/SignedIdentifier.php';
       
    77 
       
    78 /**
       
    79  * @see Zend_Service_WindowsAzure_Exception
       
    80  */
       
    81 require_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  */
       
    91 class 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 && $acl !== null && $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 ($prefix !== null) {
       
   528 			$queryString[] = 'prefix=' . $prefix;
       
   529 		}
       
   530 		if ($maxResults !== null) {
       
   531 			$queryString[] = 'maxresults=' . $maxResults;
       
   532 		}
       
   533 		if ($marker !== null) {
       
   534 			$queryString[] = 'marker=' . $marker;
       
   535 		}
       
   536 		if ($include !== null) {
       
   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 ($xmlContainers !== null) {
       
   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 ($maxResults !== null && $currentResultCount < $maxResults) {
       
   560 				if ($xmlMarker !== null && $xmlMarker != '') {
       
   561 					$containers = array_merge($containers, $this->listContainers($prefix, $maxResults, $xmlMarker, $include, $currentResultCount));
       
   562 				}
       
   563 			}
       
   564 			if ($maxResults !== null && 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 ($leaseId !== null) {
       
   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 ($leaseId !== null) {
       
   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 ($leaseId !== null) {
       
   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 ($leaseId !== null) {
       
   908 			$headers['x-ms-lease-id'] = $leaseId;
       
   909 		}
       
   910 
       
   911 		// Build query string
       
   912 		$queryString = array('comp=blocklist', 'blocklisttype=' . $blockListType);
       
   913 		if ($snapshotId !== null) {
       
   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 ($leaseId !== null) {
       
   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 ($leaseId !== null) {
       
  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 ($leaseId !== null) {
       
  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 ($destinationLeaseId !== null) {
       
  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 ($sourceSnapshotId !== null) {
       
  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 conventions. See http://msdn.microsoft.com/en-us/library/dd135715.aspx for more information.');
       
  1265 		}
       
  1266 		if ($blobName === '') {
       
  1267 			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
       
  1268 		}
       
  1269 		if ($localFileName === '') {
       
  1270 			throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.');
       
  1271 		}
       
  1272 
       
  1273 		// Fetch data
       
  1274 		file_put_contents($localFileName, $this->getBlobData($containerName, $blobName, $snapshotId, $leaseId, $additionalHeaders));
       
  1275 	}
       
  1276 
       
  1277 	/**
       
  1278 	 * Get blob data
       
  1279 	 *
       
  1280 	 * @param string $containerName      Container name
       
  1281 	 * @param string $blobName           Blob name
       
  1282 	 * @param string $snapshotId         Snapshot identifier
       
  1283 	 * @param string $leaseId            Lease identifier
       
  1284 	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
       
  1285 	 * @return mixed Blob contents
       
  1286 	 * @throws Zend_Service_WindowsAzure_Exception
       
  1287 	 */
       
  1288 	public function getBlobData($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
       
  1289 	{
       
  1290 		if ($containerName === '') {
       
  1291 			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
       
  1292 		}
       
  1293 		if (!self::isValidContainerName($containerName)) {
       
  1294 			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.');
       
  1295 		}
       
  1296 		if ($blobName === '') {
       
  1297 			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
       
  1298 		}
       
  1299 
       
  1300 		// Build query string
       
  1301 		$queryString = array();
       
  1302 		if ($snapshotId !== null) {
       
  1303 			$queryString[] = 'snapshot=' . $snapshotId;
       
  1304 		}
       
  1305 		$queryString = self::createQueryStringFromArray($queryString);
       
  1306 
       
  1307 		// Additional headers?
       
  1308 		$headers = array();
       
  1309 		if ($leaseId !== null) {
       
  1310 			$headers['x-ms-lease-id'] = $leaseId;
       
  1311 		}
       
  1312 		foreach ($additionalHeaders as $key => $value) {
       
  1313 			$headers[$key] = $value;
       
  1314 		}
       
  1315 
       
  1316 		// Resource name
       
  1317 		$resourceName = self::createResourceName($containerName , $blobName);
       
  1318 
       
  1319 		// Perform request
       
  1320 		$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);
       
  1321 		if ($response->isSuccessful()) {
       
  1322 			return $response->getBody();
       
  1323 		} else {
       
  1324 			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
       
  1325 		}
       
  1326 	}
       
  1327 
       
  1328 	/**
       
  1329 	 * Get blob instance
       
  1330 	 *
       
  1331 	 * @param string $containerName      Container name
       
  1332 	 * @param string $blobName           Blob name
       
  1333 	 * @param string $snapshotId         Snapshot identifier
       
  1334 	 * @param string $leaseId            Lease identifier
       
  1335 	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
       
  1336 	 * @return Zend_Service_WindowsAzure_Storage_BlobInstance
       
  1337 	 * @throws Zend_Service_WindowsAzure_Exception
       
  1338 	 */
       
  1339 	public function getBlobInstance($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
       
  1340 	{
       
  1341 		if ($containerName === '') {
       
  1342 			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
       
  1343 		}
       
  1344 		if (!self::isValidContainerName($containerName)) {
       
  1345 			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.');
       
  1346 		}
       
  1347 		if ($blobName === '') {
       
  1348 			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
       
  1349 		}
       
  1350 		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
       
  1351 			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
       
  1352 		}
       
  1353 
       
  1354 		// Build query string
       
  1355 		$queryString = array();
       
  1356 		if ($snapshotId !== null) {
       
  1357 			$queryString[] = 'snapshot=' . $snapshotId;
       
  1358 		}
       
  1359 		$queryString = self::createQueryStringFromArray($queryString);
       
  1360 		 
       
  1361 		// Additional headers?
       
  1362 		$headers = array();
       
  1363 		if ($leaseId !== null) {
       
  1364 			$headers['x-ms-lease-id'] = $leaseId;
       
  1365 		}
       
  1366 		foreach ($additionalHeaders as $key => $value) {
       
  1367 			$headers[$key] = $value;
       
  1368 		}
       
  1369 
       
  1370 		// Resource name
       
  1371 		$resourceName = self::createResourceName($containerName , $blobName);
       
  1372 
       
  1373 		// Perform request
       
  1374 		$response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::HEAD, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ);
       
  1375 		if ($response->isSuccessful()) {
       
  1376 			// Parse metadata
       
  1377 			$metadata = $this->_parseMetadataHeaders($response->getHeaders());
       
  1378 
       
  1379 			// Return blob
       
  1380 			return new Zend_Service_WindowsAzure_Storage_BlobInstance(
       
  1381 			$containerName,
       
  1382 			$blobName,
       
  1383 			$snapshotId,
       
  1384 			$response->getHeader('Etag'),
       
  1385 			$response->getHeader('Last-modified'),
       
  1386 			$this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
       
  1387 			$response->getHeader('Content-Length'),
       
  1388 			$response->getHeader('Content-Type'),
       
  1389 			$response->getHeader('Content-Encoding'),
       
  1390 			$response->getHeader('Content-Language'),
       
  1391 			$response->getHeader('Cache-Control'),
       
  1392 			$response->getHeader('x-ms-blob-type'),
       
  1393 			$response->getHeader('x-ms-lease-status'),
       
  1394 			false,
       
  1395 			$metadata
       
  1396 			);
       
  1397 		} else {
       
  1398 			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
       
  1399 		}
       
  1400 	}
       
  1401 
       
  1402 	/**
       
  1403 	 * Get blob metadata
       
  1404 	 *
       
  1405 	 * @param string $containerName  Container name
       
  1406 	 * @param string $blobName       Blob name
       
  1407 	 * @param string $snapshotId     Snapshot identifier
       
  1408 	 * @param string $leaseId        Lease identifier
       
  1409 	 * @return array Key/value pairs of meta data
       
  1410 	 * @throws Zend_Service_WindowsAzure_Exception
       
  1411 	 */
       
  1412 	public function getBlobMetadata($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null)
       
  1413 	{
       
  1414 		if ($containerName === '') {
       
  1415 			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
       
  1416 		}
       
  1417 		if (!self::isValidContainerName($containerName)) {
       
  1418 			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.');
       
  1419 		}
       
  1420 		if ($blobName === '') {
       
  1421 			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
       
  1422 		}
       
  1423 		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
       
  1424 			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
       
  1425 		}
       
  1426 
       
  1427 		return $this->getBlobInstance($containerName, $blobName, $snapshotId, $leaseId)->Metadata;
       
  1428 	}
       
  1429 
       
  1430 	/**
       
  1431 	 * Set blob metadata
       
  1432 	 *
       
  1433 	 * Calling the Set Blob Metadata operation overwrites all existing metadata that is associated with the blob. It's not possible to modify an individual name/value pair.
       
  1434 	 *
       
  1435 	 * @param string $containerName      Container name
       
  1436 	 * @param string $blobName           Blob name
       
  1437 	 * @param array  $metadata           Key/value pairs of meta data
       
  1438 	 * @param string $leaseId            Lease identifier
       
  1439 	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
       
  1440 	 * @throws Zend_Service_WindowsAzure_Exception
       
  1441 	 */
       
  1442 	public function setBlobMetadata($containerName = '', $blobName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array())
       
  1443 	{
       
  1444 		if ($containerName === '') {
       
  1445 			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
       
  1446 		}
       
  1447 		if (!self::isValidContainerName($containerName)) {
       
  1448 			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.');
       
  1449 		}
       
  1450 		if ($blobName === '') {
       
  1451 			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
       
  1452 		}
       
  1453 		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
       
  1454 			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
       
  1455 		}
       
  1456 		if (count($metadata) == 0) {
       
  1457 			return;
       
  1458 		}
       
  1459 
       
  1460 		// Create metadata headers
       
  1461 		$headers = array();
       
  1462 		if ($leaseId !== null) {
       
  1463 			$headers['x-ms-lease-id'] = $leaseId;
       
  1464 		}
       
  1465 		$headers = array_merge($headers, $this->_generateMetadataHeaders($metadata));
       
  1466 
       
  1467 		// Additional headers?
       
  1468 		foreach ($additionalHeaders as $key => $value) {
       
  1469 			$headers[$key] = $value;
       
  1470 		}
       
  1471 
       
  1472 		// Perform request
       
  1473 		$response = $this->_performRequest($containerName . '/' . $blobName, '?comp=metadata', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
       
  1474 		if (!$response->isSuccessful()) {
       
  1475 			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
       
  1476 		}
       
  1477 	}
       
  1478 
       
  1479 	/**
       
  1480 	 * Set blob properties
       
  1481 	 *
       
  1482 	 * All available properties are listed at http://msdn.microsoft.com/en-us/library/ee691966.aspx and should be provided in the $additionalHeaders parameter.
       
  1483 	 *
       
  1484 	 * @param string $containerName      Container name
       
  1485 	 * @param string $blobName           Blob name
       
  1486 	 * @param string $leaseId            Lease identifier
       
  1487 	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
       
  1488 	 * @throws Zend_Service_WindowsAzure_Exception
       
  1489 	 */
       
  1490 	public function setBlobProperties($containerName = '', $blobName = '', $leaseId = null, $additionalHeaders = array())
       
  1491 	{
       
  1492 		if ($containerName === '') {
       
  1493 			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
       
  1494 		}
       
  1495 		if (!self::isValidContainerName($containerName)) {
       
  1496 			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.');
       
  1497 		}
       
  1498 		if ($blobName === '') {
       
  1499 			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
       
  1500 		}
       
  1501 		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
       
  1502 			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
       
  1503 		}
       
  1504 		if (count($additionalHeaders) == 0) {
       
  1505 			throw new Zend_Service_WindowsAzure_Exception('No additional headers are specified.');
       
  1506 		}
       
  1507 
       
  1508 		// Create headers
       
  1509 		$headers = array();
       
  1510 
       
  1511 		// Lease set?
       
  1512 		if ($leaseId !== null) {
       
  1513 			$headers['x-ms-lease-id'] = $leaseId;
       
  1514 		}
       
  1515 
       
  1516 		// Additional headers?
       
  1517 		foreach ($additionalHeaders as $key => $value) {
       
  1518 			$headers[$key] = $value;
       
  1519 		}
       
  1520 
       
  1521 		// Perform request
       
  1522 		$response = $this->_performRequest($containerName . '/' . $blobName, '?comp=properties', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
       
  1523 		if (!$response->isSuccessful()) {
       
  1524 			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
       
  1525 		}
       
  1526 	}
       
  1527 
       
  1528 	/**
       
  1529 	 * Get blob properties
       
  1530 	 *
       
  1531 	 * @param string $containerName      Container name
       
  1532 	 * @param string $blobName           Blob name
       
  1533 	 * @param string $snapshotId         Snapshot identifier
       
  1534 	 * @param string $leaseId            Lease identifier
       
  1535 	 * @return Zend_Service_WindowsAzure_Storage_BlobInstance
       
  1536 	 * @throws Zend_Service_WindowsAzure_Exception
       
  1537 	 */
       
  1538 	public function getBlobProperties($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null)
       
  1539 	{
       
  1540 		if ($containerName === '') {
       
  1541 			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
       
  1542 		}
       
  1543 		if (!self::isValidContainerName($containerName)) {
       
  1544 			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.');
       
  1545 		}
       
  1546 		if ($blobName === '') {
       
  1547 			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
       
  1548 		}
       
  1549 		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
       
  1550 			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
       
  1551 		}
       
  1552 
       
  1553 		return $this->getBlobInstance($containerName, $blobName, $snapshotId, $leaseId);
       
  1554 	}
       
  1555 
       
  1556 	/**
       
  1557 	 * Delete blob
       
  1558 	 *
       
  1559 	 * @param string $containerName      Container name
       
  1560 	 * @param string $blobName           Blob name
       
  1561 	 * @param string $snapshotId         Snapshot identifier
       
  1562 	 * @param string $leaseId            Lease identifier
       
  1563 	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
       
  1564 	 * @throws Zend_Service_WindowsAzure_Exception
       
  1565 	 */
       
  1566 	public function deleteBlob($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
       
  1567 	{
       
  1568 		if ($containerName === '') {
       
  1569 			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
       
  1570 		}
       
  1571 		if (!self::isValidContainerName($containerName)) {
       
  1572 			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.');
       
  1573 		}
       
  1574 		if ($blobName === '') {
       
  1575 			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
       
  1576 		}
       
  1577 		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
       
  1578 			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
       
  1579 		}
       
  1580 
       
  1581 		// Build query string
       
  1582 		$queryString = array();
       
  1583 		if ($snapshotId !== null) {
       
  1584 			$queryString[] = 'snapshot=' . $snapshotId;
       
  1585 		}
       
  1586 		$queryString = self::createQueryStringFromArray($queryString);
       
  1587 			
       
  1588 		// Additional headers?
       
  1589 		$headers = array();
       
  1590 		if ($leaseId !== null) {
       
  1591 			$headers['x-ms-lease-id'] = $leaseId;
       
  1592 		}
       
  1593 		foreach ($additionalHeaders as $key => $value) {
       
  1594 			$headers[$key] = $value;
       
  1595 		}
       
  1596 
       
  1597 		// Resource name
       
  1598 		$resourceName = self::createResourceName($containerName , $blobName);
       
  1599 
       
  1600 		// Perform request
       
  1601 		$response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::DELETE, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
       
  1602 		if (!$response->isSuccessful()) {
       
  1603 			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
       
  1604 		}
       
  1605 	}
       
  1606 
       
  1607 	/**
       
  1608 	 * Snapshot blob
       
  1609 	 *
       
  1610 	 * @param string $containerName      Container name
       
  1611 	 * @param string $blobName           Blob name
       
  1612 	 * @param array  $metadata           Key/value pairs of meta data
       
  1613 	 * @param array  $additionalHeaders  Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
       
  1614 	 * @return string Date/Time value representing the snapshot identifier.
       
  1615 	 * @throws Zend_Service_WindowsAzure_Exception
       
  1616 	 */
       
  1617 	public function snapshotBlob($containerName = '', $blobName = '', $metadata = array(), $additionalHeaders = array())
       
  1618 	{
       
  1619 		if ($containerName === '') {
       
  1620 			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
       
  1621 		}
       
  1622 		if (!self::isValidContainerName($containerName)) {
       
  1623 			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.');
       
  1624 		}
       
  1625 		if ($blobName === '') {
       
  1626 			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
       
  1627 		}
       
  1628 		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
       
  1629 			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
       
  1630 		}
       
  1631 
       
  1632 		// Additional headers?
       
  1633 		$headers = array();
       
  1634 		foreach ($additionalHeaders as $key => $value) {
       
  1635 			$headers[$key] = $value;
       
  1636 		}
       
  1637 
       
  1638 		// Resource name
       
  1639 		$resourceName = self::createResourceName($containerName , $blobName);
       
  1640 
       
  1641 		// Perform request
       
  1642 		$response = $this->_performRequest($resourceName, '?comp=snapshot', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
       
  1643 		if ($response->isSuccessful()) {
       
  1644 			return $response->getHeader('x-ms-snapshot');
       
  1645 		} else {
       
  1646 			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
       
  1647 		}
       
  1648 	}
       
  1649 
       
  1650 	/**
       
  1651 	 * Lease blob - See (http://msdn.microsoft.com/en-us/library/ee691972.aspx)
       
  1652 	 *
       
  1653 	 * @param string $containerName      Container name
       
  1654 	 * @param string $blobName           Blob name
       
  1655 	 * @param string $leaseAction        Lease action (Zend_Service_WindowsAzure_Storage_Blob::LEASE_*)
       
  1656 	 * @param string $leaseId            Lease identifier, required to renew the lease or to release the lease.
       
  1657 	 * @return Zend_Service_WindowsAzure_Storage_LeaseInstance Lease instance
       
  1658 	 * @throws Zend_Service_WindowsAzure_Exception
       
  1659 	 */
       
  1660 	public function leaseBlob($containerName = '', $blobName = '', $leaseAction = self::LEASE_ACQUIRE, $leaseId = null)
       
  1661 	{
       
  1662 		if ($containerName === '') {
       
  1663 			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
       
  1664 		}
       
  1665 		if (!self::isValidContainerName($containerName)) {
       
  1666 			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.');
       
  1667 		}
       
  1668 		if ($blobName === '') {
       
  1669 			throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.');
       
  1670 		}
       
  1671 		if ($containerName === '$root' && strpos($blobName, '/') !== false) {
       
  1672 			throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).');
       
  1673 		}
       
  1674 
       
  1675 		// Additional headers?
       
  1676 		$headers = array();
       
  1677 		$headers['x-ms-lease-action'] = strtolower($leaseAction);
       
  1678 		if ($leaseId !== null) {
       
  1679 			$headers['x-ms-lease-id'] = $leaseId;
       
  1680 		}
       
  1681 
       
  1682 		// Resource name
       
  1683 		$resourceName = self::createResourceName($containerName , $blobName);
       
  1684 
       
  1685 		// Perform request
       
  1686 		$response = $this->_performRequest($resourceName, '?comp=lease', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE);
       
  1687 		if ($response->isSuccessful()) {
       
  1688 			return new Zend_Service_WindowsAzure_Storage_LeaseInstance(
       
  1689 			$containerName,
       
  1690 			$blobName,
       
  1691 			$response->getHeader('x-ms-lease-id'),
       
  1692 			$response->getHeader('x-ms-lease-time'));
       
  1693 		} else {
       
  1694 			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
       
  1695 		}
       
  1696 	}
       
  1697 
       
  1698 	/**
       
  1699 	 * List blobs
       
  1700 	 *
       
  1701 	 * @param string $containerName Container name
       
  1702 	 * @param string $prefix     Optional. Filters the results to return only blobs whose name begins with the specified prefix.
       
  1703 	 * @param string $delimiter  Optional. Delimiter, i.e. '/', for specifying folder hierarchy
       
  1704 	 * @param int    $maxResults Optional. Specifies the maximum number of blobs to return per call to Azure storage. This does NOT affect list size returned by this function. (maximum: 5000)
       
  1705 	 * @param string $marker     Optional string value that identifies the portion of the list to be returned with the next list operation.
       
  1706 	 * @param string $include    Optional. Specifies that the response should include one or more of the following subsets: '', 'metadata', 'snapshots', 'uncommittedblobs'). Multiple values can be added separated with a comma (,)
       
  1707 	 * @param int    $currentResultCount Current result count (internal use)
       
  1708 	 * @return array
       
  1709 	 * @throws Zend_Service_WindowsAzure_Exception
       
  1710 	 */
       
  1711 	public function listBlobs($containerName = '', $prefix = '', $delimiter = '', $maxResults = null, $marker = null, $include = null, $currentResultCount = 0)
       
  1712 	{
       
  1713 		if ($containerName === '') {
       
  1714 			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
       
  1715 		}
       
  1716 		if (!self::isValidContainerName($containerName)) {
       
  1717 			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.');
       
  1718 		}
       
  1719 			
       
  1720 		// Build query string
       
  1721 		$queryString = array('restype=container', 'comp=list');
       
  1722 		if ($prefix !== null) {
       
  1723 			$queryString[] = 'prefix=' . $prefix;
       
  1724 		}
       
  1725 		if ($delimiter !== '') {
       
  1726 			$queryString[] = 'delimiter=' . $delimiter;
       
  1727 		}
       
  1728 		if ($maxResults !== null) {
       
  1729 			$queryString[] = 'maxresults=' . $maxResults;
       
  1730 		}
       
  1731 		if ($marker !== null) {
       
  1732 			$queryString[] = 'marker=' . $marker;
       
  1733 		}
       
  1734 		if ($include !== null) {
       
  1735 			$queryString[] = 'include=' . $include;
       
  1736 		}
       
  1737 		$queryString = self::createQueryStringFromArray($queryString);
       
  1738 
       
  1739 		// Perform request
       
  1740 		$response = $this->_performRequest($containerName, $queryString, Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_LIST);
       
  1741 		if ($response->isSuccessful()) {
       
  1742 			// Return value
       
  1743 			$blobs = array();
       
  1744 
       
  1745 			// Blobs
       
  1746 			$xmlBlobs = $this->_parseResponse($response)->Blobs->Blob;
       
  1747 			if ($xmlBlobs !== null) {
       
  1748 				for ($i = 0; $i < count($xmlBlobs); $i++) {
       
  1749 					$properties = (array)$xmlBlobs[$i]->Properties;
       
  1750 						
       
  1751 					$blobs[] = new Zend_Service_WindowsAzure_Storage_BlobInstance(
       
  1752 					$containerName,
       
  1753 					(string)$xmlBlobs[$i]->Name,
       
  1754 					(string)$xmlBlobs[$i]->Snapshot,
       
  1755 					(string)$properties['Etag'],
       
  1756 					(string)$properties['Last-Modified'],
       
  1757 					(string)$xmlBlobs[$i]->Url,
       
  1758 					(string)$properties['Content-Length'],
       
  1759 					(string)$properties['Content-Type'],
       
  1760 					(string)$properties['Content-Encoding'],
       
  1761 					(string)$properties['Content-Language'],
       
  1762 					(string)$properties['Cache-Control'],
       
  1763 					(string)$properties['BlobType'],
       
  1764 					(string)$properties['LeaseStatus'],
       
  1765 					false,
       
  1766 					$this->_parseMetadataElement($xmlBlobs[$i])
       
  1767 					);
       
  1768 				}
       
  1769 			}
       
  1770 				
       
  1771 			// Blob prefixes (folders)
       
  1772 			$xmlBlobs = $this->_parseResponse($response)->Blobs->BlobPrefix;
       
  1773 				
       
  1774 			if ($xmlBlobs !== null) {
       
  1775 				for ($i = 0; $i < count($xmlBlobs); $i++) {
       
  1776 					$blobs[] = new Zend_Service_WindowsAzure_Storage_BlobInstance(
       
  1777 					$containerName,
       
  1778 					(string)$xmlBlobs[$i]->Name,
       
  1779 					null,
       
  1780 						'',
       
  1781 						'',
       
  1782 						'',
       
  1783 					0,
       
  1784 						'',
       
  1785 						'',
       
  1786 						'',
       
  1787 						'',
       
  1788 						'',
       
  1789 						'',
       
  1790 					true,
       
  1791 					$this->_parseMetadataElement($xmlBlobs[$i])
       
  1792 					);
       
  1793 				}
       
  1794 			}
       
  1795 				
       
  1796 			// More blobs?
       
  1797 			$xmlMarker = (string)$this->_parseResponse($response)->NextMarker;
       
  1798 			$currentResultCount = $currentResultCount + count($blobs);
       
  1799 			if ($maxResults !== null && $currentResultCount < $maxResults) {
       
  1800 				if ($xmlMarker !== null && $xmlMarker != '') {
       
  1801 					$blobs = array_merge($blobs, $this->listBlobs($containerName, $prefix, $delimiter, $maxResults, $marker, $include, $currentResultCount));
       
  1802 				}
       
  1803 			}
       
  1804 			if ($maxResults !== null && count($blobs) > $maxResults) {
       
  1805 				$blobs = array_slice($blobs, 0, $maxResults);
       
  1806 			}
       
  1807 				
       
  1808 			return $blobs;
       
  1809 		} else {
       
  1810 			throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.'));
       
  1811 		}
       
  1812 	}
       
  1813 
       
  1814 	/**
       
  1815 	 * Generate shared access URL
       
  1816 	 *
       
  1817 	 * @param string $containerName  Container name
       
  1818 	 * @param string $blobName       Blob name
       
  1819 	 * @param string $resource       Signed resource - container (c) - blob (b)
       
  1820 	 * @param string $permissions    Signed permissions - read (r), write (w), delete (d) and list (l)
       
  1821 	 * @param string $start          The time at which the Shared Access Signature becomes valid.
       
  1822 	 * @param string $expiry         The time at which the Shared Access Signature becomes invalid.
       
  1823 	 * @param string $identifier     Signed identifier
       
  1824 	 * @return string
       
  1825 	 */
       
  1826 	public function generateSharedAccessUrl($containerName = '', $blobName = '', $resource = 'b', $permissions = 'r', $start = '', $expiry = '', $identifier = '')
       
  1827 	{
       
  1828 		if ($containerName === '') {
       
  1829 			throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.');
       
  1830 		}
       
  1831 		if (!self::isValidContainerName($containerName)) {
       
  1832 			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.');
       
  1833 		}
       
  1834 
       
  1835 		// Resource name
       
  1836 		$resourceName = self::createResourceName($containerName , $blobName);
       
  1837 
       
  1838 		// Generate URL
       
  1839 		return $this->getBaseUrl() . '/' . $resourceName . '?' .
       
  1840 		$this->_sharedAccessSignatureCredentials->createSignedQueryString(
       
  1841 		$resourceName,
       
  1842 		        '',
       
  1843 		$resource,
       
  1844 		$permissions,
       
  1845 		$start,
       
  1846 		$expiry,
       
  1847 		$identifier);
       
  1848 	}
       
  1849 
       
  1850 	/**
       
  1851 	 * Register this object as stream wrapper client
       
  1852 	 *
       
  1853 	 * @param  string $name Protocol name
       
  1854 	 * @return Zend_Service_WindowsAzure_Storage_Blob
       
  1855 	 */
       
  1856 	public function registerAsClient($name)
       
  1857 	{
       
  1858 		self::$_wrapperClients[$name] = $this;
       
  1859 		return $this;
       
  1860 	}
       
  1861 
       
  1862 	/**
       
  1863 	 * Unregister this object as stream wrapper client
       
  1864 	 *
       
  1865 	 * @param  string $name Protocol name
       
  1866 	 * @return Zend_Service_WindowsAzure_Storage_Blob
       
  1867 	 */
       
  1868 	public function unregisterAsClient($name)
       
  1869 	{
       
  1870 		unset(self::$_wrapperClients[$name]);
       
  1871 		return $this;
       
  1872 	}
       
  1873 
       
  1874 	/**
       
  1875 	 * Get wrapper client for stream type
       
  1876 	 *
       
  1877 	 * @param  string $name Protocol name
       
  1878 	 * @return Zend_Service_WindowsAzure_Storage_Blob
       
  1879 	 */
       
  1880 	public static function getWrapperClient($name)
       
  1881 	{
       
  1882 		return self::$_wrapperClients[$name];
       
  1883 	}
       
  1884 
       
  1885 	/**
       
  1886 	 * Register this object as stream wrapper
       
  1887 	 *
       
  1888 	 * @param  string $name Protocol name
       
  1889 	 */
       
  1890 	public function registerStreamWrapper($name = 'azure')
       
  1891 	{
       
  1892 		/**
       
  1893 		 * @see Zend_Service_WindowsAzure_Storage_Blob_Stream
       
  1894 		 */
       
  1895 		require_once 'Zend/Service/WindowsAzure/Storage/Blob/Stream.php';
       
  1896 
       
  1897 		stream_register_wrapper($name, 'Zend_Service_WindowsAzure_Storage_Blob_Stream');
       
  1898 		$this->registerAsClient($name);
       
  1899 	}
       
  1900 
       
  1901 	/**
       
  1902 	 * Unregister this object as stream wrapper
       
  1903 	 *
       
  1904 	 * @param  string $name Protocol name
       
  1905 	 * @return Zend_Service_WindowsAzure_Storage_Blob
       
  1906 	 */
       
  1907 	public function unregisterStreamWrapper($name = 'azure')
       
  1908 	{
       
  1909 		stream_wrapper_unregister($name);
       
  1910 		$this->unregisterAsClient($name);
       
  1911 	}
       
  1912 
       
  1913 	/**
       
  1914 	 * Create resource name
       
  1915 	 *
       
  1916 	 * @param string $containerName  Container name
       
  1917 	 * @param string $blobName Blob name
       
  1918 	 * @return string
       
  1919 	 */
       
  1920 	public static function createResourceName($containerName = '', $blobName = '')
       
  1921 	{
       
  1922 		// Resource name
       
  1923 		$resourceName = $containerName . '/' . $blobName;
       
  1924 		if ($containerName === '' || $containerName === '$root') {
       
  1925 			$resourceName = $blobName;
       
  1926 		}
       
  1927 		if ($blobName === '') {
       
  1928 			$resourceName = $containerName;
       
  1929 		}
       
  1930 
       
  1931 		return $resourceName;
       
  1932 	}
       
  1933 
       
  1934 	/**
       
  1935 	 * Is valid container name?
       
  1936 	 *
       
  1937 	 * @param string $containerName Container name
       
  1938 	 * @return boolean
       
  1939 	 */
       
  1940 	public static function isValidContainerName($containerName = '')
       
  1941 	{
       
  1942 		if ($containerName == '$root') {
       
  1943 			return true;
       
  1944 		}
       
  1945 
       
  1946 		if (preg_match("/^[a-z0-9][a-z0-9-]*$/", $containerName) === 0) {
       
  1947 			return false;
       
  1948 		}
       
  1949 
       
  1950 		if (strpos($containerName, '--') !== false) {
       
  1951 			return false;
       
  1952 		}
       
  1953 
       
  1954 		if (strtolower($containerName) != $containerName) {
       
  1955 			return false;
       
  1956 		}
       
  1957 
       
  1958 		if (strlen($containerName) < 3 || strlen($containerName) > 63) {
       
  1959 			return false;
       
  1960 		}
       
  1961 
       
  1962 		if (substr($containerName, -1) == '-') {
       
  1963 			return false;
       
  1964 		}
       
  1965 
       
  1966 		return true;
       
  1967 	}
       
  1968 
       
  1969 	/**
       
  1970 	 * Get error message from Zend_Http_Response
       
  1971 	 *
       
  1972 	 * @param Zend_Http_Response $response Repsonse
       
  1973 	 * @param string $alternativeError Alternative error message
       
  1974 	 * @return string
       
  1975 	 */
       
  1976 	protected function _getErrorMessage(Zend_Http_Response $response, $alternativeError = 'Unknown error.')
       
  1977 	{
       
  1978 		$response = $this->_parseResponse($response);
       
  1979 		if ($response && $response->Message) {
       
  1980 			return (string)$response->Message;
       
  1981 		} else {
       
  1982 			return $alternativeError;
       
  1983 		}
       
  1984 	}
       
  1985 
       
  1986 	/**
       
  1987 	 * Generate block id
       
  1988 	 *
       
  1989 	 * @param int $part Block number
       
  1990 	 * @return string Windows Azure Blob Storage block number
       
  1991 	 */
       
  1992 	protected function _generateBlockId($part = 0)
       
  1993 	{
       
  1994 		$returnValue = $part;
       
  1995 		while (strlen($returnValue) < 64) {
       
  1996 			$returnValue = '0' . $returnValue;
       
  1997 		}
       
  1998 
       
  1999 		return $returnValue;
       
  2000 	}
       
  2001 }