PageRenderTime 41ms CodeModel.GetById 2ms app.highlight 30ms RepoModel.GetById 0ms app.codeStats 1ms

/trunk/MoodleWebRole/azure/Microsoft/WindowsAzure/Storage/Blob.php

#
PHP | 1413 lines | 822 code | 142 blank | 449 comment | 190 complexity | f2b33784e0d02c21ed50ffd75bcbadec MD5 | raw file

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

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

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