Current Directory: /home/astoriaah/www/old15/administrator/components/com_akeeba/engine/Postproc/Connector
Viewing File: /home/astoriaah/www/old15/administrator/components/com_akeeba/engine/Postproc/Connector/Azure.php
<?php
/**
* Copyright (c) 2009, RealDolmen
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of RealDolmen nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY RealDolmen ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL RealDolmen BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @category Microsoft
* @package Microsoft
* @copyright Copyright (c) 2009, RealDolmen (http://www.realdolmen.com)
* @license http://phpazure.codeplex.com/license
*/
namespace Akeeba\Engine\Postproc\Connector;
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Akeeba\Engine\Postproc\Connector\Azure\AzureStorage;
use Akeeba\Engine\Postproc\Connector\Azure\Blob\Container;
use Akeeba\Engine\Postproc\Connector\Azure\Blob\Instance;
use Akeeba\Engine\Postproc\Connector\Azure\Credentials;
use Akeeba\Engine\Postproc\Connector\Azure\Credentials\Sharedkey;
use Akeeba\Engine\Postproc\Connector\Azure\Credentials\Sharedsignature;
use Akeeba\Engine\Postproc\Connector\Azure\Exception\Api;
use Akeeba\Engine\Postproc\Connector\Azure\Http\Response;
use Akeeba\Engine\Postproc\Connector\Azure\Http\Transport;
use Akeeba\Engine\Postproc\Connector\Azure\Retrypolicy;
/**
* @category Microsoft
* @package Microsoft_WindowsAzure
* @subpackage Storage
* @copyright Copyright (c) 2009, RealDolmen (http://www.realdolmen.com)
* @license http://phpazure.codeplex.com/license
*/
class Azure extends AzureStorage
{
/**
* ACL - Private access
*/
const ACL_PRIVATE = false;
/**
* ACL - Public access
*/
const ACL_PUBLIC = true;
/**
* Maximal blob size (in bytes)
*/
const MAX_BLOB_SIZE = 67108864;
/**
* Maximal blob transfer size (in bytes)
*/
const MAX_BLOB_TRANSFER_SIZE = 4194304;
/**
* Stream wrapper clients
*
* @var array
*/
protected static $_wrapperClients = array();
/**
* SharedAccessSignature credentials
*
* @var Sharedsignature
*/
private $_sharedAccessSignatureCredentials = null;
/**
* Creates a new Azure connector instance
*
* @param string $host Storage host name
* @param string $accountName Account name for Windows Azure
* @param string $accountKey Account key for Windows Azure
* @param boolean $usePathStyleUri Use path-style URI's
* @param Retrypolicy $retryPolicy Retry policy to use when making requests
*/
public function __construct($host = AzureStorage::URL_DEV_BLOB, $accountName = Sharedkey::DEVSTORE_ACCOUNT, $accountKey = Sharedkey::DEVSTORE_KEY, $usePathStyleUri = false, Retrypolicy $retryPolicy = null)
{
parent::__construct($host, $accountName, $accountKey, $usePathStyleUri, $retryPolicy);
// API version
$this->_apiVersion = '2009-07-17';
// SharedAccessSignature credentials
$this->_sharedAccessSignatureCredentials = new Sharedsignature($accountName, $accountKey, $usePathStyleUri);
}
/**
* Get container
*
* @param string $containerName Container name
*
* @return Container
* @throws Api
*/
public function getContainer($containerName = '')
{
if ($containerName === '')
{
throw new Api('Container name is not specified.');
}
if (!self::isValidContainerName($containerName))
{
throw new Api('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', Transport::VERB_GET, array(), false, null, AzureStorage::RESOURCE_CONTAINER, Credentials::PERMISSION_READ);
if ($response->isSuccessful())
{
// Parse metadata
$metadata = array();
foreach ($response->getHeaders() as $key => $value)
{
if (substr(strtolower($key), 0, 10) == "x-ms-meta-")
{
$metadata[str_replace("x-ms-meta-", '', strtolower($key))] = $value;
}
}
// Return container
return new Container(
$containerName,
$response->getHeader('Etag'),
$response->getHeader('Last-modified'),
$metadata
);
}
else
{
throw new Api($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 array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
*
* @return object Partial blob properties
* @throws Api
*/
public function putBlob($containerName = '', $blobName = '', $localFileName = '', $metadata = array(), $additionalHeaders = array())
{
if ($containerName === '')
{
throw new Api('Container name is not specified.');
}
if (!self::isValidContainerName($containerName))
{
throw new Api('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 Api('Blob name is not specified.');
}
if ($localFileName === '')
{
throw new Api('Local file name is not specified.');
}
if (!file_exists($localFileName))
{
throw new Api('Local file not found.');
}
if ($containerName === '$root' && strpos($blobName, '/') !== false)
{
throw new Api('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)
{
throw new Api('The maximum part size for Windows Azure is 64Mb. Please set the Part Size for Archive Splitting to 64Mb or lower and retry backup.');
}
// Create metadata headers
$headers = array();
foreach ($metadata as $key => $value)
{
$headers["x-ms-meta-" . strtolower($key)] = $value;
}
// Additional headers?
foreach ($additionalHeaders as $key => $value)
{
$headers[$key] = $value;
}
// File contents
$fileContents = file_get_contents($localFileName);
// Resource name
$resourceName = self::createResourceName($containerName, $blobName);
// Perform request
$response = $this->performRequest($resourceName, '', Transport::VERB_PUT, $headers, false, $fileContents, AzureStorage::RESOURCE_BLOB, Credentials::PERMISSION_WRITE);
if ($response->isSuccessful())
{
return new Instance(
$containerName,
$blobName,
$response->getHeader('Etag'),
$response->getHeader('Last-modified'),
$this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
strlen($fileContents),
'',
'',
'',
false,
$metadata
);
}
else
{
throw new Api($this->getErrorMessage($response, 'Resource could not be accessed.'));
}
}
/**
* 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 array $additionalHeaders Additional headers. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
*
* @throws Api
*/
public function setBlobMetadata($containerName = '', $blobName = '', $metadata = array(), $additionalHeaders = array())
{
if ($containerName === '')
{
throw new Api('Container name is not specified.');
}
if (!self::isValidContainerName($containerName))
{
throw new Api('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 Api('Blob name is not specified.');
}
if ($containerName === '$root' && strpos($blobName, '/') !== false)
{
throw new Api('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();
foreach ($metadata as $key => $value)
{
$headers["x-ms-meta-" . strtolower($key)] = $value;
}
// Additional headers?
foreach ($additionalHeaders as $key => $value)
{
$headers[$key] = $value;
}
// Perform request
$response = $this->performRequest($containerName . '/' . $blobName, '?comp=metadata', Transport::VERB_PUT, $headers, false, null, AzureStorage::RESOURCE_BLOB, Credentials::PERMISSION_WRITE);
if (!$response->isSuccessful())
{
throw new Api($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 Api
*/
public function getBlob($containerName = '', $blobName = '', $localFileName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
{
if ($containerName === '')
{
throw new Api('Container name is not specified.');
}
if (!self::isValidContainerName($containerName))
{
throw new Api('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 Api('Blob name is not specified.');
}
if ($localFileName === '')
{
throw new Api('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 Api
*/
public function getBlobData($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
{
if ($containerName === '')
{
throw new Api('Container name is not specified.');
}
if (!self::isValidContainerName($containerName))
{
throw new Api('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 Api('Blob name is not specified.');
}
// Build query string
$queryString = array();
if (!is_null($snapshotId))
{
$queryString[] = 'snapshot=' . $snapshotId;
}
$queryString = self::createQueryStringFromArray($queryString);
// Additional headers?
$headers = array();
if (!is_null($leaseId))
{
$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, 'GET', $headers, false, null, self::RESOURCE_BLOB, Credentials::PERMISSION_READ);
if ($response->isSuccessful())
{
return $response->getBody();
}
else
{
throw new Api($this->getErrorMessage($response, 'Resource could not be accessed.'));
}
}
/**
* 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 Api
*/
public function deleteBlob($containerName = '', $blobName = '', $snapshotId = null, $leaseId = null, $additionalHeaders = array())
{
if ($containerName === '')
{
throw new Api('Container name is not specified.');
}
if (!self::isValidContainerName($containerName))
{
throw new Api('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 Api('Blob name is not specified.');
}
if ($containerName === '$root' && strpos($blobName, '/') !== false)
{
throw new Api('Blobs stored in the root container can not have a name containing a forward slash (/).');
}
// Build query string
$queryString = array();
if (!is_null($snapshotId))
{
$queryString[] = 'snapshot=' . $snapshotId;
}
$queryString = self::createQueryStringFromArray($queryString);
// Additional headers?
$headers = array();
if (!is_null($leaseId))
{
$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, 'DELETE', $headers, false, null, self::RESOURCE_BLOB, Credentials::PERMISSION_WRITE);
if (!$response->isSuccessful())
{
throw new Api($this->getErrorMessage($response, 'Resource could not be accessed.'));
}
}
/**
* 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 (!ereg("^[a-z0-9][a-z0-9-]*$", $containerName))
{
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 Response
*
* @param Response $response Repsonse
* @param string $alternativeError Alternative error message
*
* @return string
*/
protected function getErrorMessage(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;
}
}