PageRenderTime 57ms CodeModel.GetById 3ms app.highlight 45ms RepoModel.GetById 1ms app.codeStats 1ms

/src/vendor/zend/lib/Zend/Service/WindowsAzure/Storage/Blob.php

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

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