PageRenderTime 45ms CodeModel.GetById 2ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 1ms

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

http://github.com/centurion-project/Centurion
PHP | 1401 lines | 812 code | 142 blank | 447 comment | 197 complexity | 72ef2fa2fa3fa7e4b1ced395a9903dc9 MD5 | raw file

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

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

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