_apiVersion = '2009-09-19'; // SharedAccessSignature credentials $this->_sharedAccessSignatureCredentials = new Zend_Service_WindowsAzure_Credentials_SharedAccessSignature($accountName, $accountKey, $usePathStyleUri); } /** * Check if a blob exists * * @param string $containerName Container name * @param string $blobName Blob name * @param string $snapshotId Snapshot identifier * @return boolean */ public function blobExists($containerName = '', $blobName = '', $snapshotId = null) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } // Get blob instance try { $this->getBlobInstance($containerName, $blobName, $snapshotId); } catch (Zend_Service_WindowsAzure_Exception $e) { return false; } return true; } /** * Check if a container exists * * @param string $containerName Container name * @return boolean */ public function containerExists($containerName = '') { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } // List containers $containers = $this->listContainers($containerName, 1); foreach ($containers as $container) { if ($container->Name == $containerName) { return true; } } return false; } /** * Create container * * @param string $containerName Container name * @param array $metadata Key/value pairs of meta data * @return object Container properties * @throws Zend_Service_WindowsAzure_Exception */ public function createContainer($containerName = '', $metadata = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if (!is_array($metadata)) { throw new Zend_Service_WindowsAzure_Exception('Meta data should be an array of key and value pairs.'); } // Create metadata headers $headers = array(); $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata)); // Perform request $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); if ($response->isSuccessful()) { return new Zend_Service_WindowsAzure_Storage_BlobContainer( $containerName, $response->getHeader('Etag'), $response->getHeader('Last-modified'), $metadata ); } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Get container ACL * * @param string $containerName Container name * @param bool $signedIdentifiers Display only private/blob/container or display signed identifiers? * @return string Acl, to be compared with Zend_Service_WindowsAzure_Storage_Blob::ACL_* * @throws Zend_Service_WindowsAzure_Exception */ public function getContainerAcl($containerName = '', $signedIdentifiers = false) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } // Perform request $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); if ($response->isSuccessful()) { if ($signedIdentifiers == false) { // Only private/blob/container $accessType = $response->getHeader(Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-public-access'); if (strtolower($accessType) == 'true') { $accessType = self::ACL_PUBLIC_CONTAINER; } return $accessType; } else { // Parse result $result = $this->_parseResponse($response); if (!$result) { return array(); } $entries = null; if ($result->SignedIdentifier) { if (count($result->SignedIdentifier) > 1) { $entries = $result->SignedIdentifier; } else { $entries = array($result->SignedIdentifier); } } // Return value $returnValue = array(); foreach ($entries as $entry) { $returnValue[] = new Zend_Service_WindowsAzure_Storage_SignedIdentifier( $entry->Id, $entry->AccessPolicy ? $entry->AccessPolicy->Start ? $entry->AccessPolicy->Start : '' : '', $entry->AccessPolicy ? $entry->AccessPolicy->Expiry ? $entry->AccessPolicy->Expiry : '' : '', $entry->AccessPolicy ? $entry->AccessPolicy->Permission ? $entry->AccessPolicy->Permission : '' : '' ); } // Return return $returnValue; } } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Set container ACL * * @param string $containerName Container name * @param bool $acl Zend_Service_WindowsAzure_Storage_Blob::ACL_* * @param array $signedIdentifiers Signed identifiers * @throws Zend_Service_WindowsAzure_Exception */ public function setContainerAcl($containerName = '', $acl = self::ACL_PRIVATE, $signedIdentifiers = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } // Headers $headers = array(); // Acl specified? if ($acl != self::ACL_PRIVATE && $acl !== null && $acl != '') { $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-public-access'] = $acl; } // Policies $policies = null; if (is_array($signedIdentifiers) && count($signedIdentifiers) > 0) { $policies = ''; $policies .= '' . "\r\n"; $policies .= '' . "\r\n"; foreach ($signedIdentifiers as $signedIdentifier) { $policies .= ' ' . "\r\n"; $policies .= ' ' . $signedIdentifier->Id . '' . "\r\n"; $policies .= ' ' . "\r\n"; if ($signedIdentifier->Start != '') $policies .= ' ' . $signedIdentifier->Start . '' . "\r\n"; if ($signedIdentifier->Expiry != '') $policies .= ' ' . $signedIdentifier->Expiry . '' . "\r\n"; if ($signedIdentifier->Permissions != '') $policies .= ' ' . $signedIdentifier->Permissions . '' . "\r\n"; $policies .= ' ' . "\r\n"; $policies .= ' ' . "\r\n"; } $policies .= '' . "\r\n"; } // Perform request $response = $this->_performRequest($containerName, '?restype=container&comp=acl', Zend_Http_Client::PUT, $headers, false, $policies, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); if (!$response->isSuccessful()) { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Get container * * @param string $containerName Container name * @return Zend_Service_WindowsAzure_Storage_BlobContainer * @throws Zend_Service_WindowsAzure_Exception */ public function getContainer($containerName = '') { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } // Perform request $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); if ($response->isSuccessful()) { // Parse metadata $metadata = $this->_parseMetadataHeaders($response->getHeaders()); // Return container return new Zend_Service_WindowsAzure_Storage_BlobContainer( $containerName, $response->getHeader('Etag'), $response->getHeader('Last-modified'), $metadata ); } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Get container metadata * * @param string $containerName Container name * @return array Key/value pairs of meta data * @throws Zend_Service_WindowsAzure_Exception */ public function getContainerMetadata($containerName = '') { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } return $this->getContainer($containerName)->Metadata; } /** * Set container metadata * * 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. * * @param string $containerName Container name * @param array $metadata Key/value pairs of meta data * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @throws Zend_Service_WindowsAzure_Exception */ public function setContainerMetadata($containerName = '', $metadata = array(), $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if (!is_array($metadata)) { throw new Zend_Service_WindowsAzure_Exception('Meta data should be an array of key and value pairs.'); } if (count($metadata) == 0) { return; } // Create metadata headers $headers = array(); $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata)); // Additional headers? foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Perform request $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); if (!$response->isSuccessful()) { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Delete container * * @param string $containerName Container name * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @throws Zend_Service_WindowsAzure_Exception */ public function deleteContainer($containerName = '', $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } // Additional headers? $headers = array(); foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Perform request $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); if (!$response->isSuccessful()) { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * List containers * * @param string $prefix Optional. Filters the results to return only containers whose name begins with the specified prefix. * @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) * @param string $marker Optional string value that identifies the portion of the list to be returned with the next list operation. * @param string $include Optional. Include this parameter to specify that the container's metadata be returned as part of the response body. (allowed values: '', 'metadata') * @param int $currentResultCount Current result count (internal use) * @return array * @throws Zend_Service_WindowsAzure_Exception */ public function listContainers($prefix = null, $maxResults = null, $marker = null, $include = null, $currentResultCount = 0) { // Build query string $queryString = array('comp=list'); if ($prefix !== null) { $queryString[] = 'prefix=' . $prefix; } if ($maxResults !== null) { $queryString[] = 'maxresults=' . $maxResults; } if ($marker !== null) { $queryString[] = 'marker=' . $marker; } if ($include !== null) { $queryString[] = 'include=' . $include; } $queryString = self::createQueryStringFromArray($queryString); // Perform request $response = $this->_performRequest('', $queryString, Zend_Http_Client::GET, array(), false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_LIST); if ($response->isSuccessful()) { $xmlContainers = $this->_parseResponse($response)->Containers->Container; $xmlMarker = (string)$this->_parseResponse($response)->NextMarker; $containers = array(); if ($xmlContainers !== null) { for ($i = 0; $i < count($xmlContainers); $i++) { $containers[] = new Zend_Service_WindowsAzure_Storage_BlobContainer( (string)$xmlContainers[$i]->Name, (string)$xmlContainers[$i]->Etag, (string)$xmlContainers[$i]->LastModified, $this->_parseMetadataElement($xmlContainers[$i]) ); } } $currentResultCount = $currentResultCount + count($containers); if ($maxResults !== null && $currentResultCount < $maxResults) { if ($xmlMarker !== null && $xmlMarker != '') { $containers = array_merge($containers, $this->listContainers($prefix, $maxResults, $xmlMarker, $include, $currentResultCount)); } } if ($maxResults !== null && count($containers) > $maxResults) { $containers = array_slice($containers, 0, $maxResults); } return $containers; } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Put blob * * @param string $containerName Container name * @param string $blobName Blob name * @param string $localFileName Local file name to be uploaded * @param array $metadata Key/value pairs of meta data * @param string $leaseId Lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @return object Partial blob properties * @throws Zend_Service_WindowsAzure_Exception */ public function putBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($localFileName === '') { throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.'); } if (!file_exists($localFileName)) { throw new Zend_Service_WindowsAzure_Exception('Local file not found.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } // Check file size if (filesize($localFileName) >= self::MAX_BLOB_SIZE) { return $this->putLargeBlob($containerName, $blobName, $localFileName, $metadata, $leaseId); } // Put the data to Windows Azure Storage return $this->putBlobData($containerName, $blobName, file_get_contents($localFileName), $metadata, $leaseId, $additionalHeaders); } /** * Put blob data * * @param string $containerName Container name * @param string $blobName Blob name * @param mixed $data Data to store * @param array $metadata Key/value pairs of meta data * @param string $leaseId Lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @return object Partial blob properties * @throws Zend_Service_WindowsAzure_Exception */ public function putBlobData($containerName = '', $blobName = '', $data = '', $metadata = array(), $leaseId = null, $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } // Create metadata headers $headers = array(); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata)); // Additional headers? foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Specify blob type $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_BLOCK; // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Perform request $response = $this->_performRequest($resourceName, '', Zend_Http_Client::PUT, $headers, false, $data, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); if ($response->isSuccessful()) { return new Zend_Service_WindowsAzure_Storage_BlobInstance( $containerName, $blobName, null, $response->getHeader('Etag'), $response->getHeader('Last-modified'), $this->getBaseUrl() . '/' . $containerName . '/' . $blobName, strlen($data), '', '', '', false, $metadata ); } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Put large blob (> 64 MB) * * @param string $containerName Container name * @param string $blobName Blob name * @param string $localFileName Local file name to be uploaded * @param array $metadata Key/value pairs of meta data * @param string $leaseId Lease identifier * @return object Partial blob properties * @throws Zend_Service_WindowsAzure_Exception */ public function putLargeBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $leaseId = null) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($localFileName === '') { throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.'); } if (!file_exists($localFileName)) { throw new Zend_Service_WindowsAzure_Exception('Local file not found.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } // Check file size if (filesize($localFileName) < self::MAX_BLOB_SIZE) { return $this->putBlob($containerName, $blobName, $localFileName, $metadata); } // Determine number of parts $numberOfParts = ceil( filesize($localFileName) / self::MAX_BLOB_TRANSFER_SIZE ); // Generate block id's $blockIdentifiers = array(); for ($i = 0; $i < $numberOfParts; $i++) { $blockIdentifiers[] = $this->_generateBlockId($i); } // Open file $fp = fopen($localFileName, 'r'); if ($fp === false) { throw new Zend_Service_WindowsAzure_Exception('Could not open local file.'); } // Upload parts for ($i = 0; $i < $numberOfParts; $i++) { // Seek position in file fseek($fp, $i * self::MAX_BLOB_TRANSFER_SIZE); // Read contents $fileContents = fread($fp, self::MAX_BLOB_TRANSFER_SIZE); // Put block $this->putBlock($containerName, $blobName, $blockIdentifiers[$i], $fileContents, $leaseId); // Dispose file contents $fileContents = null; unset($fileContents); } // Close file fclose($fp); // Put block list $this->putBlockList($containerName, $blobName, $blockIdentifiers, $metadata, $leaseId); // Return information of the blob return $this->getBlobInstance($containerName, $blobName, null, $leaseId); } /** * Put large blob block * * @param string $containerName Container name * @param string $blobName Blob name * @param string $identifier Block ID * @param array $contents Contents of the block * @param string $leaseId Lease identifier * @throws Zend_Service_WindowsAzure_Exception */ public function putBlock($containerName = '', $blobName = '', $identifier = '', $contents = '', $leaseId = null) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($identifier === '') { throw new Zend_Service_WindowsAzure_Exception('Block identifier is not specified.'); } if (strlen($contents) > self::MAX_BLOB_TRANSFER_SIZE) { throw new Zend_Service_WindowsAzure_Exception('Block size is too big.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } // Headers $headers = array(); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Upload $response = $this->_performRequest($resourceName, '?comp=block&blockid=' . base64_encode($identifier), Zend_Http_Client::PUT, $headers, false, $contents, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); if (!$response->isSuccessful()) { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Put block list * * @param string $containerName Container name * @param string $blobName Blob name * @param array $blockList Array of block identifiers * @param array $metadata Key/value pairs of meta data * @param string $leaseId Lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @throws Zend_Service_WindowsAzure_Exception */ public function putBlockList($containerName = '', $blobName = '', $blockList = array(), $metadata = array(), $leaseId = null, $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if (count($blockList) == 0) { throw new Zend_Service_WindowsAzure_Exception('Block list does not contain any elements.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } // Generate block list $blocks = ''; foreach ($blockList as $block) { $blocks .= ' ' . base64_encode($block) . '' . "\n"; } // Generate block list request $fileContents = utf8_encode(implode("\n", array( '', '', $blocks, '' ))); // Create metadata headers $headers = array(); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata)); // Additional headers? foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Perform request $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); if (!$response->isSuccessful()) { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Get block list * * @param string $containerName Container name * @param string $blobName Blob name * @param string $snapshotId Snapshot identifier * @param string $leaseId Lease identifier * @param integer $type Type of block list to retrieve. 0 = all, 1 = committed, 2 = uncommitted * @return array * @throws Zend_Service_WindowsAzure_Exception */ public function getBlockList($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $type = 0) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($type < 0 || $type > 2) { throw new Zend_Service_WindowsAzure_Exception('Invalid type of block list to retrieve.'); } // Set $blockListType $blockListType = 'all'; if ($type == 1) { $blockListType = 'committed'; } if ($type == 2) { $blockListType = 'uncommitted'; } // Headers $headers = array(); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } // Build query string $queryString = array('comp=blocklist', 'blocklisttype=' . $blockListType); if ($snapshotId !== null) { $queryString[] = 'snapshot=' . $snapshotId; } $queryString = self::createQueryStringFromArray($queryString); // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Perform request $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ); if ($response->isSuccessful()) { // Parse response $blockList = $this->_parseResponse($response); // Create return value $returnValue = array(); if ($blockList->CommittedBlocks) { foreach ($blockList->CommittedBlocks->Block as $block) { $returnValue['CommittedBlocks'][] = (object)array( 'Name' => (string)$block->Name, 'Size' => (string)$block->Size ); } } if ($blockList->UncommittedBlocks) { foreach ($blockList->UncommittedBlocks->Block as $block) { $returnValue['UncommittedBlocks'][] = (object)array( 'Name' => (string)$block->Name, 'Size' => (string)$block->Size ); } } return $returnValue; } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Create page blob * * @param string $containerName Container name * @param string $blobName Blob name * @param int $size Size of the page blob in bytes * @param array $metadata Key/value pairs of meta data * @param string $leaseId Lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @return object Partial blob properties * @throws Zend_Service_WindowsAzure_Exception */ public function createPageBlob($containerName = '', $blobName = '', $size = 0, $metadata = array(), $leaseId = null, $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } if ($size <= 0) { throw new Zend_Service_WindowsAzure_Exception('Page blob size must be specified.'); } // Create metadata headers $headers = array(); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata)); // Additional headers? foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Specify blob type & blob length $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-type'] = self::BLOBTYPE_PAGE; $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'blob-content-length'] = $size; $headers['Content-Length'] = 0; // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Perform request $response = $this->_performRequest($resourceName, '', Zend_Http_Client::PUT, $headers, false, '', Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); if ($response->isSuccessful()) { return new Zend_Service_WindowsAzure_Storage_BlobInstance( $containerName, $blobName, null, $response->getHeader('Etag'), $response->getHeader('Last-modified'), $this->getBaseUrl() . '/' . $containerName . '/' . $blobName, $size, '', '', '', false, $metadata ); } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Put page in page blob * * @param string $containerName Container name * @param string $blobName Blob name * @param int $startByteOffset Start byte offset * @param int $endByteOffset End byte offset * @param mixed $contents Page contents * @param string $writeMethod Write method (Zend_Service_WindowsAzure_Storage_Blob::PAGE_WRITE_*) * @param string $leaseId Lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @throws Zend_Service_WindowsAzure_Exception */ public function putPage($containerName = '', $blobName = '', $startByteOffset = 0, $endByteOffset = 0, $contents = '', $writeMethod = self::PAGE_WRITE_UPDATE, $leaseId = null, $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } if ($startByteOffset % 512 != 0) { throw new Zend_Service_WindowsAzure_Exception('Start byte offset must be a modulus of 512.'); } if (($endByteOffset + 1) % 512 != 0) { throw new Zend_Service_WindowsAzure_Exception('End byte offset must be a modulus of 512 minus 1.'); } // Determine size $size = strlen($contents); if ($size >= self::MAX_BLOB_TRANSFER_SIZE) { throw new Zend_Service_WindowsAzure_Exception('Page blob size must not be larger than ' + self::MAX_BLOB_TRANSFER_SIZE . ' bytes.'); } // Create metadata headers $headers = array(); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } // Additional headers? foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Specify range $headers['Range'] = 'bytes=' . $startByteOffset . '-' . $endByteOffset; // Write method $headers[Zend_Service_WindowsAzure_Storage::PREFIX_STORAGE_HEADER . 'page-write'] = $writeMethod; // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Perform request $response = $this->_performRequest($resourceName, '?comp=page', Zend_Http_Client::PUT, $headers, false, $contents, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); if (!$response->isSuccessful()) { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Put page in page blob * * @param string $containerName Container name * @param string $blobName Blob name * @param int $startByteOffset Start byte offset * @param int $endByteOffset End byte offset * @param string $leaseId Lease identifier * @return array Array of page ranges * @throws Zend_Service_WindowsAzure_Exception */ public function getPageRegions($containerName = '', $blobName = '', $startByteOffset = 0, $endByteOffset = 0, $leaseId = null) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } if ($startByteOffset % 512 != 0) { throw new Zend_Service_WindowsAzure_Exception('Start byte offset must be a modulus of 512.'); } if ($endByteOffset > 0 && ($endByteOffset + 1) % 512 != 0) { throw new Zend_Service_WindowsAzure_Exception('End byte offset must be a modulus of 512 minus 1.'); } // Create metadata headers $headers = array(); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } // Specify range? if ($endByteOffset > 0) { $headers['Range'] = 'bytes=' . $startByteOffset . '-' . $endByteOffset; } // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Perform request $response = $this->_performRequest($resourceName, '?comp=pagelist', Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); if ($response->isSuccessful()) { $result = $this->_parseResponse($response); $xmlRanges = null; if (count($result->PageRange) > 1) { $xmlRanges = $result->PageRange; } else { $xmlRanges = array($result->PageRange); } $ranges = array(); for ($i = 0; $i < count($xmlRanges); $i++) { $ranges[] = new Zend_Service_WindowsAzure_Storage_PageRegionInstance( (int)$xmlRanges[$i]->Start, (int)$xmlRanges[$i]->End ); } return $ranges; } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Copy blob * * @param string $sourceContainerName Source container name * @param string $sourceBlobName Source blob name * @param string $destinationContainerName Destination container name * @param string $destinationBlobName Destination blob name * @param array $metadata Key/value pairs of meta data * @param string $sourceSnapshotId Source snapshot identifier * @param string $destinationLeaseId Destination lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd894037.aspx for more information. * @return object Partial blob properties * @throws Zend_Service_WindowsAzure_Exception */ public function copyBlob($sourceContainerName = '', $sourceBlobName = '', $destinationContainerName = '', $destinationBlobName = '', $metadata = array(), $sourceSnapshotId = null, $destinationLeaseId = null, $additionalHeaders = array()) { if ($sourceContainerName === '') { throw new Zend_Service_WindowsAzure_Exception('Source container name is not specified.'); } if (!self::isValidContainerName($sourceContainerName)) { 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.'); } if ($sourceBlobName === '') { throw new Zend_Service_WindowsAzure_Exception('Source blob name is not specified.'); } if ($destinationContainerName === '') { throw new Zend_Service_WindowsAzure_Exception('Destination container name is not specified.'); } if (!self::isValidContainerName($destinationContainerName)) { 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.'); } if ($destinationBlobName === '') { throw new Zend_Service_WindowsAzure_Exception('Destination blob name is not specified.'); } if ($sourceContainerName === '$root' && strpos($sourceBlobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } if ($destinationContainerName === '$root' && strpos($destinationBlobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } // Create metadata headers $headers = array(); if ($destinationLeaseId !== null) { $headers['x-ms-lease-id'] = $destinationLeaseId; } $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata)); // Additional headers? foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Resource names $sourceResourceName = self::createResourceName($sourceContainerName, $sourceBlobName); if ($sourceSnapshotId !== null) { $sourceResourceName .= '?snapshot=' . $sourceSnapshotId; } $destinationResourceName = self::createResourceName($destinationContainerName, $destinationBlobName); // Set source blob $headers["x-ms-copy-source"] = '/' . $this->_accountName . '/' . $sourceResourceName; // Perform request $response = $this->_performRequest($destinationResourceName, '', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); if ($response->isSuccessful()) { return new Zend_Service_WindowsAzure_Storage_BlobInstance( $destinationContainerName, $destinationBlobName, null, $response->getHeader('Etag'), $response->getHeader('Last-modified'), $this->getBaseUrl() . '/' . $destinationContainerName . '/' . $destinationBlobName, 0, '', '', '', false, $metadata ); } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Get blob * * @param string $containerName Container name * @param string $blobName Blob name * @param string $localFileName Local file name to store downloaded blob * @param string $snapshotId Snapshot identifier * @param string $leaseId Lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @throws Zend_Service_WindowsAzure_Exception */ public function getBlob($containerName = '', $blobName = '', $localFileName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($localFileName === '') { throw new Zend_Service_WindowsAzure_Exception('Local file name is not specified.'); } // Fetch data file_put_contents($localFileName, $this->getBlobData($containerName, $blobName, $snapshotId, $leaseId, $additionalHeaders)); } /** * Get blob data * * @param string $containerName Container name * @param string $blobName Blob name * @param string $snapshotId Snapshot identifier * @param string $leaseId Lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @return mixed Blob contents * @throws Zend_Service_WindowsAzure_Exception */ public function getBlobData($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } // Build query string $queryString = array(); if ($snapshotId !== null) { $queryString[] = 'snapshot=' . $snapshotId; } $queryString = self::createQueryStringFromArray($queryString); // Additional headers? $headers = array(); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Perform request $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::GET, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ); if ($response->isSuccessful()) { return $response->getBody(); } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Get blob instance * * @param string $containerName Container name * @param string $blobName Blob name * @param string $snapshotId Snapshot identifier * @param string $leaseId Lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @return Zend_Service_WindowsAzure_Storage_BlobInstance * @throws Zend_Service_WindowsAzure_Exception */ public function getBlobInstance($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } // Build query string $queryString = array(); if ($snapshotId !== null) { $queryString[] = 'snapshot=' . $snapshotId; } $queryString = self::createQueryStringFromArray($queryString); // Additional headers? $headers = array(); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Perform request $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::HEAD, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ); if ($response->isSuccessful()) { // Parse metadata $metadata = $this->_parseMetadataHeaders($response->getHeaders()); // Return blob return new Zend_Service_WindowsAzure_Storage_BlobInstance( $containerName, $blobName, $snapshotId, $response->getHeader('Etag'), $response->getHeader('Last-modified'), $this->getBaseUrl() . '/' . $containerName . '/' . $blobName, $response->getHeader('Content-Length'), $response->getHeader('Content-Type'), $response->getHeader('Content-Encoding'), $response->getHeader('Content-Language'), $response->getHeader('Cache-Control'), $response->getHeader('x-ms-blob-type'), $response->getHeader('x-ms-lease-status'), false, $metadata ); } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Get blob metadata * * @param string $containerName Container name * @param string $blobName Blob name * @param string $snapshotId Snapshot identifier * @param string $leaseId Lease identifier * @return array Key/value pairs of meta data * @throws Zend_Service_WindowsAzure_Exception */ public function getBlobMetadata($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } return $this->getBlobInstance($containerName, $blobName, $snapshotId, $leaseId)->Metadata; } /** * Set blob metadata * * 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. * * @param string $containerName Container name * @param string $blobName Blob name * @param array $metadata Key/value pairs of meta data * @param string $leaseId Lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @throws Zend_Service_WindowsAzure_Exception */ public function setBlobMetadata($containerName = '', $blobName = '', $metadata = array(), $leaseId = null, $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } if (count($metadata) == 0) { return; } // Create metadata headers $headers = array(); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } $headers = array_merge($headers, $this->_generateMetadataHeaders($metadata)); // Additional headers? foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Perform request $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); if (!$response->isSuccessful()) { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Set blob properties * * All available properties are listed at http://msdn.microsoft.com/en-us/library/ee691966.aspx and should be provided in the $additionalHeaders parameter. * * @param string $containerName Container name * @param string $blobName Blob name * @param string $leaseId Lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @throws Zend_Service_WindowsAzure_Exception */ public function setBlobProperties($containerName = '', $blobName = '', $leaseId = null, $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } if (count($additionalHeaders) == 0) { throw new Zend_Service_WindowsAzure_Exception('No additional headers are specified.'); } // Create headers $headers = array(); // Lease set? if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } // Additional headers? foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Perform request $response = $this->_performRequest($containerName . '/' . $blobName, '?comp=properties', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); if (!$response->isSuccessful()) { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Get blob properties * * @param string $containerName Container name * @param string $blobName Blob name * @param string $snapshotId Snapshot identifier * @param string $leaseId Lease identifier * @return Zend_Service_WindowsAzure_Storage_BlobInstance * @throws Zend_Service_WindowsAzure_Exception */ public function getBlobProperties($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } return $this->getBlobInstance($containerName, $blobName, $snapshotId, $leaseId); } /** * Delete blob * * @param string $containerName Container name * @param string $blobName Blob name * @param string $snapshotId Snapshot identifier * @param string $leaseId Lease identifier * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @throws Zend_Service_WindowsAzure_Exception */ public function deleteBlob($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } // Build query string $queryString = array(); if ($snapshotId !== null) { $queryString[] = 'snapshot=' . $snapshotId; } $queryString = self::createQueryStringFromArray($queryString); // Additional headers? $headers = array(); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Perform request $response = $this->_performRequest($resourceName, $queryString, Zend_Http_Client::DELETE, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); if (!$response->isSuccessful()) { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Snapshot blob * * @param string $containerName Container name * @param string $blobName Blob name * @param array $metadata Key/value pairs of meta data * @param array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information. * @return string Date/Time value representing the snapshot identifier. * @throws Zend_Service_WindowsAzure_Exception */ public function snapshotBlob($containerName = '', $blobName = '', $metadata = array(), $additionalHeaders = array()) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } // Additional headers? $headers = array(); foreach ($additionalHeaders as $key => $value) { $headers[$key] = $value; } // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Perform request $response = $this->_performRequest($resourceName, '?comp=snapshot', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); if ($response->isSuccessful()) { return $response->getHeader('x-ms-snapshot'); } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Lease blob - See (http://msdn.microsoft.com/en-us/library/ee691972.aspx) * * @param string $containerName Container name * @param string $blobName Blob name * @param string $leaseAction Lease action (Zend_Service_WindowsAzure_Storage_Blob::LEASE_*) * @param string $leaseId Lease identifier, required to renew the lease or to release the lease. * @return Zend_Service_WindowsAzure_Storage_LeaseInstance Lease instance * @throws Zend_Service_WindowsAzure_Exception */ public function leaseBlob($containerName = '', $blobName = '', $leaseAction = self::LEASE_ACQUIRE, $leaseId = null) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } if ($blobName === '') { throw new Zend_Service_WindowsAzure_Exception('Blob name is not specified.'); } if ($containerName === '$root' && strpos($blobName, '/') !== false) { throw new Zend_Service_WindowsAzure_Exception('Blobs stored in the root container can not have a name containing a forward slash (/).'); } // Additional headers? $headers = array(); $headers['x-ms-lease-action'] = strtolower($leaseAction); if ($leaseId !== null) { $headers['x-ms-lease-id'] = $leaseId; } // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Perform request $response = $this->_performRequest($resourceName, '?comp=lease', Zend_Http_Client::PUT, $headers, false, null, Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB, Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_WRITE); if ($response->isSuccessful()) { return new Zend_Service_WindowsAzure_Storage_LeaseInstance( $containerName, $blobName, $response->getHeader('x-ms-lease-id'), $response->getHeader('x-ms-lease-time')); } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * List blobs * * @param string $containerName Container name * @param string $prefix Optional. Filters the results to return only blobs whose name begins with the specified prefix. * @param string $delimiter Optional. Delimiter, i.e. '/', for specifying folder hierarchy * @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) * @param string $marker Optional string value that identifies the portion of the list to be returned with the next list operation. * @param string $include Optional. Specifies that the response should include one or more of the following subsets: '', 'metadata', 'snapshots', 'uncommittedblobs'). Multiple values can be added separated with a comma (,) * @param int $currentResultCount Current result count (internal use) * @return array * @throws Zend_Service_WindowsAzure_Exception */ public function listBlobs($containerName = '', $prefix = '', $delimiter = '', $maxResults = null, $marker = null, $include = null, $currentResultCount = 0) { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } // Build query string $queryString = array('restype=container', 'comp=list'); if ($prefix !== null) { $queryString[] = 'prefix=' . $prefix; } if ($delimiter !== '') { $queryString[] = 'delimiter=' . $delimiter; } if ($maxResults !== null) { $queryString[] = 'maxresults=' . $maxResults; } if ($marker !== null) { $queryString[] = 'marker=' . $marker; } if ($include !== null) { $queryString[] = 'include=' . $include; } $queryString = self::createQueryStringFromArray($queryString); // Perform request $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); if ($response->isSuccessful()) { // Return value $blobs = array(); // Blobs $xmlBlobs = $this->_parseResponse($response)->Blobs->Blob; if ($xmlBlobs !== null) { for ($i = 0; $i < count($xmlBlobs); $i++) { $properties = (array)$xmlBlobs[$i]->Properties; $blobs[] = new Zend_Service_WindowsAzure_Storage_BlobInstance( $containerName, (string)$xmlBlobs[$i]->Name, (string)$xmlBlobs[$i]->Snapshot, (string)$properties['Etag'], (string)$properties['Last-Modified'], (string)$xmlBlobs[$i]->Url, (string)$properties['Content-Length'], (string)$properties['Content-Type'], (string)$properties['Content-Encoding'], (string)$properties['Content-Language'], (string)$properties['Cache-Control'], (string)$properties['BlobType'], (string)$properties['LeaseStatus'], false, $this->_parseMetadataElement($xmlBlobs[$i]) ); } } // Blob prefixes (folders) $xmlBlobs = $this->_parseResponse($response)->Blobs->BlobPrefix; if ($xmlBlobs !== null) { for ($i = 0; $i < count($xmlBlobs); $i++) { $blobs[] = new Zend_Service_WindowsAzure_Storage_BlobInstance( $containerName, (string)$xmlBlobs[$i]->Name, null, '', '', '', 0, '', '', '', '', '', '', true, $this->_parseMetadataElement($xmlBlobs[$i]) ); } } // More blobs? $xmlMarker = (string)$this->_parseResponse($response)->NextMarker; $currentResultCount = $currentResultCount + count($blobs); if ($maxResults !== null && $currentResultCount < $maxResults) { if ($xmlMarker !== null && $xmlMarker != '') { $blobs = array_merge($blobs, $this->listBlobs($containerName, $prefix, $delimiter, $maxResults, $marker, $include, $currentResultCount)); } } if ($maxResults !== null && count($blobs) > $maxResults) { $blobs = array_slice($blobs, 0, $maxResults); } return $blobs; } else { throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } } /** * Generate shared access URL * * @param string $containerName Container name * @param string $blobName Blob name * @param string $resource Signed resource - container (c) - blob (b) * @param string $permissions Signed permissions - read (r), write (w), delete (d) and list (l) * @param string $start The time at which the Shared Access Signature becomes valid. * @param string $expiry The time at which the Shared Access Signature becomes invalid. * @param string $identifier Signed identifier * @return string */ public function generateSharedAccessUrl($containerName = '', $blobName = '', $resource = 'b', $permissions = 'r', $start = '', $expiry = '', $identifier = '') { if ($containerName === '') { throw new Zend_Service_WindowsAzure_Exception('Container name is not specified.'); } if (!self::isValidContainerName($containerName)) { 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.'); } // Resource name $resourceName = self::createResourceName($containerName , $blobName); // Generate URL return $this->getBaseUrl() . '/' . $resourceName . '?' . $this->_sharedAccessSignatureCredentials->createSignedQueryString( $resourceName, '', $resource, $permissions, $start, $expiry, $identifier); } /** * Register this object as stream wrapper client * * @param string $name Protocol name * @return Zend_Service_WindowsAzure_Storage_Blob */ public function registerAsClient($name) { self::$_wrapperClients[$name] = $this; return $this; } /** * Unregister this object as stream wrapper client * * @param string $name Protocol name * @return Zend_Service_WindowsAzure_Storage_Blob */ public function unregisterAsClient($name) { unset(self::$_wrapperClients[$name]); return $this; } /** * Get wrapper client for stream type * * @param string $name Protocol name * @return Zend_Service_WindowsAzure_Storage_Blob */ public static function getWrapperClient($name) { return self::$_wrapperClients[$name]; } /** * Register this object as stream wrapper * * @param string $name Protocol name */ public function registerStreamWrapper($name = 'azure') { /** * @see Zend_Service_WindowsAzure_Storage_Blob_Stream */ require_once 'Zend/Service/WindowsAzure/Storage/Blob/Stream.php'; stream_register_wrapper($name, 'Zend_Service_WindowsAzure_Storage_Blob_Stream'); $this->registerAsClient($name); } /** * Unregister this object as stream wrapper * * @param string $name Protocol name * @return Zend_Service_WindowsAzure_Storage_Blob */ public function unregisterStreamWrapper($name = 'azure') { stream_wrapper_unregister($name); $this->unregisterAsClient($name); } /** * Create resource name * * @param string $containerName Container name * @param string $blobName Blob name * @return string */ public static function createResourceName($containerName = '', $blobName = '') { // Resource name $resourceName = $containerName . '/' . $blobName; if ($containerName === '' || $containerName === '$root') { $resourceName = $blobName; } if ($blobName === '') { $resourceName = $containerName; } return $resourceName; } /** * Is valid container name? * * @param string $containerName Container name * @return boolean */ public static function isValidContainerName($containerName = '') { if ($containerName == '$root') { return true; } if (preg_match("/^[a-z0-9][a-z0-9-]*$/", $containerName) === 0) { return false; } if (strpos($containerName, '--') !== false) { return false; } if (strtolower($containerName) != $containerName) { return false; } if (strlen($containerName) < 3 || strlen($containerName) > 63) { return false; } if (substr($containerName, -1) == '-') { return false; } return true; } /** * Get error message from Zend_Http_Response * * @param Zend_Http_Response $response Repsonse * @param string $alternativeError Alternative error message * @return string */ protected function _getErrorMessage(Zend_Http_Response $response, $alternativeError = 'Unknown error.') { $response = $this->_parseResponse($response); if ($response && $response->Message) { return (string)$response->Message; } else { return $alternativeError; } } /** * Generate block id * * @param int $part Block number * @return string Windows Azure Blob Storage block number */ protected function _generateBlockId($part = 0) { $returnValue = $part; while (strlen($returnValue) < 64) { $returnValue = '0' . $returnValue; } return $returnValue; } }