Обновление клиента (apps, 3rdparty, install)

This commit is contained in:
root
2026-03-16 08:42:57 +00:00
parent b8905de237
commit f390426546
3354 changed files with 505213 additions and 3 deletions
@@ -0,0 +1,155 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
use MicrosoftAzure\Storage\Common\Internal\Validate;
use MicrosoftAzure\Storage\Common\Internal\ConnectionStringSource;
/**
* Configuration manager for accessing Windows Azure settings.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class CloudConfigurationManager
{
private static $_isInitialized = false;
private static $_sources;
/**
* Restrict users from creating instances from this class
*/
private function __construct()
{
}
/**
* Initializes the connection string source providers.
*
* @return void
*/
private static function _init()
{
if (!self::$_isInitialized) {
self::$_sources = array();
// Get list of default connection string sources.
$default = ConnectionStringSource::getDefaultSources();
foreach ($default as $name => $provider) {
self::$_sources[$name] = $provider;
}
self::$_isInitialized = true;
}
}
/**
* Gets a connection string from all available sources.
*
* @param string $key The connection string key name.
*
* @return string If the key does not exist return null.
*/
public static function getConnectionString($key)
{
Validate::canCastAsString($key, 'key');
self::_init();
$value = null;
foreach (self::$_sources as $source) {
$value = call_user_func_array($source, array($key));
if (!empty($value)) {
break;
}
}
return $value;
}
/**
* Registers a new connection string source provider. If the source to get
* registered is a default source, only the name of the source is required.
*
* @param string $name The source name.
* @param callable $provider The source callback.
* @param boolean $prepend When true, the $provider is processed first when
* calling getConnectionString. When false (the default) the $provider is
* processed after the existing callbacks.
*
* @return void
*/
public static function registerSource($name, $provider = null, $prepend = false)
{
Validate::canCastAsString($name, 'name');
Validate::notNullOrEmpty($name, 'name');
self::_init();
$default = ConnectionStringSource::getDefaultSources();
// Try to get callback if the user is trying to register a default source.
$provider = Utilities::tryGetValue($default, $name, $provider);
Validate::notNullOrEmpty($provider, 'callback');
if ($prepend) {
self::$_sources = array_merge(
array($name => $provider),
self::$_sources
);
} else {
self::$_sources[$name] = $provider;
}
}
/**
* Unregisters a connection string source.
*
* @param string $name The source name.
*
* @return callable
*/
public static function unregisterSource($name)
{
Validate::canCastAsString($name, 'name');
Validate::notNullOrEmpty($name, 'name');
self::_init();
$sourceCallback = Utilities::tryGetValue(self::$_sources, $name);
if (!is_null($sourceCallback)) {
unset(self::$_sources[$name]);
}
return $sourceCallback;
}
}
@@ -0,0 +1,55 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Exceptions
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Exceptions;
use MicrosoftAzure\Storage\Common\Internal\Resources;
/**
* Exception thrown if an argument type does not match with the expected type.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Exceptions
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class InvalidArgumentTypeException extends \InvalidArgumentException
{
/**
* Constructor.
*
* @param string $validType The valid type that should be provided by the user.
* @param string $name The parameter name.
*
* @return InvalidArgumentTypeException
*/
public function __construct($validType, $name = null)
{
parent::__construct(
sprintf(Resources::INVALID_PARAM_MSG, $name, $validType)
);
}
}
@@ -0,0 +1,177 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Exceptions
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Exceptions;
use MicrosoftAzure\Storage\Common\Internal\Serialization\XmlSerializer;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use Psr\Http\Message\ResponseInterface;
/**
* Fires when the response code is incorrect.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Exceptions
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class ServiceException extends \LogicException
{
private $response;
private $errorText;
private $errorMessage;
/**
* Constructor
*
* @param ResponseInterface $response The response received that causes the
* exception.
*
* @internal
*
* @return ServiceException
*/
public function __construct(ResponseInterface $response)
{
parent::__construct(
sprintf(
Resources::AZURE_ERROR_MSG,
$response->getStatusCode(),
$response->getReasonPhrase(),
$response->getBody()
)
);
$this->code = $response->getStatusCode();
$this->response = $response;
$this->errorText = $response->getReasonPhrase();
$this->errorMessage = self::parseErrorMessage($response);
}
/**
* Error message to be parsed.
*
* @param ResponseInterface $response The response with a response body.
*
* @internal
*
* @return string
*/
protected static function parseErrorMessage(ResponseInterface $response)
{
//try to parse using xml serializer, if failed, return the whole body
//as the error message.
$serializer = new XmlSerializer();
$errorMessage = '';
try {
$internalErrors = libxml_use_internal_errors(true);
$parsedArray = $serializer->unserialize($response->getBody());
$messages = array();
foreach (libxml_get_errors() as $error) {
$messages[] = $error->message;
}
if (!empty($messages)) {
throw new \Exception(
sprintf(Resources::ERROR_CANNOT_PARSE_XML, implode('; ', $messages))
);
}
libxml_use_internal_errors($internalErrors);
if (array_key_exists(Resources::XTAG_MESSAGE, $parsedArray)) {
$errorMessage = $parsedArray[Resources::XTAG_MESSAGE];
} else {
$errorMessage = $response->getBody();
}
} catch (\Exception $e) {
$errorMessage = $response->getBody();
}
return $errorMessage;
}
/**
* Gets error text.
*
* @return string
*/
public function getErrorText()
{
return $this->errorText;
}
/**
* Gets detailed error message.
*
* @return string
*/
public function getErrorMessage()
{
return $this->errorMessage;
}
/**
* Gets the request ID of the failure.
*
* @return string
*/
public function getRequestID()
{
$requestID = '';
if (array_key_exists(
Resources::X_MS_REQUEST_ID,
$this->getResponse()->getHeaders()
)) {
$requestID = $this->getResponse()
->getHeaders()[Resources::X_MS_REQUEST_ID][0];
}
return $requestID;
}
/**
* Gets the Date of the failure.
*
* @return string
*/
public function getDate()
{
$date = '';
if (array_key_exists(
Resources::DATE,
$this->getResponse()->getHeaders()
)) {
$date = $this->getResponse()
->getHeaders()[Resources::DATE][0];
}
return $date;
}
/**
* Gets the response of the failue.
*
* @return ResponseInterface
*/
public function getResponse()
{
return $this->response;
}
}
@@ -0,0 +1,260 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
use MicrosoftAzure\Storage\Common\Models\AccessPolicy;
use MicrosoftAzure\Storage\Common\Models\SignedIdentifier;
use MicrosoftAzure\Storage\Common\Internal\Serialization\XmlSerializer;
/**
* Provide base class for service ACLs.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
abstract class ACLBase
{
private $signedIdentifiers = array();
private $resourceType = '';
/**
* Create an AccessPolicy object by resource type.
*
* @return AccessPolicy
*/
abstract protected static function createAccessPolicy();
/**
* Validate if the resource type for the class.
*
* @param string $resourceType the resource type to be validated.
*
* @throws \InvalidArgumentException
*
* @internal
*
* @return void
*/
abstract protected static function validateResourceType($resourceType);
/**
* Converts signed identifiers to array representation for XML serialization
*
* @internal
*
* @return array
*/
public function toArray()
{
$array = array();
foreach ($this->getSignedIdentifiers() as $value) {
$array[] = $value->toArray();
}
return $array;
}
/**
* Converts this signed identifiers to XML representation.
*
* @param XmlSerializer $xmlSerializer The XML serializer.
*
* @internal
*
* @return string
*/
public function toXml(XmlSerializer $serializer)
{
$properties = array(
XmlSerializer::DEFAULT_TAG => Resources::XTAG_SIGNED_IDENTIFIER,
XmlSerializer::ROOT_NAME => Resources::XTAG_SIGNED_IDENTIFIERS
);
return $serializer->serialize($this->toArray(), $properties);
}
/**
* Construct the signed identifiers from a given parsed XML in array
* representation.
*
* @param array|null $parsed The parsed XML into array representation.
*
* @internal
*
* @return void
*/
public function fromXmlArray(array $parsed = null)
{
$this->setSignedIdentifiers(array());
// Initialize signed identifiers.
if (!empty($parsed) &&
is_array($parsed[Resources::XTAG_SIGNED_IDENTIFIER])
) {
$entries = $parsed[Resources::XTAG_SIGNED_IDENTIFIER];
$temp = Utilities::getArray($entries);
foreach ($temp as $value) {
$accessPolicy = $value[Resources::XTAG_ACCESS_POLICY];
$startString = urldecode(
$accessPolicy[Resources::XTAG_SIGNED_START]
);
$expiryString = urldecode(
$accessPolicy[Resources::XTAG_SIGNED_EXPIRY]
);
$start = Utilities::convertToDateTime($startString);
$expiry = Utilities::convertToDateTime($expiryString);
$permission = $accessPolicy[Resources::XTAG_SIGNED_PERMISSION];
$id = $value[Resources::XTAG_SIGNED_ID];
$this->addSignedIdentifier($id, $start, $expiry, $permission);
}
}
}
/**
* Gets the type of resource this ACL relate to.
*
* @internal
*
* @return string
*/
protected function getResourceType()
{
return $this->resourceType;
}
/**
* Set the type of resource this ACL relate to.
*
* @internal
*
* @return void
*/
protected function setResourceType($resourceType)
{
static::validateResourceType($resourceType);
$this->resourceType = $resourceType;
}
/**
* Add a signed identifier to the ACL.
*
* @param string $id A unique id for this signed identifier.
* @param \DateTime $start The time at which the Shared Access
* Signature becomes valid. If omitted, start
* time for this call is assumed to be the
* time when the service receives the
* request.
* @param \DateTime $expiry The time at which the Shared Access
* Signature becomes invalid.
* @param string $permissions The permissions associated with the Shared
* Access Signature. The user is restricted to
* operations allowed by the permissions.
*
* @return void
*
* @see https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/establishing-a-stored-access-policy
*/
public function addSignedIdentifier(
$id,
\DateTime $start,
\DateTime $expiry,
$permissions
) {
Validate::canCastAsString($id, 'id');
if ($start != null) {
Validate::isDate($start);
}
Validate::isDate($expiry);
Validate::canCastAsString($permissions, 'permissions');
$accessPolicy = static::createAccessPolicy();
$accessPolicy->setStart($start);
$accessPolicy->setExpiry($expiry);
$accessPolicy->setPermission($permissions);
$signedIdentifier = new SignedIdentifier();
$signedIdentifier->setId($id);
$signedIdentifier->setAccessPolicy($accessPolicy);
// Remove the signed identifier with the same ID.
$this->removeSignedIdentifier($id);
// There can be no more than 5 signed identifiers at the same time.
Validate::isTrue(
count($this->getSignedIdentifiers()) < 5,
Resources::ERROR_TOO_MANY_SIGNED_IDENTIFIERS
);
$this->signedIdentifiers[] = $signedIdentifier;
}
/**
* Remove the signed identifier with given ID.
*
* @param string $id The ID of the signed identifier to be removed.
*
* @return boolean
*/
public function removeSignedIdentifier($id)
{
Validate::canCastAsString($id, 'id');
//var_dump($this->signedIdentifiers);
for ($i = 0; $i < count($this->signedIdentifiers); ++$i) {
if ($this->signedIdentifiers[$i]->getId() == $id) {
array_splice($this->signedIdentifiers, $i, 1);
return true;
}
}
return false;
}
/**
* Gets signed identifiers.
*
* @return array
*/
public function getSignedIdentifiers()
{
return $this->signedIdentifiers;
}
public function setSignedIdentifiers(array $signedIdentifiers)
{
// There can be no more than 5 signed identifiers at the same time.
Validate::isTrue(
count($signedIdentifiers) <= 5,
Resources::ERROR_TOO_MANY_SIGNED_IDENTIFIERS
);
$this->signedIdentifiers = $signedIdentifiers;
}
}
@@ -0,0 +1,52 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Authentication
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal\Authentication;
use GuzzleHttp\Psr7\Request;
/**
* Interface for azure authentication schemes.
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Authentication
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
interface IAuthScheme
{
/**
* Signs a request.
*
* @param \GuzzleHttp\Psr7\Request $request HTTP request object.
*
* @abstract
*
* @return \GuzzleHttp\Psr7\Request
*/
public function signRequest(Request $request);
}
@@ -0,0 +1,96 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Authentication
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal\Authentication;
use GuzzleHttp\Psr7\Request;
use MicrosoftAzure\Storage\Common\Internal\Resources;
/**
* Base class for azure authentication schemes.
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Authentication
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class SharedAccessSignatureAuthScheme implements IAuthScheme
{
/**
* The sas token
*/
protected $sasToken;
/**
* Constructor.
*
* @param string $sasToken shared access signature token.
*
*/
public function __construct($sasToken)
{
// Remove '?' in front of the SAS token if existing
$this->sasToken = str_replace('?', '', $sasToken, $i);
if ($i > 1) {
throw new \InvalidArgumentException(
sprintf(
Resources::INVALID_SAS_TOKEN,
$sasToken
)
);
}
}
/**
* Adds authentication header to the request headers.
*
* @param \GuzzleHttp\Psr7\Request $request HTTP request object.
*
* @abstract
*
* @return \GuzzleHttp\Psr7\Request
*/
public function signRequest(Request $request)
{
// initial URI
$uri = $request->getUri();
// new query values from SAS token
$queryValues = explode('&', $this->sasToken);
// append SAS token query values to existing URI
foreach ($queryValues as $queryField) {
list($key, $value) = explode('=', $queryField);
$uri = \GuzzleHttp\Psr7\Uri::withQueryValue($uri, $key, $value);
}
// replace URI
return $request->withUri($uri, true);
}
}
@@ -0,0 +1,317 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Authentication
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal\Authentication;
use GuzzleHttp\Psr7\Query;
use GuzzleHttp\Psr7\Request;
use MicrosoftAzure\Storage\Common\Internal\Http\HttpFormatter;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
/**
* Provides shared key authentication scheme for blob and queue. For more info
* check: http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Authentication
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class SharedKeyAuthScheme implements IAuthScheme
{
/**
* The account name
*/
protected $accountName;
/**
* The account key
*/
protected $accountKey;
/**
* The included headers
*/
protected $includedHeaders;
/**
* Constructor.
*
* @param string $accountName storage account name.
* @param string $accountKey storage account primary or secondary key.
*
* @return SharedKeyAuthScheme
*/
public function __construct($accountName, $accountKey)
{
$this->accountKey = $accountKey;
$this->accountName = $accountName;
$this->includedHeaders = array();
$this->includedHeaders[] = Resources::CONTENT_ENCODING;
$this->includedHeaders[] = Resources::CONTENT_LANGUAGE;
$this->includedHeaders[] = Resources::CONTENT_LENGTH;
$this->includedHeaders[] = Resources::CONTENT_MD5;
$this->includedHeaders[] = Resources::CONTENT_TYPE;
$this->includedHeaders[] = Resources::DATE;
$this->includedHeaders[] = Resources::IF_MODIFIED_SINCE;
$this->includedHeaders[] = Resources::IF_MATCH;
$this->includedHeaders[] = Resources::IF_NONE_MATCH;
$this->includedHeaders[] = Resources::IF_UNMODIFIED_SINCE;
$this->includedHeaders[] = Resources::RANGE;
}
/**
* Computes the authorization signature for blob and queue shared key.
*
* @param array $headers request headers.
* @param string $url reuqest url.
* @param array $queryParams query variables.
* @param string $httpMethod request http method.
*
* @see Blob and Queue Services (Shared Key Authentication) at
* http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
*
* @return string
*/
protected function computeSignature(
array $headers,
$url,
array $queryParams,
$httpMethod
) {
$canonicalizedHeaders = $this->computeCanonicalizedHeaders($headers);
$canonicalizedResource = $this->computeCanonicalizedResource(
$url,
$queryParams
);
$stringToSign = array();
$stringToSign[] = strtoupper($httpMethod);
foreach ($this->includedHeaders as $header) {
$stringToSign[] = Utilities::tryGetValueInsensitive($header, $headers);
}
if (count($canonicalizedHeaders) > 0) {
$stringToSign[] = implode("\n", $canonicalizedHeaders);
}
$stringToSign[] = $canonicalizedResource;
$stringToSign = implode("\n", $stringToSign);
return $stringToSign;
}
/**
* Returns authorization header to be included in the request.
*
* @param array $headers request headers.
* @param string $url reuqest url.
* @param array $queryParams query variables.
* @param string $httpMethod request http method.
*
* @see Specifying the Authorization Header section at
* http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
*
* @return string
*/
public function getAuthorizationHeader(
array $headers,
$url,
array $queryParams,
$httpMethod
) {
$signature = $this->computeSignature(
$headers,
$url,
$queryParams,
$httpMethod
);
return 'SharedKey ' . $this->accountName . ':' . base64_encode(
hash_hmac('sha256', $signature, base64_decode($this->accountKey), true)
);
}
/**
* Computes canonicalized headers for headers array.
*
* @param array $headers request headers.
*
* @see Constructing the Canonicalized Headers String section at
* http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
*
* @return array
*/
protected function computeCanonicalizedHeaders($headers)
{
$canonicalizedHeaders = array();
$normalizedHeaders = array();
$validPrefix = Resources::X_MS_HEADER_PREFIX;
if (is_null($normalizedHeaders)) {
return $canonicalizedHeaders;
}
foreach ($headers as $header => $value) {
// Convert header to lower case.
$header = strtolower($header);
// Retrieve all headers for the resource that begin with x-ms-,
// including the x-ms-date header.
if (Utilities::startsWith($header, $validPrefix)) {
// Unfold the string by replacing any breaking white space
// (meaning what splits the headers, which is \r\n) with a single
// space.
$value = str_replace("\r\n", ' ', $value);
// Trim any white space around the colon in the header.
$value = ltrim($value);
$header = rtrim($header);
$normalizedHeaders[$header] = $value;
}
}
// Sort the headers lexicographically by header name, in ascending order.
// Note that each header may appear only once in the string.
ksort($normalizedHeaders);
foreach ($normalizedHeaders as $key => $value) {
$canonicalizedHeaders[] = $key . ':' . $value;
}
return $canonicalizedHeaders;
}
/**
* Computes canonicalized resources from URL using Table formar
*
* @param string $url request url.
* @param array $queryParams request query variables.
*
* @see Constructing the Canonicalized Resource String section at
* http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
*
* @return string
*/
protected function computeCanonicalizedResourceForTable($url, $queryParams)
{
$queryParams = array_change_key_case($queryParams);
// 1. Beginning with an empty string (""), append a forward slash (/),
// followed by the name of the account that owns the accessed resource.
$canonicalizedResource = '/' . $this->accountName;
// 2. Append the resource's encoded URI path, without any query parameters.
$canonicalizedResource .= parse_url($url, PHP_URL_PATH);
// 3. The query string should include the question mark and the comp
// parameter (for example, ?comp=metadata). No other parameters should
// be included on the query string.
if (array_key_exists(Resources::QP_COMP, $queryParams)) {
$canonicalizedResource .= '?' . Resources::QP_COMP . '=';
$canonicalizedResource .= $queryParams[Resources::QP_COMP];
}
return $canonicalizedResource;
}
/**
* Computes canonicalized resources from URL.
*
* @param string $url request url.
* @param array $queryParams request query variables.
*
* @see Constructing the Canonicalized Resource String section at
* http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
*
* @return string
*/
protected function computeCanonicalizedResource($url, $queryParams)
{
$queryParams = array_change_key_case($queryParams);
// 1. Beginning with an empty string (""), append a forward slash (/),
// followed by the name of the account that owns the accessed resource.
$canonicalizedResource = '/' . $this->accountName;
// 2. Append the resource's encoded URI path, without any query parameters.
$canonicalizedResource .= parse_url($url, PHP_URL_PATH);
// 3. Retrieve all query parameters on the resource URI, including the comp
// parameter if it exists.
// 4. Sort the query parameters lexicographically by parameter name, in
// ascending order.
if (count($queryParams) > 0) {
ksort($queryParams);
}
// 5. Convert all parameter names to lowercase.
// 6. URL-decode each query parameter name and value.
// 7. Append each query parameter name and value to the string in the
// following format:
// parameter-name:parameter-value
// 9. Group query parameters
// 10. Append a new line character (\n) after each name-value pair.
foreach ($queryParams as $key => $value) {
// $value must already be ordered lexicographically
// See: ServiceRestProxy::groupQueryValues
$canonicalizedResource .= "\n" . $key . ':' . $value;
}
return $canonicalizedResource;
}
/**
* Adds authentication header to the request headers.
*
* @param \GuzzleHttp\Psr7\Request $request HTTP request object.
*
* @abstract
*
* @return \GuzzleHttp\Psr7\Request
*/
public function signRequest(Request $request)
{
$requestHeaders = HttpFormatter::formatHeaders($request->getHeaders());
$signedKey = $this->getAuthorizationHeader(
$requestHeaders,
$request->getUri(),
Query::parse(
$request->getUri()->getQuery()
),
$request->getMethod()
);
return $request->withHeader(Resources::AUTHENTICATION, $signedKey);
}
}
@@ -0,0 +1,73 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Authentication
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2019 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal\Authentication;
use GuzzleHttp\Psr7\Request;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Validate;
/**
* Azure authentication scheme for token credential.
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Authentication
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2019 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class TokenAuthScheme implements IAuthScheme
{
/**
* The authentication token
*/
protected $tokenRef;
/**
* Constructor.
*
* @param string $token the token used for AAD authentication.
*/
public function __construct(&$token)
{
$this->tokenRef =& $token;
}
/**
* Adds authentication header to the request headers.
*
* @param \GuzzleHttp\Psr7\Request $request HTTP request object.
*
* @abstract
*
* @return \GuzzleHttp\Psr7\Request
*/
public function signRequest(Request $request)
{
$bearerToken = "Bearer ". $this->tokenRef;
return $request->withHeader(Resources::AUTHENTICATION, $bearerToken);
}
}
@@ -0,0 +1,335 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
/**
* Helper methods for parsing connection strings. The rules for formatting connection
* strings are defined here:
* www.connectionstrings.com/articles/show/important-rules-for-connection-strings
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class ConnectionStringParser
{
const EXPECT_KEY = 'ExpectKey';
const EXPECT_ASSIGNMENT = 'ExpectAssignment';
const EXPECT_VALUE = 'ExpectValue';
const EXPECT_SEPARATOR = 'ExpectSeparator';
private $_argumentName;
private $_value;
private $_pos;
private $_state;
/**
* Parses the connection string into a collection of key/value pairs.
*
* @param string $argumentName Name of the argument to be used in error
* messages.
* @param string $connectionString Connection string.
*
* @return array
*/
public static function parseConnectionString($argumentName, $connectionString)
{
Validate::canCastAsString($argumentName, 'argumentName');
Validate::notNullOrEmpty($argumentName, 'argumentName');
Validate::canCastAsString($connectionString, 'connectionString');
Validate::notNullOrEmpty($connectionString, 'connectionString');
$parser = new ConnectionStringParser($argumentName, $connectionString);
return $parser->_parse();
}
/**
* Initializes the object.
*
* @param string $argumentName Name of the argument to be used in error
* messages.
* @param string $value Connection string.
*/
private function __construct($argumentName, $value)
{
$this->_argumentName = $argumentName;
$this->_value = $value;
$this->_pos = 0;
$this->_state = ConnectionStringParser::EXPECT_KEY;
}
/**
* Parses the connection string.
*
* @return array
*
* @throws \RuntimeException
*/
private function _parse()
{
$key = null;
$value = null;
$connectionStringValues = array();
while (true) {
$this->_skipWhiteSpaces();
if ($this->_pos == strlen($this->_value)
&& $this->_state != ConnectionStringParser::EXPECT_VALUE
) {
// Not stopping after the end has been reached and a value is
// expected results in creating an empty value, which we expect.
break;
}
switch ($this->_state) {
case ConnectionStringParser::EXPECT_KEY:
$key = $this->_extractKey();
$this->_state = ConnectionStringParser::EXPECT_ASSIGNMENT;
break;
case ConnectionStringParser::EXPECT_ASSIGNMENT:
$this->_skipOperator('=');
$this->_state = ConnectionStringParser::EXPECT_VALUE;
break;
case ConnectionStringParser::EXPECT_VALUE:
$value = $this->_extractValue();
$this->_state =
ConnectionStringParser::EXPECT_SEPARATOR;
$connectionStringValues[$key] = $value;
$key = null;
$value = null;
break;
default:
$this->_skipOperator(';');
$this->_state = ConnectionStringParser::EXPECT_KEY;
break;
}
}
// Must end parsing in the valid state (expected key or separator)
if ($this->_state == ConnectionStringParser::EXPECT_ASSIGNMENT) {
throw $this->_createException(
$this->_pos,
Resources::MISSING_CONNECTION_STRING_CHAR,
'='
);
}
return $connectionStringValues;
}
/**
*Generates an invalid connection string exception with the detailed error
* message.
*
* @param integer $position The position of the error.
* @param string $errorString The short error formatting string.
*
* @return \RuntimeException
*/
private function _createException($position, $errorString)
{
$arguments = func_get_args();
// Remove first and second arguments (position and error string)
unset($arguments[0], $arguments[1]);
// Create a short error message.
$errorString = vsprintf($errorString, $arguments);
// Add position.
$errorString = sprintf(
Resources::ERROR_PARSING_STRING,
$errorString,
$position
);
// Create final error message.
$errorString = sprintf(
Resources::INVALID_CONNECTION_STRING,
$this->_argumentName,
$errorString
);
return new \RuntimeException($errorString);
}
/**
* Skips whitespaces at the current position.
*
* @return void
*/
private function _skipWhiteSpaces()
{
while ($this->_pos < strlen($this->_value)
&& ctype_space($this->_value[$this->_pos])
) {
$this->_pos++;
}
}
/**
* Extracts the key's value.
*
* @return string
*/
private function _extractValue()
{
$value = Resources::EMPTY_STRING;
if ($this->_pos < strlen($this->_value)) {
$ch = $this->_value[$this->_pos];
if ($ch == '"' || $ch == '\'') {
// Value is contained between double quotes or skipped single quotes.
$this->_pos++;
$value = $this->_extractString($ch);
} else {
$firstPos = $this->_pos;
$isFound = false;
while ($this->_pos < strlen($this->_value) && !$isFound) {
$ch = $this->_value[$this->_pos];
if ($ch == ';') {
$isFound = true;
} else {
$this->_pos++;
}
}
$value = rtrim(
substr($this->_value, $firstPos, $this->_pos - $firstPos)
);
}
}
return $value;
}
/**
* Extracts key at the current position.
*
* @return string
*/
private function _extractKey()
{
$key = null;
$firstPos = $this->_pos;
$ch = $this->_value[$this->_pos];
if ($ch == '"' || $ch == '\'') {
$this->_pos++;
$key = $this->_extractString($ch);
} elseif ($ch == ';' || $ch == '=') {
// Key name was expected.
throw $this->_createException(
$firstPos,
Resources::ERROR_CONNECTION_STRING_MISSING_KEY
);
} else {
while ($this->_pos < strlen($this->_value)) {
$ch = $this->_value[$this->_pos];
// At this point we've read the key, break.
if ($ch == '=') {
break;
}
$this->_pos++;
}
$key = rtrim(substr($this->_value, $firstPos, $this->_pos - $firstPos));
}
if (strlen($key) == 0) {
// Empty key name.
throw $this->_createException(
$firstPos,
Resources::ERROR_CONNECTION_STRING_EMPTY_KEY
);
}
return $key;
}
/**
* Extracts the string until the given quotation mark.
*
* @param string $quote The quotation mark terminating the string.
*
* @return string
*/
private function _extractString($quote)
{
$firstPos = $this->_pos;
while ($this->_pos < strlen($this->_value)
&& $this->_value[$this->_pos] != $quote
) {
$this->_pos++;
}
if ($this->_pos == strlen($this->_value)) {
// Runaway string.
throw $this->_createException(
$this->_pos,
Resources::ERROR_CONNECTION_STRING_MISSING_CHARACTER,
$quote
);
}
return substr($this->_value, $firstPos, $this->_pos++ - $firstPos);
}
/**
* Skips specified operator.
*
* @param string $operatorChar The operator character.
*
* @return void
*
* @throws \RuntimeException
*/
private function _skipOperator($operatorChar)
{
if ($this->_value[$this->_pos] != $operatorChar) {
// Character was expected.
throw $this->_createException(
$this->_pos,
Resources::MISSING_CONNECTION_STRING_CHAR,
$operatorChar
);
}
$this->_pos++;
}
}
@@ -0,0 +1,83 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
/**
* Holder for default connection string sources used in CloudConfigurationManager.
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class ConnectionStringSource
{
private static $_defaultSources;
private static $_isInitialized;
const ENVIRONMENT_SOURCE = 'environment_source';
/**
* Initializes the default sources.
*
* @return void
*/
private static function _init()
{
if (!self::$_isInitialized) {
self::$_defaultSources = array(
self::ENVIRONMENT_SOURCE => array(__CLASS__, 'environmentSource')
);
self::$_isInitialized = true;
}
}
/**
* Gets a connection string value from the system environment.
*
* @param string $key The connection string name.
*
* @return string
*/
public static function environmentSource($key)
{
Validate::canCastAsString($key, 'key');
return getenv($key);
}
/**
* Gets list of default sources.
*
* @return array
*/
public static function getDefaultSources()
{
self::_init();
return self::$_defaultSources;
}
}
@@ -0,0 +1,432 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Http
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal\Http;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Validate;
use MicrosoftAzure\Storage\Common\Models\ServiceOptions;
/**
* Holds basic elements for making HTTP call.
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Http
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class HttpCallContext
{
private $_method;
private $_headers;
private $_queryParams;
private $_postParameters;
private $_uri;
private $_path;
private $_statusCodes;
private $_body;
private $_serviceOptions;
/**
* Default constructor.
*/
public function __construct()
{
$this->_method = null;
$this->_body = null;
$this->_path = null;
$this->_uri = null;
$this->_queryParams = array();
$this->_postParameters = array();
$this->_statusCodes = array();
$this->_headers = array();
$this->_serviceOptions = new ServiceOptions();
}
/**
* Gets method.
*
* @return string
*/
public function getMethod()
{
return $this->_method;
}
/**
* Sets method.
*
* @param string $method The method value.
*
* @return void
*/
public function setMethod($method)
{
Validate::canCastAsString($method, 'method');
$this->_method = $method;
}
/**
* Gets headers.
*
* @return array
*/
public function getHeaders()
{
return $this->_headers;
}
/**
* Sets headers.
*
* Ignores the header if its value is empty.
*
* @param array $headers The headers value.
*
* @return void
*/
public function setHeaders(array $headers)
{
$this->_headers = array();
foreach ($headers as $key => $value) {
$this->addHeader($key, $value);
}
}
/**
* Gets queryParams.
*
* @return array
*/
public function getQueryParameters()
{
return $this->_queryParams;
}
/**
* Sets queryParams.
*
* Ignores the query variable if its value is empty.
*
* @param array $queryParams The queryParams value.
*
* @return void
*/
public function setQueryParameters(array $queryParams)
{
$this->_queryParams = array();
foreach ($queryParams as $key => $value) {
$this->addQueryParameter($key, $value);
}
}
/**
* Gets uri.
*
* @return string
*/
public function getUri()
{
return $this->_uri;
}
/**
* Sets uri.
*
* @param string $uri The uri value.
*
* @return void
*/
public function setUri($uri)
{
Validate::canCastAsString($uri, 'uri');
$this->_uri = $uri;
}
/**
* Gets path.
*
* @return string
*/
public function getPath()
{
return $this->_path;
}
/**
* Sets path.
*
* @param string $path The path value.
*
* @return void
*/
public function setPath($path)
{
Validate::canCastAsString($path, 'path');
$this->_path = $path;
}
/**
* Gets statusCodes.
*
* @return array
*/
public function getStatusCodes()
{
return $this->_statusCodes;
}
/**
* Sets statusCodes.
*
* @param array $statusCodes The statusCodes value.
*
* @return void
*/
public function setStatusCodes(array $statusCodes)
{
$this->_statusCodes = array();
foreach ($statusCodes as $value) {
$this->addStatusCode($value);
}
}
/**
* Gets body.
*
* @return string
*/
public function getBody()
{
return $this->_body;
}
/**
* Sets body.
*
* @param string $body The body value.
*
* @return void
*/
public function setBody($body)
{
Validate::canCastAsString($body, 'body');
$this->_body = $body;
}
/**
* Adds or sets header pair.
*
* @param string $name The HTTP header name.
* @param string $value The HTTP header value.
*
* @return void
*/
public function addHeader($name, $value)
{
Validate::canCastAsString($name, 'name');
Validate::canCastAsString($value, 'value');
$this->_headers[$name] = $value;
}
/**
* Adds or sets header pair.
*
* Ignores header if it's value satisfies empty().
*
* @param string $name The HTTP header name.
* @param string $value The HTTP header value.
*
* @return void
*/
public function addOptionalHeader($name, $value)
{
Validate::canCastAsString($name, 'name');
Validate::canCastAsString($value, 'value');
if (!empty($value)) {
$this->_headers[$name] = $value;
}
}
/**
* Removes header from the HTTP request headers.
*
* @param string $name The HTTP header name.
*
* @return void
*/
public function removeHeader($name)
{
Validate::canCastAsString($name, 'name');
Validate::notNullOrEmpty($name, 'name');
unset($this->_headers[$name]);
}
/**
* Adds or sets query parameter pair.
*
* @param string $name The URI query parameter name.
* @param string $value The URI query parameter value.
*
* @return void
*/
public function addQueryParameter($name, $value)
{
Validate::canCastAsString($name, 'name');
Validate::canCastAsString($value, 'value');
$this->_queryParams[$name] = $value;
}
/**
* Gets HTTP POST parameters.
*
* @return array
*/
public function getPostParameters()
{
return $this->_postParameters;
}
/**
* Sets HTTP POST parameters.
*
* @param array $postParameters The HTTP POST parameters.
*
* @return void
*/
public function setPostParameters(array $postParameters)
{
Validate::isArray($postParameters, 'postParameters');
$this->_postParameters = $postParameters;
}
/**
* Adds or sets query parameter pair.
*
* Ignores query parameter if it's value satisfies empty().
*
* @param string $name The URI query parameter name.
* @param string $value The URI query parameter value.
*
* @return void
*/
public function addOptionalQueryParameter($name, $value)
{
Validate::canCastAsString($name, 'name');
Validate::canCastAsString($value, 'value');
if (!empty($value)) {
$this->_queryParams[$name] = $value;
}
}
/**
* Adds status code to the expected status codes.
*
* @param integer $statusCode The expected status code.
*
* @return void
*/
public function addStatusCode($statusCode)
{
Validate::isInteger($statusCode, 'statusCode');
$this->_statusCodes[] = $statusCode;
}
/**
* Gets header value.
*
* @param string $name The header name.
*
* @return mixed
*/
public function getHeader($name)
{
return Utilities::tryGetValue($this->_headers, $name);
}
/**
* Gets the saved service options
*
* @return ServiceOptions
*/
public function getServiceOptions()
{
if ($this->_serviceOptions == null) {
$this->_serviceOptions = new ServiceOptions();
}
return $this->_serviceOptions;
}
/**
* Sets the service options
*
* @param ServiceOptions $serviceOptions the service options to be set.
*
* @return void
*/
public function setServiceOptions(ServiceOptions $serviceOptions)
{
$this->_serviceOptions = $serviceOptions;
}
/**
* Converts the context object to string.
*
* @return string
*/
public function __toString()
{
$headers = Resources::EMPTY_STRING;
$uri = $this->_uri;
if ($uri === null) {
$uri = '/';
} elseif ($uri[strlen($uri)-1] != '/') {
$uri = $uri.'/';
}
foreach ($this->_headers as $key => $value) {
$headers .= "$key: $value\n";
}
$str = "$this->_method $uri$this->_path HTTP/1.1\n$headers\n";
$str .= "$this->_body";
return $str;
}
}
@@ -0,0 +1,59 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Http
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal\Http;
/**
* Helper class to format the http headers
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Http
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class HttpFormatter
{
/**
* Convert a http headers array into an uniformed format for further process
*
* @param array $headers headers for format
*
* @return array
*/
public static function formatHeaders(array $headers)
{
$result = array();
foreach ($headers as $key => $value) {
if (is_array($value) && count($value) == 1) {
$result[strtolower($key)] = $value[0];
} else {
$result[strtolower($key)] = $value;
}
}
return $result;
}
}
@@ -0,0 +1,142 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
/**
* Trait implementing common logic for metadata, last-modified and etag. The
* code is shared for multiple REST APIs.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
trait MetadataTrait
{
private $lastModified;
private $etag;
private $metadata;
/**
* Any operation that modifies the share or its properties or metadata
* updates the last modified time. Operations on files do not affect the
* last modified time of the share.
*
* @return \DateTime.
*/
public function getLastModified()
{
return $this->lastModified;
}
/**
* Sets share lastModified.
*
* @param \DateTime $lastModified value.
*
* @return void
*/
protected function setLastModified(\DateTime $lastModified)
{
$this->lastModified = $lastModified;
}
/**
* The entity tag for the share. If the request version is 2011-08-18 or
* newer, the ETag value will be in quotes.
*
* @return string
*/
public function getETag()
{
return $this->etag;
}
/**
* Sets share etag.
*
* @param string $etag value.
*
* @return void
*/
protected function setETag($etag)
{
$this->etag = $etag;
}
/**
* Gets user defined metadata.
*
* @return array
*/
public function getMetadata()
{
return $this->metadata;
}
/**
* Sets user defined metadata. This metadata should be added without the
* header prefix (x-ms-meta-*).
*
* @param array $metadata user defined metadata object in array form.
*
* @return void
*/
protected function setMetadata(array $metadata)
{
$this->metadata = $metadata;
}
/**
* Create an instance using the response headers from the API call.
*
* @param array $responseHeaders The array contains all the response headers
*
* @internal
*
* @return GetShareMetadataResult
*/
public static function createMetadataResult(array $responseHeaders)
{
$result = new static();
$metadata = Utilities::getMetadataArray($responseHeaders);
$date = Utilities::tryGetValueInsensitive(
Resources::LAST_MODIFIED,
$responseHeaders
);
$date = Utilities::rfc1123ToDateTime($date);
$result->setETag(Utilities::tryGetValueInsensitive(
Resources::ETAG,
$responseHeaders
));
$result->setMetadata($metadata);
$result->setLastModified($date);
return $result;
}
}
@@ -0,0 +1,132 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal\Middlewares;
use MicrosoftAzure\Storage\Common\Middlewares\MiddlewareBase;
use MicrosoftAzure\Storage\Common\Internal\Authentication\IAuthScheme;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use Psr\Http\Message\RequestInterface;
/**
* CommonRequestMiddleware is the middleware used to add the necessary headers
* and to sign the request with provided authentication scheme. This middleware
* is by default applied to each of the request.
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class CommonRequestMiddleware extends MiddlewareBase
{
private $authenticationScheme;
private $headers;
private $msVersion;
private $userAgent;
/**
* Creates CommonRequestMiddleware with the passed scheme and headers to
* be added.
*
* @param IAuthScheme $authenticationScheme The authentication scheme.
* @param string $storageAPIVersion Azure Storage Service API version,
* like '2016-05-31'.
* @param string $serviceSDKVersion Like '1.0.1' or '1.2.0'.
* @param array $headers The headers to be added.
*/
public function __construct(
IAuthScheme $authenticationScheme = null,
$storageAPIVersion,
$serviceSDKVersion,
array $headers = array()
) {
$this->authenticationScheme = $authenticationScheme;
$this->msVersion = $storageAPIVersion;
$this->userAgent = self::getUserAgent($serviceSDKVersion);
$this->headers = $headers;
}
/**
* Add the provided headers, the date, then sign the request using the
* authentication scheme, and return it.
*
* @param RequestInterface $request un-signed request.
*
* @return RequestInterface
*/
protected function onRequest(RequestInterface $request)
{
$result = $request;
//Adding headers.
foreach ($this->headers as $key => $value) {
$headers = $result->getHeaders();
if (!array_key_exists($key, $headers)) {
$result = $result->withHeader($key, $value);
}
}
//rewriting version and user-agent.
$result = $result->withHeader(
Resources::X_MS_VERSION,
$this->msVersion
);
$result = $result->withHeader(
Resources::USER_AGENT,
$this->userAgent
);
//Adding date.
$date = gmdate(Resources::AZURE_DATE_FORMAT, time());
$result = $result->withHeader(Resources::DATE, $date);
//Adding client request-ID if not specified by the user.
if (!$result->hasHeader(Resources::X_MS_CLIENT_REQUEST_ID)) {
$result = $result->withHeader(Resources::X_MS_CLIENT_REQUEST_ID, \uniqid());
}
//Sign the request if authentication scheme is not null.
$request = $this->authenticationScheme == null ?
$request : $this->authenticationScheme->signRequest($result);
return $request;
}
/**
* Gets the user agent string used in request header.
*
* @param $serviceSDKVersion
*
* @return string
*/
private static function getUserAgent($serviceSDKVersion)
{
// e.g. User-Agent: Azure-Storage/1.0.1-1.1.1 (PHP 5.5.32)/WINNT
return 'Azure-Storage/' . $serviceSDKVersion . '-' .
Resources::COMMON_SDK_VERSION .
' (PHP ' . PHP_VERSION . ')' . '/' . php_uname("s");
}
}
@@ -0,0 +1,422 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
/**
* Project resources.
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class Resources
{
// @codingStandardsIgnoreStart
// Connection strings
const USE_DEVELOPMENT_STORAGE_NAME = 'UseDevelopmentStorage';
const DEVELOPMENT_STORAGE_PROXY_URI_NAME = 'DevelopmentStorageProxyUri';
const DEFAULT_ENDPOINTS_PROTOCOL_NAME = 'DefaultEndpointsProtocol';
const ACCOUNT_NAME_NAME = 'AccountName';
const ACCOUNT_KEY_NAME = 'AccountKey';
const SAS_TOKEN_NAME = 'SharedAccessSignature';
const BLOB_ENDPOINT_NAME = 'BlobEndpoint';
const QUEUE_ENDPOINT_NAME = 'QueueEndpoint';
const TABLE_ENDPOINT_NAME = 'TableEndpoint';
const FILE_ENDPOINT_NAME = 'FileEndpoint';
const SHARED_ACCESS_SIGNATURE_NAME = 'SharedAccessSignature';
const ENDPOINT_SUFFIX_NAME = 'EndpointSuffix';
const DEFAULT_ENDPOINT_SUFFIX = 'core.windows.net';
const DEV_STORE_NAME = 'devstoreaccount1';
const DEV_STORE_KEY = 'Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==';
const BLOB_BASE_DNS_NAME = 'blob.core.windows.net';
const BLOB_DNS_PREFIX = 'blob.';
const QUEUE_BASE_DNS_NAME = 'queue.core.windows.net';
const QUEUE_DNS_PREFIX = 'queue.';
const TABLE_BASE_DNS_NAME = 'table.core.windows.net';
const TABLE_DNS_PREFIX = 'table.';
const FILE_BASE_DNS_NAME = 'file.core.windows.net';
const FILE_DNS_PREFIX = 'file.';
const DEV_STORE_CONNECTION_STRING = 'BlobEndpoint=127.0.0.1:10000;QueueEndpoint=127.0.0.1:10001;TableEndpoint=127.0.0.1:10002;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==';
const SUBSCRIPTION_ID_NAME = 'SubscriptionID';
const CERTIFICATE_PATH_NAME = 'CertificatePath';
const SECONDARY_STRING = '-secondary';
const PRIMARY_STRING = '-primary';
// Messages
const INVALID_FUNCTION_NAME = 'The class %s does not have a function named %s.';
const INVALID_TYPE_MSG = 'The provided variable should be of type: ';
const INVALID_META_MSG = 'Metadata cannot contain newline characters.';
const AZURE_ERROR_MSG = "Fail:\nCode: %s\nValue: %s\ndetails (if any): %s.";
const NOT_IMPLEMENTED_MSG = 'This method is not implemented.';
const NULL_OR_EMPTY_MSG = "'%s' can't be NULL or empty.";
const NULL_MSG = "'%s' can't be NULL.";
const INVALID_URL_MSG = 'Provided URL is invalid.';
const INVALID_HT_MSG = 'The header type provided is invalid.';
const INVALID_VERSION_MSG = 'Server does not support any known protocol versions.';
const INVALID_EXC_OBJ_MSG = 'Exception object type should be ServiceException.';
const INVALID_PARAM_MSG = "The provided variable '%s' should be of type '%s'";
const INVALID_VALUE_MSG = "The provided variable '%s' has unexpected value. Reason: '%s'";
const INVALID_STRING_LENGTH = "The provided variable '%s' should be of %s characters long";
const INVALID_SVC_PROP_MSG = 'The provided service properties is invalid.';
const UNKNOWN_SRILZER_MSG = 'The provided serializer type is unknown';
const INVALID_CREATE_SERVICE_OPTIONS_MSG = 'Must provide valid location or affinity group.';
const INVALID_UPDATE_SERVICE_OPTIONS_MSG = 'Must provide either description or label.';
const INVALID_CONFIG_MSG = 'Config object must be of type Configuration';
const INVALID_CONFIG_HOSTNAME = "The provided hostname '%s' is invalid.";
const INVALID_CONFIG_URI = "The provided URI '%s' is invalid. It has to pass the check 'filter_var(<user_uri>, FILTER_VALIDATE_URL)'.";
const INVALID_CONFIG_VALUE = "The provided config value '%s' does not belong to the valid values subset:\n%s";
const INVALID_ACCOUNT_KEY_FORMAT = "The provided account key '%s' is not a valid base64 string. It has to pass the check 'base64_decode(<user_account_key>, true)'.";
const MISSING_CONNECTION_STRING_SETTINGS = "The provided connection string '%s' does not have complete configuration settings.";
const INVALID_CONNECTION_STRING_SETTING_KEY = "The setting key '%s' is not found in the expected configuration setting keys:\n%s";
const INVALID_CERTIFICATE_PATH = "The provided certificate path '%s' is invalid.";
const INSTANCE_TYPE_VALIDATION_MSG = 'The type of %s is %s but is expected to be %s.';
const INVALID_MESSAGE_OBJECT_TO_SERIALIZE = 'The given object does not have required methods, so it could not be serialized.';
const MISSING_CONNECTION_STRING_CHAR = "Missing %s character";
const ERROR_PARSING_STRING = "'%s' at position %d.";
const INVALID_CONNECTION_STRING = "Argument '%s' is not a valid connection string: '%s'";
const ERROR_CONNECTION_STRING_MISSING_KEY = 'Missing key name';
const ERROR_CONNECTION_STRING_EMPTY_KEY = 'Empty key name';
const ERROR_CONNECTION_STRING_MISSING_CHARACTER = "Missing %s character";
const ERROR_EMPTY_SETTINGS = 'No keys were found in the connection string';
const MISSING_LOCK_LOCATION_MSG = 'The lock location of the brokered message is missing.';
const INVALID_SAS_TOKEN = 'The shared access signatures (SAS) provided is not valid \'%s\'';
const INVALID_SLOT = "The provided deployment slot '%s' is not valid. Only 'staging' and 'production' are accepted.";
const INVALID_DEPLOYMENT_LOCATOR_MSG = 'A slot or deployment name must be provided.';
const INVALID_CHANGE_MODE_MSG = "The change mode must be 'Auto' or 'Manual'. Use Mode class constants for that purpose.";
const INVALID_DEPLOYMENT_STATUS_MSG = "The change mode must be 'Running' or 'Suspended'. Use DeploymentStatus class constants for that purpose.";
const ERROR_OAUTH_GET_ACCESS_TOKEN = 'Unable to get oauth access token for endpoint \'%s\', account name \'%s\'';
const ERROR_OAUTH_SERVICE_MISSING = 'OAuth service missing for account name \'%s\'';
const ERROR_METHOD_NOT_FOUND = 'Method \'%s\' not found in object class \'%s\'';
const ERROR_INVALID_DATE_STRING = 'Parameter \'%s\' is not a date formatted string \'%s\'';
const ERROR_FILE_COULD_NOT_BE_OPENED = 'Error: file with given path could not be opened or created.';
const INVALID_PARAM_GENERAL = 'The provided parameter \'%s\' is invalid';
const INVALID_NEGATIVE_PARAM = 'The provided parameter \'%s\' should be positive number.';
const SIGNED_SERVICE_INVALID_VALIDATION_MSG = 'The signed service should only be a combination of the letters b(lob) q(ueue) t(able) or f(ile).';
const SIGNED_RESOURCE_TYPE_INVALID_VALIDATION_MSG = 'The signed resource type should only be a combination of the letters s(ervice) c(container) or o(bject).';
const STRING_NOT_WITH_GIVEN_COMBINATION = 'The string should only be a combination of the letters %s.';
const SIGNED_PROTOCOL_INVALID_VALIDATION_MSG = 'The signed protocol is invalid: possible values are https or https,http.';
const ERROR_RESOURCE_TYPE_NOT_SUPPORTED = 'The given resource type cannot be recognized or is not supported.';
const ERROR_TOO_MANY_SIGNED_IDENTIFIERS = 'There can be at most 5 signed identifiers at the same time.';
const INVALID_PERMISSION_PROVIDED = 'Invalid permission provided, the permission of resource type \'%s\' can only be of \'%s\'';
const INVALID_RESOURCE_TYPE = 'Provided resource type is invalid.';
const ERROR_KEY_NOT_EXIST = "The key '%s' does not exist in the given array.";
const RESOURCE_RANGE_LENGTH_MUST_SET = "The start and end/length of the range must be set.";
const INVALID_ACCEPT_CONTENT_TYPE = "The given accept content type is not valid.";
const ERROR_CANNOT_PARSE_XML = "Cannot parse XML, reasons: %s";
const INVALID_SCHEME = 'HTTP scheme can only be string \'http\' or \'https\'.';
const AAD_TOKEN_MUST_START_WITH_BEARER = 'AAD token is invalid, please make sure that it has format \'Bearer ################\'';
// HTTP Headers
const X_MS_HEADER_PREFIX = 'x-ms-';
const X_MS_META_HEADER_PREFIX = 'x-ms-meta-';
const X_MS_VERSION = 'x-ms-version';
const X_MS_DATE = 'x-ms-date';
const X_MS_COPY_ACTION = 'x-ms-copy-action';
const X_MS_COPY_ID = 'x-ms-copy-id';
const X_MS_COPY_COMPLETION_TIME = 'x-ms-copy-completion-time';
const X_MS_COPY_STATUS = 'x-ms-copy-status';
const X_MS_COPY_STATUS_DESCRIPTION = 'x-ms-copy-status-description';
const X_MS_COPY_SOURCE = 'x-ms-copy-source';
const X_MS_COPY_PROGRESS = 'x-ms-copy-progress';
const X_MS_RANGE = 'x-ms-range';
const X_MS_RANGE_GET_CONTENT_MD5 = 'x-ms-range-get-content-md5';
const X_MS_DELETE_SNAPSHOTS = 'x-ms-delete-snapshots';
const X_MS_SNAPSHOT = 'x-ms-snapshot';
const X_MS_SOURCE_IF_MODIFIED_SINCE = 'x-ms-source-if-modified-since';
const X_MS_SOURCE_IF_UNMODIFIED_SINCE = 'x-ms-source-if-unmodified-since';
const X_MS_SOURCE_IF_MATCH = 'x-ms-source-if-match';
const X_MS_SOURCE_IF_NONE_MATCH = 'x-ms-source-if-none-match';
const X_MS_SOURCE_LEASE_ID = 'x-ms-source-lease-id';
const X_MS_CONTINUATION_NEXTTABLENAME = 'x-ms-continuation-nexttablename';
const X_MS_CONTINUATION_NEXTPARTITIONKEY = 'x-ms-continuation-nextpartitionkey';
const X_MS_CONTINUATION_NEXTROWKEY = 'x-ms-continuation-nextrowkey';
const X_MS_REQUEST_ID = 'x-ms-request-id';
const X_MS_CLIENT_REQUEST_ID = 'x-ms-client-request-id';
const X_MS_CONTINUATION_LOCATION_MODE = 'x-ms-continuation-location-mode';
const X_MS_TYPE = 'x-ms-type';
const X_MS_CONTENT_LENGTH = 'x-ms-content-length';
const X_MS_CACHE_CONTROL = 'x-ms-cache-control';
const X_MS_CONTENT_TYPE = 'x-ms-content-type';
const X_MS_CONTENT_MD5 = 'x-ms-content-md5';
const X_MS_CONTENT_ENCODING = 'x-ms-content-encoding';
const X_MS_CONTENT_LANGUAGE = 'x-ms-content-language';
const X_MS_CONTENT_DISPOSITION = 'x-ms-content-disposition';
const X_MS_WRITE = 'x-ms-write';
const ETAG = 'etag';
const LAST_MODIFIED = 'last-modified';
const DATE = 'date';
const AUTHENTICATION = 'authorization';
const WRAP_AUTHORIZATION = 'WRAP access_token="%s"';
const CONTENT_ENCODING = 'content-encoding';
const CONTENT_LANGUAGE = 'content-language';
const CONTENT_LENGTH = 'content-length';
const CONTENT_LENGTH_NO_SPACE = 'contentlength';
const CONTENT_MD5 = 'content-md5';
const CONTENT_TYPE_LOWER_CASE = 'content-type';
const CONTENT_TYPE = 'Content-Type';
const CONTENT_ID = 'content-id';
const CONTENT_RANGE = 'content-range';
const CACHE_CONTROL = 'cache-control';
const CONTENT_DISPOSITION = 'content-disposition';
const IF_MODIFIED_SINCE = 'if-modified-since';
const IF_MATCH = 'if-match';
const IF_NONE_MATCH = 'if-none-match';
const IF_UNMODIFIED_SINCE = 'if-unmodified-since';
const RANGE = 'range';
const DATA_SERVICE_VERSION = 'dataserviceversion';
const MAX_DATA_SERVICE_VERSION = 'maxdataserviceversion';
const ACCEPT_HEADER = 'accept';
const ACCEPT_CHARSET = 'accept-charset';
const USER_AGENT = 'User-Agent';
const PREFER = 'Prefer';
// HTTP Methods
const HTTP_GET = 'GET';
const HTTP_PUT = 'PUT';
const HTTP_POST = 'POST';
const HTTP_HEAD = 'HEAD';
const HTTP_DELETE = 'DELETE';
const HTTP_MERGE = 'MERGE';
// Misc
const EMPTY_STRING = '';
const SEPARATOR = ',';
const AZURE_DATE_FORMAT = 'D, d M Y H:i:s T';
const TIMESTAMP_FORMAT = 'Y-m-d H:i:s';
const EMULATED = 'EMULATED';
const EMULATOR_BLOB_URI = '127.0.0.1:10000';
const EMULATOR_QUEUE_URI = '127.0.0.1:10001';
const EMULATOR_TABLE_URI = '127.0.0.1:10002';
const ASTERISK = '*';
const SERVICE_MANAGEMENT_URL = 'https://management.core.windows.net';
const HTTP_SCHEME = 'http';
const HTTPS_SCHEME = 'https';
const SETTING_NAME = 'SettingName';
const SETTING_CONSTRAINT = 'SettingConstraint';
const DEV_STORE_URI = 'http://127.0.0.1';
const SERVICE_URI_FORMAT = "%s://%s.%s";
const WRAP_ENDPOINT_URI_FORMAT = "https://%s-sb.accesscontrol.windows.net/WRAPv0.9";
const MB_IN_BYTES_1 = 1048576;
const MB_IN_BYTES_4 = 4194304;
const MB_IN_BYTES_32 = 33554432;
const MB_IN_BYTES_64 = 67108864;
const MB_IN_BYTES_128 = 134217728;
const MB_IN_BYTES_256 = 268435456;
const MB_IN_BYTES_100 = 104857600;
const GB_IN_BYTES = 1073741824;
const GB_IN_BYTES_200 = 214748364800;
const MAX_BLOB_BLOCKS = 50000;
const MAX_BLOCK_BLOB_SIZE = 5242880000000;
const RETURN_CONTENT = 'return-content';
const NUMBER_OF_CONCURRENCY = 25;//Guzzle's default value
const DEFAULT_NUMBER_OF_RETRIES = 3;
const DEFAULT_RETRY_INTERVAL = 1000;//Milliseconds
const BEARER = 'Bearer ';
// Header values
const COMMON_SDK_VERSION = '1.5.2';
const INT32_MAX = 2147483647;
const INT32_MIN = -2147483648;
// Query parameter names
const QP_ENTRIES = 'Entries';
const QP_PREFIX = 'Prefix';
const QP_PREFIX_LOWERCASE = 'prefix';
const QP_MAX_RESULTS = 'MaxResults';
const QP_MAX_RESULTS_LOWERCASE = 'maxresults';
const QP_MARKER = 'Marker';
const QP_MARKER_LOWERCASE = 'marker';
const QP_METADATA = 'Metadata';
const QP_NEXT_MARKER = 'NextMarker';
const QP_COMP = 'comp';
const QP_INCLUDE = 'include';
const QP_TIMEOUT = 'timeout';
const QP_REST_TYPE = 'restype';
const QP_SNAPSHOT = 'snapshot';
const QP_COPY_ID = 'copyid';
const QP_NAME = 'Name';
const QP_PROPERTIES = 'Properties';
const QP_LAST_MODIFIED = 'Last-Modified';
const QP_ETAG = 'Etag';
const QP_QUOTA = 'Quota';
const QP_CONTENT_LENGTH = 'Content-Length';
// Request body content types
const URL_ENCODED_CONTENT_TYPE = 'application/x-www-form-urlencoded';
const BINARY_FILE_TYPE = 'application/octet-stream';
const HTTP_TYPE = 'application/http';
const MULTIPART_MIXED_TYPE = 'multipart/mixed';
// Common used XML tags
const XTAG_ATTRIBUTES = '@attributes';
const XTAG_NAMESPACE = '@namespace';
const XTAG_LABEL = 'Label';
const XTAG_NAME = 'Name';
const XTAG_DESCRIPTION = 'Description';
const XTAG_LOCATION = 'Location';
const XTAG_AFFINITY_GROUP = 'AffinityGroup';
const XTAG_HOSTED_SERVICES = 'HostedServices';
const XTAG_STORAGE_SERVICES = 'StorageServices';
const XTAG_STORAGE_SERVICE = 'StorageService';
const XTAG_DISPLAY_NAME = 'DisplayName';
const XTAG_SERVICE_NAME = 'ServiceName';
const XTAG_URL = 'Url';
const XTAG_ID = 'ID';
const XTAG_STATUS = 'Status';
const XTAG_HTTP_STATUS_CODE = 'HttpStatusCode';
const XTAG_CODE = 'Code';
const XTAG_MESSAGE = 'Message';
const XTAG_STORAGE_SERVICE_PROPERTIES = 'StorageServiceProperties';
const XTAG_SERVICE_ENDPOINT = 'ServiceEndpoint';
const XTAG_ENDPOINT = 'Endpoint';
const XTAG_ENDPOINTS = 'Endpoints';
const XTAG_PRIMARY = 'Primary';
const XTAG_SECONDARY = 'Secondary';
const XTAG_KEY_TYPE = 'KeyType';
const XTAG_STORAGE_SERVICE_KEYS = 'StorageServiceKeys';
const XTAG_ERROR = 'Error';
const XTAG_HOSTED_SERVICE = 'HostedService';
const XTAG_HOSTED_SERVICE_PROPERTIES = 'HostedServiceProperties';
const XTAG_CREATE_HOSTED_SERVICE = 'CreateHostedService';
const XTAG_CREATE_STORAGE_SERVICE_INPUT = 'CreateStorageServiceInput';
const XTAG_UPDATE_STORAGE_SERVICE_INPUT = 'UpdateStorageServiceInput';
const XTAG_CREATE_AFFINITY_GROUP = 'CreateAffinityGroup';
const XTAG_UPDATE_AFFINITY_GROUP = 'UpdateAffinityGroup';
const XTAG_UPDATE_HOSTED_SERVICE = 'UpdateHostedService';
const XTAG_PACKAGE_URL = 'PackageUrl';
const XTAG_CONFIGURATION = 'Configuration';
const XTAG_START_DEPLOYMENT = 'StartDeployment';
const XTAG_TREAT_WARNINGS_AS_ERROR = 'TreatWarningsAsError';
const XTAG_CREATE_DEPLOYMENT = 'CreateDeployment';
const XTAG_DEPLOYMENT_SLOT = 'DeploymentSlot';
const XTAG_PRIVATE_ID = 'PrivateID';
const XTAG_ROLE_INSTANCE_LIST = 'RoleInstanceList';
const XTAG_UPGRADE_DOMAIN_COUNT = 'UpgradeDomainCount';
const XTAG_ROLE_LIST = 'RoleList';
const XTAG_SDK_VERSION = 'SdkVersion';
const XTAG_INPUT_ENDPOINT_LIST = 'InputEndpointList';
const XTAG_LOCKED = 'Locked';
const XTAG_ROLLBACK_ALLOWED = 'RollbackAllowed';
const XTAG_UPGRADE_STATUS = 'UpgradeStatus';
const XTAG_UPGRADE_TYPE = 'UpgradeType';
const XTAG_CURRENT_UPGRADE_DOMAIN_STATE = 'CurrentUpgradeDomainState';
const XTAG_CURRENT_UPGRADE_DOMAIN = 'CurrentUpgradeDomain';
const XTAG_ROLE_NAME = 'RoleName';
const XTAG_INSTANCE_NAME = 'InstanceName';
const XTAG_INSTANCE_STATUS = 'InstanceStatus';
const XTAG_INSTANCE_UPGRADE_DOMAIN = 'InstanceUpgradeDomain';
const XTAG_INSTANCE_FAULT_DOMAIN = 'InstanceFaultDomain';
const XTAG_INSTANCE_SIZE = 'InstanceSize';
const XTAG_INSTANCE_STATE_DETAILS = 'InstanceStateDetails';
const XTAG_INSTANCE_ERROR_CODE = 'InstanceErrorCode';
const XTAG_OS_VERSION = 'OsVersion';
const XTAG_ROLE_INSTANCE = 'RoleInstance';
const XTAG_ROLE = 'Role';
const XTAG_INPUT_ENDPOINT = 'InputEndpoint';
const XTAG_VIP = 'Vip';
const XTAG_PORT = 'Port';
const XTAG_DEPLOYMENT = 'Deployment';
const XTAG_DEPLOYMENTS = 'Deployments';
const XTAG_REGENERATE_KEYS = 'RegenerateKeys';
const XTAG_SWAP = 'Swap';
const XTAG_PRODUCTION = 'Production';
const XTAG_SOURCE_DEPLOYMENT = 'SourceDeployment';
const XTAG_CHANGE_CONFIGURATION = 'ChangeConfiguration';
const XTAG_MODE = 'Mode';
const XTAG_UPDATE_DEPLOYMENT_STATUS = 'UpdateDeploymentStatus';
const XTAG_ROLE_TO_UPGRADE = 'RoleToUpgrade';
const XTAG_FORCE = 'Force';
const XTAG_UPGRADE_DEPLOYMENT = 'UpgradeDeployment';
const XTAG_UPGRADE_DOMAIN = 'UpgradeDomain';
const XTAG_WALK_UPGRADE_DOMAIN = 'WalkUpgradeDomain';
const XTAG_ROLLBACK_UPDATE_OR_UPGRADE = 'RollbackUpdateOrUpgrade';
const XTAG_CONTAINER_NAME = 'ContainerName';
const XTAG_ACCOUNT_NAME = 'AccountName';
const XTAG_LOGGING = 'Logging';
const XTAG_HOUR_METRICS = 'HourMetrics';
const XTAG_MINUTE_METRICS = 'MinuteMetrics';
const XTAG_CORS = 'Cors';
const XTAG_CORS_RULE = 'CorsRule';
const XTAG_ALLOWED_ORIGINS = 'AllowedOrigins';
const XTAG_ALLOWED_METHODS = 'AllowedMethods';
const XTAG_ALLOWED_HEADERS = 'AllowedHeaders';
const XTAG_EXPOSED_HEADERS = 'ExposedHeaders';
const XTAG_MAX_AGE_IN_SECONDS = 'MaxAgeInSeconds';
const XTAG_SIGNED_IDENTIFIERS = 'SignedIdentifiers';
const XTAG_SIGNED_IDENTIFIER = 'SignedIdentifier';
const XTAG_ACCESS_POLICY = 'AccessPolicy';
const XTAG_SIGNED_START = 'Start';
const XTAG_SIGNED_EXPIRY = 'Expiry';
const XTAG_SIGNED_PERMISSION = 'Permission';
const XTAG_SIGNED_ID = 'Id';
const XTAG_DEFAULT_SERVICE_VERSION = 'DefaultServiceVersion';
const XTAG_GEO_REPLICATION = 'GeoReplication';
const XTAG_LAST_SYNC_TIME = 'LastSyncTime';
const XTAG_PAGE_RANGE = 'PageRange';
const XTAG_CLEAR_RANGE = 'ClearRange';
const XTAG_RANGE_START = 'Start';
const XTAG_RANGE_END = 'End';
// PHP URL Keys
const PHP_URL_SCHEME = 'scheme';
const PHP_URL_HOST = 'host';
const PHP_URL_PORT = 'port';
const PHP_URL_USER = 'user';
const PHP_URL_PASS = 'pass';
const PHP_URL_PATH = 'path';
const PHP_URL_QUERY = 'query';
const PHP_URL_FRAGMENT = 'fragment';
// Status Codes
const STATUS_OK = 200;
const STATUS_CREATED = 201;
const STATUS_ACCEPTED = 202;
const STATUS_NO_CONTENT = 204;
const STATUS_PARTIAL_CONTENT = 206;
const STATUS_MOVED_PERMANENTLY = 301;
// Resource Types
const RESOURCE_TYPE_BLOB = 'b';
const RESOURCE_TYPE_CONTAINER = 'c';
const RESOURCE_TYPE_QUEUE = 'q';
const RESOURCE_TYPE_TABLE = 't';
const RESOURCE_TYPE_SHARE = 's';
const RESOURCE_TYPE_FILE = 'f';
// Request Options String
const ROS_LOCATION_MODE = 'location_mode';
const ROS_SECONDARY_URI = 'secondary_uri';
const ROS_PRIMARY_URI = 'primary_uri';
const ROS_DECODE_CONTENT = 'decode_content';
const ROS_STREAM = 'stream';
const ROS_HANDLER = 'requestHandler';
// @codingStandardsIgnoreEnd
}
@@ -0,0 +1,131 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
use MicrosoftAzure\Storage\Common\Internal\IMiddleware;
/**
* Base class for all REST proxies.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class RestProxy
{
/**
* @var array
*/
private $middlewares;
/**
* @var Serialization\ISerializer
*/
protected $dataSerializer;
/**
* Initializes new RestProxy object.
*
* @param Serialization\ISerializer $dataSerializer The data serializer.
*/
public function __construct(Serialization\ISerializer $dataSerializer = null)
{
$this->middlewares = array();
$this->dataSerializer = $dataSerializer;
//For logging the request and responses.
// $this->middlewares[] = new HistoryMiddleware('.\\messages.log');
}
/**
* Gets middlewares that will be handling the request and response.
*
* @return array
*/
public function getMiddlewares()
{
return $this->middlewares;
}
/**
* Push a new middleware into the middlewares array. The newly added
* middleware will be the most inner middleware when executed.
*
* @param callable|IMiddleware $middleware the middleware to be added.
*
* @return void
*/
public function pushMiddleware($middleware)
{
$this->middlewares[] = $middleware;
}
/**
* Adds optional query parameter.
*
* Doesn't add the value if it satisfies empty().
*
* @param array &$queryParameters The query parameters.
* @param string $key The query variable name.
* @param string $value The query variable value.
*
* @return void
*/
protected function addOptionalQueryParam(array &$queryParameters, $key, $value)
{
Validate::isArray($queryParameters, 'queryParameters');
Validate::canCastAsString($key, 'key');
Validate::canCastAsString($value, 'value');
if (!is_null($value) && Resources::EMPTY_STRING !== $value) {
$queryParameters[$key] = $value;
}
}
/**
* Adds optional header.
*
* Doesn't add the value if it satisfies empty().
*
* @param array &$headers The HTTP header parameters.
* @param string $key The HTTP header name.
* @param string $value The HTTP header value.
*
* @return void
*/
protected function addOptionalHeader(array &$headers, $key, $value)
{
Validate::isArray($headers, 'headers');
Validate::canCastAsString($key, 'key');
Validate::canCastAsString($value, 'value');
if (!is_null($value) && Resources::EMPTY_STRING !== $value) {
$headers[$key] = $value;
}
}
}
@@ -0,0 +1,70 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Serialization
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal\Serialization;
/**
* The serialization interface.
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Serialization
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
interface ISerializer
{
/**
* Serialize an object into a XML.
*
* @param Object $targetObject The target object to be serialized.
* @param string $rootName The name of the root.
*
* @return string
*/
public static function objectSerialize($targetObject, $rootName);
/**
* Serializes given array. The array indices must be string to use them as
* as element name.
*
* @param array $array The object to serialize represented in array.
* @param array $properties The used properties in the serialization process.
*
* @return string
*/
public function serialize(array $array, array $properties = null);
/**
* Unserializes given serialized string.
*
* @param string $serialized The serialized object in string representation.
*
* @return array
*/
public function unserialize($serialized);
}
@@ -0,0 +1,96 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Serialization
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal\Serialization;
use MicrosoftAzure\Storage\Common\Internal\Validate;
/**
* Perform JSON serialization / deserialization
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Serialization
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class JsonSerializer implements ISerializer
{
/**
* Serialize an object with specified root element name.
*
* @param object $targetObject The target object.
* @param string $rootName The name of the root element.
*
* @return string
*/
public static function objectSerialize($targetObject, $rootName)
{
Validate::notNull($targetObject, 'targetObject');
Validate::canCastAsString($rootName, 'rootName');
$contianer = new \stdClass();
$contianer->$rootName = $targetObject;
return json_encode($contianer);
}
/**
* Serializes given array. The array indices must be string to use them as
* as element name.
*
* @param array $array The object to serialize represented in array.
* @param array $properties The used properties in the serialization process.
*
* @return string
*/
public function serialize(array $array = null, array $properties = null)
{
Validate::isArray($array, 'array');
return json_encode($array);
}
/**
* Unserializes given serialized string to array.
*
* @param string $serialized The serialized object in string representation.
*
* @return array
*/
public function unserialize($serialized)
{
Validate::canCastAsString($serialized, 'serialized');
$json = json_decode($serialized);
if ($json && !is_array($json)) {
return get_object_vars($json);
} else {
return $json;
}
}
}
@@ -0,0 +1,178 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Serialization
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal\Serialization;
use MicrosoftAzure\Storage\Common\Internal\Validate;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use GuzzleHttp\Exception\RequestException;
/**
* Provides functionality to serialize a message to a string.
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Serialization
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class MessageSerializer
{
/**
* Serialize a message to a string. The message object must be either a type
* of \Exception, or have following methods implemented.
* getHeaders()
* getProtocolVersion()
* (getUri() && getMethod()) || (getStatusCode() && getReasonPhrase())
*
* @param object $message The message to be serialized.
*
* @return string
*/
public static function objectSerialize($targetObject)
{
//if the object is of exception type, serialize it using the methods
//without checking the methods.
if ($targetObject instanceof RequestException) {
return self::serializeRequestException($targetObject);
} elseif ($targetObject instanceof \Exception) {
return self::serializeException($targetObject);
}
Validate::methodExists($targetObject, 'getHeaders', 'targetObject');
Validate::methodExists($targetObject, 'getProtocolVersion', 'targetObject');
// Serialize according to the implemented method.
if (method_exists($targetObject, 'getUri') &&
method_exists($targetObject, 'getMethod')) {
return self::serializeRequest($targetObject);
} elseif (method_exists($targetObject, 'getStatusCode') &&
method_exists($targetObject, 'getReasonPhrase')) {
return self::serializeResponse($targetObject);
} else {
throw new \InvalidArgumentException(
Resources::INVALID_MESSAGE_OBJECT_TO_SERIALIZE
);
}
}
/**
* Serialize the request type that implemented the following methods:
* getHeaders()
* getProtocolVersion()
* getUri()
* getMethod()
*
* @param object $request The request to be serialized.
*
* @return string
*/
private static function serializeRequest($request)
{
$headers = $request->getHeaders();
$version = $request->getProtocolVersion();
$uri = $request->getUri();
$method = $request->getMethod();
$resultString = "Request:\n";
$resultString .= "URI: {$uri}\nHTTP Version: {$version}\nMethod: {$method}\n";
$resultString .= self::serializeHeaders($headers);
return $resultString;
}
/**
* Serialize the response type that implemented the following methods:
* getHeaders()
* getProtocolVersion()
* getStatusCode()
* getReasonPhrase()
*
* @param object $response The response to be serialized
*
* @return string
*/
private static function serializeResponse($response)
{
$headers = $response->getHeaders();
$version = $response->getProtocolVersion();
$status = $response->getStatusCode();
$reason = $response->getReasonPhrase();
$resultString = "Response:\n";
$resultString .= "Status Code: {$status}\nReason: {$reason}\n";
$resultString .= "HTTP Version: {$version}\n";
$resultString .= self::serializeHeaders($headers);
return $resultString;
}
/**
* Serialize the message headers.
*
* @param array $headers The headers to be serialized.
*
* @return string
*/
private static function serializeHeaders(array $headers)
{
$resultString = "Headers:\n";
foreach ($headers as $key => $value) {
$resultString .= sprintf("%s: %s\n", $key, $value[0]);
}
return $resultString;
}
/**
* Serialize the request exception.
*
* @param RequestException $e the request exception to be serialized.
*
* @return string
*/
private static function serializeRequestException(RequestException $e)
{
$resultString = sprintf("Reason:\n%s\n", $e);
if ($e->hasResponse()) {
$resultString .= self::serializeResponse($e->getResponse());
}
return $resultString;
}
/**
* Serialize the general exception
*
* @param \Exception $e general exception to be serialized.
*
* @return string
*/
private static function serializeException(\Exception $e)
{
return sprintf("Reason:\n%s\n", $e);
}
}
@@ -0,0 +1,245 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Serialization
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal\Serialization;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Validate;
/**
* Short description
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Serialization
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class XmlSerializer implements ISerializer
{
const STANDALONE = 'standalone';
const ROOT_NAME = 'rootName';
const DEFAULT_TAG = 'defaultTag';
/**
* Converts a SimpleXML object to an Array recursively
* ensuring all sub-elements are arrays as well.
*
* @param string $sxml The SimpleXML object.
* @param array $arr The array into which to store results.
*
* @return array
*/
private function sxml2arr($sxml, array $arr = null)
{
foreach ((array) $sxml as $key => $value) {
if (is_object($value) || (is_array($value))) {
$arr[$key] = $this->sxml2arr($value);
} else {
$arr[$key] = $value;
}
}
return $arr;
}
/**
* Takes an array and produces XML based on it.
*
* @param XMLWriter $xmlw XMLWriter object that was previously instanted
* and is used for creating the XML.
* @param array $data Array to be converted to XML.
* @param string $defaultTag Default XML tag to be used if none specified.
*
* @return void
*/
private function arr2xml(\XMLWriter $xmlw, array $data, $defaultTag = null)
{
foreach ($data as $key => $value) {
if ($key === Resources::XTAG_ATTRIBUTES) {
foreach ($value as $attributeName => $attributeValue) {
$xmlw->writeAttribute($attributeName, $attributeValue);
}
} elseif (is_array($value)) {
if (!is_int($key)) {
if ($key != Resources::EMPTY_STRING) {
$xmlw->startElement($key);
} else {
$xmlw->startElement($defaultTag);
}
}
$this->arr2xml($xmlw, $value);
if (!is_int($key)) {
$xmlw->endElement();
}
} else {
$xmlw->writeElement($key, $value);
}
}
}
/**
* Gets the attributes of a specified object if get attributes
* method is exposed.
*
* @param object $targetObject The target object.
* @param array $methodArray The array of method of the target object.
*
* @return mixed
*/
private static function getInstanceAttributes($targetObject, array $methodArray)
{
foreach ($methodArray as $method) {
if ($method->name == 'getAttributes') {
$classProperty = $method->invoke($targetObject);
return $classProperty;
}
}
return null;
}
/**
* Serialize an object with specified root element name.
*
* @param object $targetObject The target object.
* @param string $rootName The name of the root element.
*
* @return string
*/
public static function objectSerialize($targetObject, $rootName)
{
Validate::notNull($targetObject, 'targetObject');
Validate::canCastAsString($rootName, 'rootName');
$xmlWriter = new \XmlWriter();
$xmlWriter->openMemory();
$xmlWriter->setIndent(true);
$reflectionClass = new \ReflectionClass($targetObject);
$methodArray = $reflectionClass->getMethods();
$attributes = self::getInstanceAttributes(
$targetObject,
$methodArray
);
$xmlWriter->startElement($rootName);
if (!is_null($attributes)) {
foreach (array_keys($attributes) as $attributeKey) {
$xmlWriter->writeAttribute(
$attributeKey,
$attributes[$attributeKey]
);
}
}
foreach ($methodArray as $method) {
if ((strpos($method->name, 'get') === 0)
&& $method->isPublic()
&& ($method->name != 'getAttributes')
) {
$variableName = substr($method->name, 3);
$variableValue = $method->invoke($targetObject);
if (!empty($variableValue)) {
if (gettype($variableValue) === 'object') {
$xmlWriter->writeRaw(
XmlSerializer::objectSerialize(
$variableValue,
$variableName
)
);
} else {
$xmlWriter->writeElement($variableName, $variableValue);
}
}
}
}
$xmlWriter->endElement();
return $xmlWriter->outputMemory(true);
}
/**
* Serializes given array. The array indices must be string to use them as
* as element name.
*
* @param array $array The object to serialize represented in array.
* @param array $properties The used properties in the serialization process.
*
* @return string
*/
public function serialize(array $array, array $properties = null)
{
$xmlVersion = '1.0';
$xmlEncoding = 'UTF-8';
$standalone = Utilities::tryGetValue($properties, self::STANDALONE);
$defaultTag = Utilities::tryGetValue($properties, self::DEFAULT_TAG);
$rootName = Utilities::tryGetValue($properties, self::ROOT_NAME);
$docNamespace = Utilities::tryGetValue(
$array,
Resources::XTAG_NAMESPACE,
null
);
if (!is_array($array)) {
return false;
}
$xmlw = new \XmlWriter();
$xmlw->openMemory();
$xmlw->setIndent(true);
$xmlw->startDocument($xmlVersion, $xmlEncoding, $standalone);
if (is_null($docNamespace)) {
$xmlw->startElement($rootName);
} else {
foreach ($docNamespace as $uri => $prefix) {
$xmlw->startElementNS($prefix, $rootName, $uri);
break;
}
}
unset($array[Resources::XTAG_NAMESPACE]);
self::arr2xml($xmlw, $array, $defaultTag);
$xmlw->endElement();
return $xmlw->outputMemory(true);
}
/**
* Unserializes given serialized string.
*
* @param string $serialized The serialized object in string representation.
*
* @return array
*/
public function unserialize($serialized)
{
$sxml = new \SimpleXMLElement($serialized);
return $this->sxml2arr($sxml);
}
}
@@ -0,0 +1,658 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;
use MicrosoftAzure\Storage\Common\Internal\RetryMiddlewareFactory;
use MicrosoftAzure\Storage\Common\Internal\Serialization\XmlSerializer;
use MicrosoftAzure\Storage\Common\Models\ServiceOptions;
use MicrosoftAzure\Storage\Common\Internal\Http\HttpCallContext;
use MicrosoftAzure\Storage\Common\Internal\Middlewares\MiddlewareBase;
use MicrosoftAzure\Storage\Common\Middlewares\MiddlewareStack;
use MicrosoftAzure\Storage\Common\LocationMode;
use GuzzleHttp\Promise\EachPromise;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7;
use Psr\Http\Message\ResponseInterface;
/**
* Base class for all services rest proxies.
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class ServiceRestProxy extends RestProxy
{
private $accountName;
private $psrPrimaryUri;
private $psrSecondaryUri;
private $options;
private $client;
/**
* Initializes new ServiceRestProxy object.
*
* @param string $primaryUri The storage account
* primary uri.
* @param string $secondaryUri The storage account
* secondary uri.
* @param string $accountName The name of the account.
* @param array $options Array of options for
* the service
*/
public function __construct(
$primaryUri,
$secondaryUri,
$accountName,
array $options = []
) {
$primaryUri = Utilities::appendDelimiter($primaryUri, '/');
$secondaryUri = Utilities::appendDelimiter($secondaryUri, '/');
$dataSerializer = new XmlSerializer();
parent::__construct($dataSerializer);
$this->accountName = $accountName;
$this->psrPrimaryUri = new Uri($primaryUri);
$this->psrSecondaryUri = new Uri($secondaryUri);
$this->options = array_merge(array('http' => array()), $options);
$this->client = self::createClient($this->options['http']);
}
/**
* Create a Guzzle client for future usage.
*
* @param array $options Optional parameters for the client.
*
* @return Client
*/
private static function createClient(array $options)
{
$verify = true;
//Disable SSL if proxy has been set, and set the proxy in the client.
$proxy = getenv('HTTP_PROXY');
// For testing with Fiddler
// $proxy = 'localhost:8888';
// $verify = false;
if (!empty($proxy)) {
$options['proxy'] = $proxy;
}
if (isset($options['verify'])) {
$verify = $options['verify'];
}
return (new \GuzzleHttp\Client(
array_merge(
$options,
array(
"defaults" => array(
"allow_redirects" => true,
"exceptions" => true,
"decode_content" => true,
"config" => [
"curl" => [
CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2
]
]
),
'cookies' => true,
'verify' => $verify,
)
)
));
}
/**
* Gets the account name.
*
* @return string
*/
public function getAccountName()
{
return $this->accountName;
}
/**
* Create a middleware stack with given middleware.
*
* @param ServiceOptions $serviceOptions The options user passed in.
*
* @return MiddlewareStack
*/
protected function createMiddlewareStack(ServiceOptions $serviceOptions)
{
//If handler stack is not defined by the user, create a default
//middleware stack.
$stack = null;
if (array_key_exists('stack', $this->options['http'])) {
$stack = $this->options['http']['stack'];
} elseif ($serviceOptions->getMiddlewareStack() != null) {
$stack = $serviceOptions->getMiddlewareStack();
} else {
$stack = new MiddlewareStack();
}
//Push all the middlewares specified in the $serviceOptions to the
//handlerstack.
if ($serviceOptions->getMiddlewares() != array()) {
foreach ($serviceOptions->getMiddlewares() as $middleware) {
$stack->push($middleware);
}
}
//Push all the middlewares specified in the $options to the
//handlerstack.
if (array_key_exists('middlewares', $this->options)) {
foreach ($this->options['middlewares'] as $middleware) {
$stack->push($middleware);
}
}
//Push all the middlewares specified in $this->middlewares to the
//handlerstack.
foreach ($this->getMiddlewares() as $middleware) {
$stack->push($middleware);
}
return $stack;
}
/**
* Send the requests concurrently. Number of concurrency can be modified
* by inserting a new key/value pair with the key 'number_of_concurrency'
* into the $requestOptions of $serviceOptions. Return only the promise.
*
* @param callable $generator the generator function to generate
* request upon fulfillment
* @param int $statusCode The expected status code for each of the
* request generated by generator.
* @param ServiceOptions $options The service options for the concurrent
* requests.
*
* @return \GuzzleHttp\Promise\Promise|\GuzzleHttp\Promise\PromiseInterface
*/
protected function sendConcurrentAsync(
callable $generator,
$statusCode,
ServiceOptions $options
) {
$client = $this->client;
$middlewareStack = $this->createMiddlewareStack($options);
$sendAsync = function ($request, $options) use ($client) {
if ($request->getMethod() == 'HEAD') {
$options['decode_content'] = false;
}
return $client->sendAsync($request, $options);
};
$handler = $middlewareStack->apply($sendAsync);
$requestOptions = $this->generateRequestOptions($options, $handler);
$promises = \call_user_func(
function () use (
$generator,
$handler,
$requestOptions
) {
while (is_callable($generator) && ($request = $generator())) {
yield \call_user_func($handler, $request, $requestOptions);
}
}
);
$eachPromise = new EachPromise($promises, [
'concurrency' => $options->getNumberOfConcurrency(),
'fulfilled' => function ($response, $index) use ($statusCode) {
//the promise is fulfilled, evaluate the response
self::throwIfError(
$response,
$statusCode
);
},
'rejected' => function ($reason, $index) {
//Still rejected even if the retry logic has been applied.
//Throwing exception.
throw $reason;
}
]);
return $eachPromise->promise();
}
/**
* Create the request to be sent.
*
* @param string $method The method of the HTTP request
* @param array $headers The header field of the request
* @param array $queryParams The query parameter of the request
* @param array $postParameters The HTTP POST parameters
* @param string $path URL path
* @param string $body Request body
*
* @return \GuzzleHttp\Psr7\Request
*/
protected function createRequest(
$method,
array $headers,
array $queryParams,
array $postParameters,
$path,
$locationMode,
$body = Resources::EMPTY_STRING
) {
if ($locationMode == LocationMode::SECONDARY_ONLY ||
$locationMode == LocationMode::SECONDARY_THEN_PRIMARY) {
$uri = $this->psrSecondaryUri;
} else {
$uri = $this->psrPrimaryUri;
}
//Append the path, not replacing it.
if ($path != null) {
$exPath = $uri->getPath();
if ($exPath != '') {
//Remove the duplicated slash in the path.
if ($path != '' && $path[0] == '/') {
$path = $exPath . substr($path, 1);
} else {
$path = $exPath . $path;
}
}
$uri = $uri->withPath($path);
}
// add query parameters into headers
if ($queryParams != null) {
$queryString = Psr7\Query::build($queryParams);
$uri = $uri->withQuery($queryString);
}
// add post parameters into bodies
$actualBody = null;
if (empty($body)) {
if (empty($headers[Resources::CONTENT_TYPE])) {
$headers[Resources::CONTENT_TYPE] = Resources::URL_ENCODED_CONTENT_TYPE;
$actualBody = Psr7\Query::build($postParameters);
}
} else {
$actualBody = $body;
}
$request = new Request(
$method,
$uri,
$headers,
$actualBody
);
//add content-length to header
$bodySize = $request->getBody()->getSize();
if ($bodySize > 0) {
$request = $request->withHeader('content-length', $bodySize);
}
return $request;
}
/**
* Create promise of sending HTTP request with the specified parameters.
*
* @param string $method HTTP method used in the request
* @param array $headers HTTP headers.
* @param array $queryParams URL query parameters.
* @param array $postParameters The HTTP POST parameters.
* @param string $path URL path
* @param array|int $expected Expected Status Codes.
* @param string $body Request body
* @param ServiceOptions $serviceOptions Service options
*
* @return \GuzzleHttp\Promise\PromiseInterface
*/
protected function sendAsync(
$method,
array $headers,
array $queryParams,
array $postParameters,
$path,
$expected = Resources::STATUS_OK,
$body = Resources::EMPTY_STRING,
ServiceOptions $serviceOptions = null
) {
if ($serviceOptions == null) {
$serviceOptions = new ServiceOptions();
}
$this->addOptionalQueryParam(
$queryParams,
Resources::QP_TIMEOUT,
$serviceOptions->getTimeout()
);
$request = $this->createRequest(
$method,
$headers,
$queryParams,
$postParameters,
$path,
$serviceOptions->getLocationMode(),
$body
);
$client = $this->client;
$middlewareStack = $this->createMiddlewareStack($serviceOptions);
$sendAsync = function ($request, $options) use ($client) {
return $client->sendAsync($request, $options);
};
$handler = $middlewareStack->apply($sendAsync);
$requestOptions =
$this->generateRequestOptions($serviceOptions, $handler);
if ($request->getMethod() == 'HEAD') {
$requestOptions[Resources::ROS_DECODE_CONTENT] = false;
}
$promise = \call_user_func($handler, $request, $requestOptions);
return $promise->then(
function ($response) use ($expected, $requestOptions) {
self::throwIfError(
$response,
$expected
);
return self::addLocationHeaderToResponse(
$response,
$requestOptions[Resources::ROS_LOCATION_MODE]
);
},
function ($reason) use ($expected) {
return $this->onRejected($reason, $expected);
}
);
}
/**
* @param string|\Exception $reason Rejection reason.
* @param array|int $expected Expected Status Codes.
*
* @return ResponseInterface
*/
protected function onRejected($reason, $expected)
{
if (!($reason instanceof \Exception)) {
throw new \RuntimeException($reason);
}
if (!($reason instanceof RequestException)) {
throw $reason;
}
$response = $reason->getResponse();
if ($response != null) {
self::throwIfError(
$response,
$expected
);
} else {
//if could not get response but promise rejected, throw reason.
throw $reason;
}
return $response;
}
/**
* Generate the request options using the given service options and stored
* information.
*
* @param ServiceOptions $serviceOptions The service options used to
* generate request options.
* @param callable $handler The handler used to send the
* request.
* @return array
*/
protected function generateRequestOptions(
ServiceOptions $serviceOptions,
callable $handler
) {
$result = array();
$result[Resources::ROS_LOCATION_MODE] = $serviceOptions->getLocationMode();
$result[Resources::ROS_STREAM] = $serviceOptions->getIsStreaming();
$result[Resources::ROS_DECODE_CONTENT] = $serviceOptions->getDecodeContent();
$result[Resources::ROS_HANDLER] = $handler;
$result[Resources::ROS_SECONDARY_URI] = $this->getPsrSecondaryUri();
$result[Resources::ROS_PRIMARY_URI] = $this->getPsrPrimaryUri();
return $result;
}
/**
* Sends the context.
*
* @param HttpCallContext $context The context of the request.
* @return \GuzzleHttp\Psr7\Response
*/
protected function sendContext(HttpCallContext $context)
{
return $this->sendContextAsync($context)->wait();
}
/**
* Creates the promise to send the context.
*
* @param HttpCallContext $context The context of the request.
*
* @return \GuzzleHttp\Promise\PromiseInterface
*/
protected function sendContextAsync(HttpCallContext $context)
{
return $this->sendAsync(
$context->getMethod(),
$context->getHeaders(),
$context->getQueryParameters(),
$context->getPostParameters(),
$context->getPath(),
$context->getStatusCodes(),
$context->getBody(),
$context->getServiceOptions()
);
}
/**
* Throws ServiceException if the received status code is not expected.
*
* @param ResponseInterface $response The response received
* @param array|int $expected The expected status codes.
*
* @return void
*
* @throws ServiceException
*/
public static function throwIfError(ResponseInterface $response, $expected)
{
$expectedStatusCodes = is_array($expected) ? $expected : array($expected);
if (!in_array($response->getStatusCode(), $expectedStatusCodes)) {
throw new ServiceException($response);
}
}
/**
* Adds HTTP POST parameter to the specified
*
* @param array $postParameters An array of HTTP POST parameters.
* @param string $key The key of a HTTP POST parameter.
* @param string $value the value of a HTTP POST parameter.
*
* @return array
*/
public function addPostParameter(
array $postParameters,
$key,
$value
) {
Validate::isArray($postParameters, 'postParameters');
$postParameters[$key] = $value;
return $postParameters;
}
/**
* Groups set of values into one value separated with Resources::SEPARATOR
*
* @param array $values array of values to be grouped.
*
* @return string
*/
public static function groupQueryValues(array $values)
{
Validate::isArray($values, 'values');
$joined = Resources::EMPTY_STRING;
sort($values);
foreach ($values as $value) {
if (!is_null($value) && !empty($value)) {
$joined .= $value . Resources::SEPARATOR;
}
}
return trim($joined, Resources::SEPARATOR);
}
/**
* Adds metadata elements to headers array
*
* @param array $headers HTTP request headers
* @param array $metadata user specified metadata
*
* @return array
*/
protected function addMetadataHeaders(array $headers, array $metadata = null)
{
Utilities::validateMetadata($metadata);
$metadata = $this->generateMetadataHeaders($metadata);
$headers = array_merge($headers, $metadata);
return $headers;
}
/**
* Generates metadata headers by prefixing each element with 'x-ms-meta'.
*
* @param array $metadata user defined metadata.
*
* @return array
*/
public function generateMetadataHeaders(array $metadata = null)
{
$metadataHeaders = array();
if (is_array($metadata) && !is_null($metadata)) {
foreach ($metadata as $key => $value) {
$headerName = Resources::X_MS_META_HEADER_PREFIX;
if (strpos($value, "\r") !== false
|| strpos($value, "\n") !== false
) {
throw new \InvalidArgumentException(Resources::INVALID_META_MSG);
}
// Metadata name is case-presrved and case insensitive
$headerName .= $key;
$metadataHeaders[$headerName] = $value;
}
}
return $metadataHeaders;
}
/**
* Get the primary URI in PSR form.
*
* @return Uri
*/
public function getPsrPrimaryUri()
{
return $this->psrPrimaryUri;
}
/**
* Get the secondary URI in PSR form.
*
* @return Uri
*/
public function getPsrSecondaryUri()
{
return $this->psrSecondaryUri;
}
/**
* Adds the header that indicates the location mode to the response header.
*
* @return ResponseInterface
*/
private static function addLocationHeaderToResponse(
ResponseInterface $response,
$locationMode
) {
//If the response already has this header, return itself.
if ($response->hasHeader(Resources::X_MS_CONTINUATION_LOCATION_MODE)) {
return $response;
}
//Otherwise, add the header that indicates the endpoint to be used if
//continuation token is used for subsequent request. Notice that if the
//response does not have location header set at the moment, it means
//that the user have not set a retry middleware.
if ($locationMode == LocationMode::PRIMARY_THEN_SECONDARY) {
$response = $response->withHeader(
Resources::X_MS_CONTINUATION_LOCATION_MODE,
LocationMode::PRIMARY_ONLY
);
} elseif ($locationMode == LocationMode::SECONDARY_THEN_PRIMARY) {
$response = $response->withHeader(
Resources::X_MS_CONTINUATION_LOCATION_MODE,
LocationMode::SECONDARY_ONLY
);
} elseif ($locationMode == LocationMode::SECONDARY_ONLY ||
$locationMode == LocationMode::PRIMARY_ONLY) {
$response = $response->withHeader(
Resources::X_MS_CONTINUATION_LOCATION_MODE,
$locationMode
);
}
return $response;
}
}
@@ -0,0 +1,259 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
use MicrosoftAzure\Storage\Common\LocationMode;
use MicrosoftAzure\Storage\Common\Models\ServiceOptions;
use MicrosoftAzure\Storage\Common\Models\ServiceProperties;
use MicrosoftAzure\Storage\Common\Models\GetServicePropertiesResult;
use MicrosoftAzure\Storage\Common\Models\GetServiceStatsResult;
/**
* Trait implementing common REST API for all the services, including the
* following:
* Get/Set Service Properties
* Get service stats
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
trait ServiceRestTrait
{
/**
* Gets the properties of the service.
*
* @param ServiceOptions $options The optional parameters.
*
* @return \MicrosoftAzure\Storage\Common\Models\GetServicePropertiesResult
*
* @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452239.aspx
*/
public function getServiceProperties(
ServiceOptions $options = null
) {
return $this->getServicePropertiesAsync($options)->wait();
}
/**
* Creates promise to get the properties of the service.
*
* @param ServiceOptions $options The optional parameters.
*
* @return \GuzzleHttp\Promise\PromiseInterface
*
* @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452239.aspx
*/
public function getServicePropertiesAsync(
ServiceOptions $options = null
) {
$method = Resources::HTTP_GET;
$headers = array();
$queryParams = array();
$postParams = array();
$path = Resources::EMPTY_STRING;
if (is_null($options)) {
$options = new ServiceOptions();
}
$this->addOptionalQueryParam(
$queryParams,
Resources::QP_REST_TYPE,
'service'
);
$this->addOptionalQueryParam(
$queryParams,
Resources::QP_COMP,
'properties'
);
$dataSerializer = $this->dataSerializer;
return $this->sendAsync(
$method,
$headers,
$queryParams,
$postParams,
$path,
Resources::STATUS_OK,
Resources::EMPTY_STRING,
$options
)->then(function ($response) use ($dataSerializer) {
$parsed = $dataSerializer->unserialize($response->getBody());
return GetServicePropertiesResult::create($parsed);
}, null);
}
/**
* Sets the properties of the service.
*
* It's recommended to use getServiceProperties, alter the returned object and
* then use setServiceProperties with this altered object.
*
* @param ServiceProperties $serviceProperties The service properties.
* @param ServiceOptions $options The optional parameters.
*
* @return void
*
* @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452235.aspx
*/
public function setServiceProperties(
ServiceProperties $serviceProperties,
ServiceOptions $options = null
) {
$this->setServicePropertiesAsync($serviceProperties, $options)->wait();
}
/**
* Creates the promise to set the properties of the service.
*
* It's recommended to use getServiceProperties, alter the returned object and
* then use setServiceProperties with this altered object.
*
* @param ServiceProperties $serviceProperties The service properties.
* @param ServiceOptions $options The optional parameters.
*
* @return \GuzzleHttp\Promise\PromiseInterface
*
* @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452235.aspx
*/
public function setServicePropertiesAsync(
ServiceProperties $serviceProperties,
ServiceOptions $options = null
) {
Validate::isTrue(
$serviceProperties instanceof ServiceProperties,
Resources::INVALID_SVC_PROP_MSG
);
$method = Resources::HTTP_PUT;
$headers = array();
$queryParams = array();
$postParams = array();
$path = Resources::EMPTY_STRING;
$body = $serviceProperties->toXml($this->dataSerializer);
if (is_null($options)) {
$options = new ServiceOptions();
}
$this->addOptionalQueryParam(
$queryParams,
Resources::QP_REST_TYPE,
'service'
);
$this->addOptionalQueryParam(
$queryParams,
Resources::QP_COMP,
'properties'
);
$this->addOptionalHeader(
$headers,
Resources::CONTENT_TYPE,
Resources::URL_ENCODED_CONTENT_TYPE
);
$options->setLocationMode(LocationMode::PRIMARY_ONLY);
return $this->sendAsync(
$method,
$headers,
$queryParams,
$postParams,
$path,
Resources::STATUS_ACCEPTED,
$body,
$options
);
}
/**
* Retrieves statistics related to replication for the service. The operation
* will only be sent to secondary location endpoint.
*
* @param ServiceOptions|null $options The options this operation sends with.
*
* @return GetServiceStatsResult
*/
public function getServiceStats(ServiceOptions $options = null)
{
return $this->getServiceStatsAsync($options)->wait();
}
/**
* Creates promise that retrieves statistics related to replication for the
* service. The operation will only be sent to secondary location endpoint.
*
* @param ServiceOptions|null $options The options this operation sends with.
*
* @return \GuzzleHttp\Promise\PromiseInterface
*/
public function getServiceStatsAsync(ServiceOptions $options = null)
{
$method = Resources::HTTP_GET;
$headers = array();
$queryParams = array();
$postParams = array();
$path = Resources::EMPTY_STRING;
if (is_null($options)) {
$options = new ServiceOptions();
}
$this->addOptionalQueryParam(
$queryParams,
Resources::QP_REST_TYPE,
'service'
);
$this->addOptionalQueryParam(
$queryParams,
Resources::QP_COMP,
'stats'
);
$dataSerializer = $this->dataSerializer;
$options->setLocationMode(LocationMode::SECONDARY_ONLY);
return $this->sendAsync(
$method,
$headers,
$queryParams,
$postParams,
$path,
Resources::STATUS_OK,
Resources::EMPTY_STRING,
$options
)->then(function ($response) use ($dataSerializer) {
$parsed = $dataSerializer->unserialize($response->getBody());
return GetServiceStatsResult::create($parsed);
}, null);
}
}
@@ -0,0 +1,288 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
/**
* Base class for all REST services settings.
*
* Derived classes must implement the following members:
* 1- $isInitialized: A static property that indicates whether the class's static
* members have been initialized.
* 2- init(): A protected static method that initializes static members.
* 3- $validSettingKeys: A static property that contains valid setting keys for this
* service.
* 4- createFromConnectionString($connectionString): A public static function that
* takes a connection string and returns the created settings object.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
abstract class ServiceSettings
{
/**
* Throws an exception if the connection string format does not match any of the
* available formats.
*
* @param string $connectionString The invalid formatted connection string.
*
* @return void
*
* @throws \RuntimeException
*/
protected static function noMatch($connectionString)
{
throw new \RuntimeException(
sprintf(Resources::MISSING_CONNECTION_STRING_SETTINGS, $connectionString)
);
}
/**
* Parses the connection string and then validate that the parsed keys belong to
* the $validSettingKeys
*
* @param string $connectionString The user provided connection string.
*
* @return array The tokenized connection string keys.
*
* @throws \RuntimeException
*/
protected static function parseAndValidateKeys($connectionString)
{
// Initialize the static values if they are not initialized yet.
if (!static::$isInitialized) {
static::init();
static::$isInitialized = true;
}
$tokenizedSettings = ConnectionStringParser::parseConnectionString(
'connectionString',
$connectionString
);
// Assure that all given keys are valid.
foreach ($tokenizedSettings as $key => $value) {
if (!Utilities::inArrayInsensitive($key, static::$validSettingKeys)) {
throw new \RuntimeException(
sprintf(
Resources::INVALID_CONNECTION_STRING_SETTING_KEY,
$key,
implode("\n", static::$validSettingKeys)
)
);
}
}
return $tokenizedSettings;
}
/**
* Creates an anonymous function that acts as predicate.
*
* @param array $requirements The array of conditions to satisfy.
* @param boolean $isRequired Either these conditions are all required or all
* optional.
* @param boolean $atLeastOne Indicates that at least one requirement must
* succeed.
*
* @return callable
*/
protected static function getValidator(
array $requirements,
$isRequired,
$atLeastOne
) {
// @codingStandardsIgnoreStart
return function ($userSettings) use ($requirements, $isRequired, $atLeastOne) {
$oneFound = false;
$result = array_change_key_case($userSettings);
foreach ($requirements as $requirement) {
$settingName = strtolower($requirement[Resources::SETTING_NAME]);
// Check if the setting name exists in the provided user settings.
if (array_key_exists($settingName, $result)) {
// Check if the provided user setting value is valid.
$validationFunc = $requirement[Resources::SETTING_CONSTRAINT];
$isValid = $validationFunc($result[$settingName]);
if ($isValid) {
// Remove the setting as indicator for successful validation.
unset($result[$settingName]);
$oneFound = true;
}
} else {
// If required then fail because the setting does not exist
if ($isRequired) {
return null;
}
}
}
if ($atLeastOne) {
// At least one requirement must succeed, otherwise fail.
return $oneFound ? $result : null;
} else {
return $result;
}
};
// @codingStandardsIgnoreEnd
}
/**
* Creates at lease one succeed predicate for the provided list of requirements.
*
* @return callable
*/
protected static function atLeastOne()
{
$allSettings = func_get_args();
return self::getValidator($allSettings, false, true);
}
/**
* Creates an optional predicate for the provided list of requirements.
*
* @return callable
*/
protected static function optional()
{
$optionalSettings = func_get_args();
return self::getValidator($optionalSettings, false, false);
}
/**
* Creates an required predicate for the provided list of requirements.
*
* @return callable
*/
protected static function allRequired()
{
$requiredSettings = func_get_args();
return self::getValidator($requiredSettings, true, false);
}
/**
* Creates a setting value condition using the passed predicate.
*
* @param string $name The setting key name.
* @param callable $predicate The setting value predicate.
*
* @return array
*/
protected static function settingWithFunc($name, $predicate)
{
$requirement = array();
$requirement[Resources::SETTING_NAME] = $name;
$requirement[Resources::SETTING_CONSTRAINT] = $predicate;
return $requirement;
}
/**
* Creates a setting value condition that validates it is one of the
* passed valid values.
*
* @param string $name The setting key name.
*
* @return array
*/
protected static function setting($name)
{
$validValues = func_get_args();
// Remove $name argument.
unset($validValues[0]);
$validValuesCount = func_num_args();
$predicate = function ($settingValue) use ($validValuesCount, $validValues) {
if (empty($validValues)) {
// No restrictions, succeed,
return true;
}
// Check to find if the $settingValue is valid or not. The index must
// start from 1 as unset deletes the value but does not update the array
// indecies.
for ($index = 1; $index < $validValuesCount; $index++) {
if ($settingValue == $validValues[$index]) {
// $settingValue is found in valid values set, succeed.
return true;
}
}
throw new \RuntimeException(
sprintf(
Resources::INVALID_CONFIG_VALUE,
$settingValue,
implode("\n", $validValues)
)
);
// $settingValue is missing in valid values set, fail.
return false;
};
return self::settingWithFunc($name, $predicate);
}
/**
* Tests to see if a given list of settings matches a set of filters exactly.
*
* @param array $settings The settings to check.
*
* @return boolean If any filter returns null, false. If there are any settings
* left over after all filters are processed, false. Otherwise true.
*/
protected static function matchedSpecification(array $settings)
{
$constraints = func_get_args();
// Remove first element which corresponds to $settings
unset($constraints[0]);
foreach ($constraints as $constraint) {
$remainingSettings = $constraint($settings);
if (is_null($remainingSettings)) {
return false;
} else {
$settings = $remainingSettings;
}
}
if (empty($settings)) {
return true;
}
return false;
}
}
@@ -0,0 +1,713 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
/**
* Represents the settings used to sign and access a request against the storage
* service. For more information about storage service connection strings check this
* page: http://msdn.microsoft.com/en-us/library/ee758697
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class StorageServiceSettings extends ServiceSettings
{
private $name;
private $key;
private $sas;
private $blobEndpointUri;
private $queueEndpointUri;
private $tableEndpointUri;
private $fileEndpointUri;
private $blobSecondaryEndpointUri;
private $queueSecondaryEndpointUri;
private $tableSecondaryEndpointUri;
private $fileSecondaryEndpointUri;
private static $devStoreAccount;
private static $useDevelopmentStorageSetting;
private static $developmentStorageProxyUriSetting;
private static $defaultEndpointsProtocolSetting;
private static $accountNameSetting;
private static $accountKeySetting;
private static $sasTokenSetting;
private static $blobEndpointSetting;
private static $queueEndpointSetting;
private static $tableEndpointSetting;
private static $fileEndpointSetting;
private static $endpointSuffixSetting;
/**
* If initialized or not
* @internal
*/
protected static $isInitialized = false;
/**
* Valid setting keys
* @internal
*/
protected static $validSettingKeys = array();
/**
* Initializes static members of the class.
*
* @return void
*/
protected static function init()
{
self::$useDevelopmentStorageSetting = self::setting(
Resources::USE_DEVELOPMENT_STORAGE_NAME,
'true'
);
self::$developmentStorageProxyUriSetting = self::settingWithFunc(
Resources::DEVELOPMENT_STORAGE_PROXY_URI_NAME,
Validate::getIsValidUri()
);
self::$defaultEndpointsProtocolSetting = self::setting(
Resources::DEFAULT_ENDPOINTS_PROTOCOL_NAME,
'http',
'https'
);
self::$accountNameSetting = self::setting(Resources::ACCOUNT_NAME_NAME);
self::$accountKeySetting = self::settingWithFunc(
Resources::ACCOUNT_KEY_NAME,
// base64_decode will return false if the $key is not in base64 format.
function ($key) {
$isValidBase64String = base64_decode($key, true);
if ($isValidBase64String) {
return true;
} else {
throw new \RuntimeException(
sprintf(Resources::INVALID_ACCOUNT_KEY_FORMAT, $key)
);
}
}
);
self::$sasTokenSetting = self::setting(Resources::SAS_TOKEN_NAME);
self::$blobEndpointSetting = self::settingWithFunc(
Resources::BLOB_ENDPOINT_NAME,
Validate::getIsValidUri()
);
self::$queueEndpointSetting = self::settingWithFunc(
Resources::QUEUE_ENDPOINT_NAME,
Validate::getIsValidUri()
);
self::$tableEndpointSetting = self::settingWithFunc(
Resources::TABLE_ENDPOINT_NAME,
Validate::getIsValidUri()
);
self::$fileEndpointSetting = self::settingWithFunc(
Resources::FILE_ENDPOINT_NAME,
Validate::getIsValidUri()
);
self::$endpointSuffixSetting = self::settingWithFunc(
Resources::ENDPOINT_SUFFIX_NAME,
Validate::getIsValidHostname()
);
self::$validSettingKeys[] = Resources::USE_DEVELOPMENT_STORAGE_NAME;
self::$validSettingKeys[] = Resources::DEVELOPMENT_STORAGE_PROXY_URI_NAME;
self::$validSettingKeys[] = Resources::DEFAULT_ENDPOINTS_PROTOCOL_NAME;
self::$validSettingKeys[] = Resources::ACCOUNT_NAME_NAME;
self::$validSettingKeys[] = Resources::ACCOUNT_KEY_NAME;
self::$validSettingKeys[] = Resources::SAS_TOKEN_NAME;
self::$validSettingKeys[] = Resources::BLOB_ENDPOINT_NAME;
self::$validSettingKeys[] = Resources::QUEUE_ENDPOINT_NAME;
self::$validSettingKeys[] = Resources::TABLE_ENDPOINT_NAME;
self::$validSettingKeys[] = Resources::FILE_ENDPOINT_NAME;
self::$validSettingKeys[] = Resources::ENDPOINT_SUFFIX_NAME;
}
/**
* Creates new storage service settings instance.
*
* @param string $name The storage service name.
* @param string $key The storage service key.
* @param string $blobEndpointUri The storage service blob
* endpoint.
* @param string $queueEndpointUri The storage service queue
* endpoint.
* @param string $tableEndpointUri The storage service table
* endpoint.
* @param string $fileEndpointUri The storage service file
* endpoint.
* @param string $blobSecondaryEndpointUri The storage service secondary
* blob endpoint.
* @param string $queueSecondaryEndpointUri The storage service secondary
* queue endpoint.
* @param string $tableSecondaryEndpointUri The storage service secondary
* table endpoint.
* @param string $fileSecondaryEndpointUri The storage service secondary
* file endpoint.
* @param string $sas The storage service SAS token.
*/
public function __construct(
$name,
$key,
$blobEndpointUri,
$queueEndpointUri,
$tableEndpointUri,
$fileEndpointUri,
$blobSecondaryEndpointUri = null,
$queueSecondaryEndpointUri = null,
$tableSecondaryEndpointUri = null,
$fileSecondaryEndpointUri = null,
$sas = null
) {
$this->name = $name;
$this->key = $key;
$this->sas = $sas;
$this->blobEndpointUri = $blobEndpointUri;
$this->queueEndpointUri = $queueEndpointUri;
$this->tableEndpointUri = $tableEndpointUri;
$this->fileEndpointUri = $fileEndpointUri;
$this->blobSecondaryEndpointUri = $blobSecondaryEndpointUri;
$this->queueSecondaryEndpointUri = $queueSecondaryEndpointUri;
$this->tableSecondaryEndpointUri = $tableSecondaryEndpointUri;
$this->fileSecondaryEndpointUri = $fileSecondaryEndpointUri;
}
/**
* Returns a StorageServiceSettings with development storage credentials using
* the specified proxy Uri.
*
* @param string $proxyUri The proxy endpoint to use.
*
* @return StorageServiceSettings
*/
private static function getDevelopmentStorageAccount($proxyUri)
{
if (is_null($proxyUri)) {
return self::developmentStorageAccount();
}
$scheme = parse_url($proxyUri, PHP_URL_SCHEME);
$host = parse_url($proxyUri, PHP_URL_HOST);
$prefix = $scheme . "://" . $host;
return new StorageServiceSettings(
Resources::DEV_STORE_NAME,
Resources::DEV_STORE_KEY,
$prefix . ':10000/devstoreaccount1/',
$prefix . ':10001/devstoreaccount1/',
$prefix . ':10002/devstoreaccount1/',
null
);
}
/**
* Gets a StorageServiceSettings object that references the development storage
* account.
*
* @return StorageServiceSettings
*/
public static function developmentStorageAccount()
{
if (is_null(self::$devStoreAccount)) {
self::$devStoreAccount = self::getDevelopmentStorageAccount(
Resources::DEV_STORE_URI
);
}
return self::$devStoreAccount;
}
/**
* Gets the default service endpoint using the specified protocol and account
* name.
*
* @param string $scheme The scheme of the service end point.
* @param string $accountName The account name of the service.
* @param string $dnsPrefix The service DNS prefix.
* @param string $dnsSuffix The service DNS suffix.
* @param bool $isSecondary If generating secondary endpoint.
*
* @return string
*/
private static function getServiceEndpoint(
$scheme,
$accountName,
$dnsPrefix,
$dnsSuffix = null,
$isSecondary = false
) {
if ($isSecondary) {
$accountName .= Resources::SECONDARY_STRING;
}
if ($dnsSuffix === null) {
$dnsSuffix = Resources::DEFAULT_ENDPOINT_SUFFIX;
}
return sprintf(
Resources::SERVICE_URI_FORMAT,
$scheme,
$accountName,
$dnsPrefix.$dnsSuffix
);
}
/**
* Creates StorageServiceSettings object given endpoints uri.
*
* @param array $settings The service settings.
* @param string $blobEndpointUri The blob endpoint uri.
* @param string $queueEndpointUri The queue endpoint uri.
* @param string $tableEndpointUri The table endpoint uri.
* @param string $fileEndpointUri The file endpoint uri.
* @param string $blobSecondaryEndpointUri The blob secondary endpoint uri.
* @param string $queueSecondaryEndpointUri The queue secondary endpoint uri.
* @param string $tableSecondaryEndpointUri The table secondary endpoint uri.
* @param string $fileSecondaryEndpointUri The file secondary endpoint uri.
*
* @return StorageServiceSettings
*/
private static function createStorageServiceSettings(
array $settings,
$blobEndpointUri = null,
$queueEndpointUri = null,
$tableEndpointUri = null,
$fileEndpointUri = null,
$blobSecondaryEndpointUri = null,
$queueSecondaryEndpointUri = null,
$tableSecondaryEndpointUri = null,
$fileSecondaryEndpointUri = null
) {
$blobEndpointUri = Utilities::tryGetValueInsensitive(
Resources::BLOB_ENDPOINT_NAME,
$settings,
$blobEndpointUri
);
$queueEndpointUri = Utilities::tryGetValueInsensitive(
Resources::QUEUE_ENDPOINT_NAME,
$settings,
$queueEndpointUri
);
$tableEndpointUri = Utilities::tryGetValueInsensitive(
Resources::TABLE_ENDPOINT_NAME,
$settings,
$tableEndpointUri
);
$fileEndpointUri = Utilities::tryGetValueInsensitive(
Resources::FILE_ENDPOINT_NAME,
$settings,
$fileEndpointUri
);
$accountName = Utilities::tryGetValueInsensitive(
Resources::ACCOUNT_NAME_NAME,
$settings
);
$accountKey = Utilities::tryGetValueInsensitive(
Resources::ACCOUNT_KEY_NAME,
$settings
);
$sasToken = Utilities::tryGetValueInsensitive(
Resources::SAS_TOKEN_NAME,
$settings
);
return new StorageServiceSettings(
$accountName,
$accountKey,
$blobEndpointUri,
$queueEndpointUri,
$tableEndpointUri,
$fileEndpointUri,
$blobSecondaryEndpointUri,
$queueSecondaryEndpointUri,
$tableSecondaryEndpointUri,
$fileSecondaryEndpointUri,
$sasToken
);
}
/**
* Creates a StorageServiceSettings object from the given connection string.
*
* @param string $connectionString The storage settings connection string.
*
* @return StorageServiceSettings
*/
public static function createFromConnectionString($connectionString)
{
$tokenizedSettings = self::parseAndValidateKeys($connectionString);
// Devstore case
$matchedSpecs = self::matchedSpecification(
$tokenizedSettings,
self::allRequired(self::$useDevelopmentStorageSetting),
self::optional(self::$developmentStorageProxyUriSetting)
);
if ($matchedSpecs) {
$proxyUri = Utilities::tryGetValueInsensitive(
Resources::DEVELOPMENT_STORAGE_PROXY_URI_NAME,
$tokenizedSettings
);
return self::getDevelopmentStorageAccount($proxyUri);
}
// Automatic case
$matchedSpecs = self::matchedSpecification(
$tokenizedSettings,
self::allRequired(
self::$defaultEndpointsProtocolSetting,
self::$accountNameSetting,
self::$accountKeySetting
),
self::optional(
self::$blobEndpointSetting,
self::$queueEndpointSetting,
self::$tableEndpointSetting,
self::$fileEndpointSetting,
self::$endpointSuffixSetting
)
);
if ($matchedSpecs) {
$scheme = Utilities::tryGetValueInsensitive(
Resources::DEFAULT_ENDPOINTS_PROTOCOL_NAME,
$tokenizedSettings
);
$accountName = Utilities::tryGetValueInsensitive(
Resources::ACCOUNT_NAME_NAME,
$tokenizedSettings
);
$endpointSuffix = Utilities::tryGetValueInsensitive(
Resources::ENDPOINT_SUFFIX_NAME,
$tokenizedSettings
);
return self::createStorageServiceSettings(
$tokenizedSettings,
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::BLOB_DNS_PREFIX,
$endpointSuffix
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::QUEUE_DNS_PREFIX,
$endpointSuffix
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::TABLE_DNS_PREFIX,
$endpointSuffix
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::FILE_DNS_PREFIX,
$endpointSuffix
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::BLOB_DNS_PREFIX,
$endpointSuffix,
true
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::QUEUE_DNS_PREFIX,
$endpointSuffix,
true
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::TABLE_DNS_PREFIX,
$endpointSuffix,
true
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::FILE_DNS_PREFIX,
$endpointSuffix,
true
)
);
}
// Explicit case for AccountName/AccountKey combination
$matchedSpecs = self::matchedSpecification(
$tokenizedSettings,
self::atLeastOne(
self::$blobEndpointSetting,
self::$queueEndpointSetting,
self::$tableEndpointSetting,
self::$fileEndpointSetting
),
self::allRequired(
self::$accountNameSetting,
self::$accountKeySetting
)
);
if ($matchedSpecs) {
return self::createStorageServiceSettings($tokenizedSettings);
}
// Explicit case for SAS token
$matchedSpecs = self::matchedSpecification(
$tokenizedSettings,
self::atLeastOne(
self::$blobEndpointSetting,
self::$queueEndpointSetting,
self::$tableEndpointSetting,
self::$fileEndpointSetting
),
self::allRequired(
self::$sasTokenSetting
)
);
if ($matchedSpecs) {
return self::createStorageServiceSettings($tokenizedSettings);
}
self::noMatch($connectionString);
}
/**
* Creates a StorageServiceSettings object from the given connection string.
* Note this is only for AAD connection string, it should at least contain
* the account name.
*
* @param string $connectionString The storage settings connection string.
*
* @return StorageServiceSettings
*/
public static function createFromConnectionStringForTokenCredential($connectionString)
{
// Explicit case for AAD token, Connection string could only have account
// name.
$tokenizedSettings = self::parseAndValidateKeys($connectionString);
$scheme = Utilities::tryGetValueInsensitive(
Resources::DEFAULT_ENDPOINTS_PROTOCOL_NAME,
$tokenizedSettings
);
$accountName = Utilities::tryGetValueInsensitive(
Resources::ACCOUNT_NAME_NAME,
$tokenizedSettings
);
$endpointSuffix = Utilities::tryGetValueInsensitive(
Resources::ENDPOINT_SUFFIX_NAME,
$tokenizedSettings
);
return self::createStorageServiceSettings(
$tokenizedSettings,
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::BLOB_DNS_PREFIX,
$endpointSuffix
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::QUEUE_DNS_PREFIX,
$endpointSuffix
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::TABLE_DNS_PREFIX,
$endpointSuffix
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::FILE_DNS_PREFIX,
$endpointSuffix
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::BLOB_DNS_PREFIX,
$endpointSuffix,
true
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::QUEUE_DNS_PREFIX,
$endpointSuffix,
true
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::TABLE_DNS_PREFIX,
$endpointSuffix,
true
),
self::getServiceEndpoint(
$scheme,
$accountName,
Resources::FILE_DNS_PREFIX,
$endpointSuffix,
true
)
);
}
/**
* Gets storage service name.
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Gets storage service key.
*
* @return string
*/
public function getKey()
{
return $this->key;
}
/**
* Checks if there is a SAS token.
*
* @return boolean
*/
public function hasSasToken()
{
return !empty($this->sas);
}
/**
* Gets storage service SAS token.
*
* @return string
*/
public function getSasToken()
{
return $this->sas;
}
/**
* Gets storage service blob endpoint uri.
*
* @return string
*/
public function getBlobEndpointUri()
{
return $this->blobEndpointUri;
}
/**
* Gets storage service queue endpoint uri.
*
* @return string
*/
public function getQueueEndpointUri()
{
return $this->queueEndpointUri;
}
/**
* Gets storage service table endpoint uri.
*
* @return string
*/
public function getTableEndpointUri()
{
return $this->tableEndpointUri;
}
/**
* Gets storage service file endpoint uri.
*
* @return string
*/
public function getFileEndpointUri()
{
return $this->fileEndpointUri;
}
/**
* Gets storage service secondary blob endpoint uri.
*
* @return string
*/
public function getBlobSecondaryEndpointUri()
{
return $this->blobSecondaryEndpointUri;
}
/**
* Gets storage service secondary queue endpoint uri.
*
* @return string
*/
public function getQueueSecondaryEndpointUri()
{
return $this->queueSecondaryEndpointUri;
}
/**
* Gets storage service secondary table endpoint uri.
*
* @return string
*/
public function getTableSecondaryEndpointUri()
{
return $this->tableSecondaryEndpointUri;
}
/**
* Gets storage service secondary file endpoint uri.
*
* @return string
*/
public function getFileSecondaryEndpointUri()
{
return $this->fileSecondaryEndpointUri;
}
}
@@ -0,0 +1,907 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
use Psr\Http\Message\StreamInterface;
/**
* Utilities for the project
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class Utilities
{
/**
* Returns the specified value of the $key passed from $array and in case that
* this $key doesn't exist, the default value is returned.
*
* @param array $array The array to be used.
* @param mixed $key The array key.
* @param mixed $default The value to return if $key is not found in $array.
*
* @return mixed
*/
public static function tryGetValue($array, $key, $default = null)
{
return (!is_null($array)) && is_array($array) && array_key_exists($key, $array)
? $array[$key]
: $default;
}
/**
* Adds a url scheme if there is no scheme. Return null if input URL is null.
*
* @param string $url The URL.
* @param string $scheme The scheme. By default HTTP
*
* @return string
*/
public static function tryAddUrlScheme($url, $scheme = 'http')
{
if ($url == null) {
return $url;
}
$urlScheme = parse_url($url, PHP_URL_SCHEME);
if (empty($urlScheme)) {
$url = "$scheme://" . $url;
}
return $url;
}
/**
* Parse storage account name from an endpoint url.
*
* @param string $url The endpoint $url
*
* @return string
*/
public static function tryParseAccountNameFromUrl($url)
{
$host = parse_url($url, PHP_URL_HOST);
// first token of the url host is account name
return explode('.', $host)[0];
}
/**
* Parse secondary endpoint url string from a primary endpoint url.
*
* Return null if the primary endpoint url is invalid.
*
* @param string $uri The primary endpoint url string.
*
* @return null|string
*/
public static function tryGetSecondaryEndpointFromPrimaryEndpoint($uri)
{
$splitTokens = explode('.', $uri);
if (count($splitTokens) > 0 && $splitTokens[0] != '') {
$schemaAccountToken = $splitTokens[0];
$schemaAccountSplitTokens = explode('/', $schemaAccountToken);
if (count($schemaAccountSplitTokens) > 0 &&
$schemaAccountSplitTokens[0] != '') {
$accountName = $schemaAccountSplitTokens[
count($schemaAccountSplitTokens) - 1
];
$schemaAccountSplitTokens[count($schemaAccountSplitTokens) - 1] =
$accountName . Resources::SECONDARY_STRING;
$splitTokens[0] = implode('/', $schemaAccountSplitTokens);
$secondaryUri = implode('.', $splitTokens);
return $secondaryUri;
}
}
return null;
}
/**
* tries to get nested array with index name $key from $array.
*
* Returns empty array object if the value is NULL.
*
* @param string $key The index name.
* @param array $array The array object.
*
* @return array
*/
public static function tryGetArray($key, array $array)
{
return Utilities::getArray(Utilities::tryGetValue($array, $key));
}
/**
* Adds the given key/value pair into array if the value doesn't satisfy empty().
*
* This function just validates that the given $array is actually array. If it's
* NULL the function treats it as array.
*
* @param string $key The key.
* @param string $value The value.
* @param array &$array The array. If NULL will be used as array.
*
* @return void
*/
public static function addIfNotEmpty($key, $value, array &$array)
{
if (!is_null($array)) {
Validate::isArray($array, 'array');
}
if (!empty($value)) {
$array[$key] = $value;
}
}
/**
* Returns the specified value of the key chain passed from $array and in case
* that key chain doesn't exist, null is returned.
*
* @param array $array Array to be used.
*
* @return mixed
*/
public static function tryGetKeysChainValue(array $array)
{
$arguments = func_get_args();
$numArguments = func_num_args();
$currentArray = $array;
for ($i = 1; $i < $numArguments; $i++) {
if (is_array($currentArray)) {
if (array_key_exists($arguments[$i], $currentArray)) {
$currentArray = $currentArray[$arguments[$i]];
} else {
return null;
}
} else {
return null;
}
}
return $currentArray;
}
/**
* Checks if the passed $string starts with $prefix
*
* @param string $string word to seaech in
* @param string $prefix prefix to be matched
* @param boolean $ignoreCase true to ignore case during the comparison;
* otherwise, false
*
* @return boolean
*/
public static function startsWith($string, $prefix, $ignoreCase = false)
{
if ($ignoreCase) {
$string = strtolower($string);
$prefix = strtolower($prefix);
}
return ($prefix == substr($string, 0, strlen($prefix)));
}
/**
* Returns grouped items from passed $var
*
* @param array $var item to group
*
* @return array
*/
public static function getArray(array $var)
{
if (is_null($var) || empty($var)) {
return array();
}
foreach ($var as $value) {
if ((gettype($value) == 'object')
&& (get_class($value) == 'SimpleXMLElement')
) {
return (array) $var;
} elseif (!is_array($value)) {
return array($var);
}
}
return $var;
}
/**
* Unserializes the passed $xml into array.
*
* @param string $xml XML to be parsed.
*
* @return array
*/
public static function unserialize($xml)
{
$sxml = new \SimpleXMLElement($xml);
return self::_sxml2arr($sxml);
}
/**
* Converts a SimpleXML object to an Array recursively
* ensuring all sub-elements are arrays as well.
*
* @param string $sxml SimpleXML object
* @param array $arr Array into which to store results
*
* @return array
*/
private static function _sxml2arr($sxml, array $arr = null)
{
foreach ((array) $sxml as $key => $value) {
if (is_object($value) || (is_array($value))) {
$arr[$key] = self::_sxml2arr($value);
} else {
$arr[$key] = $value;
}
}
return $arr;
}
/**
* Serializes given array into xml. The array indices must be string to use
* them as XML tags.
*
* @param array $array object to serialize represented in array.
* @param string $rootName name of the XML root element.
* @param string $defaultTag default tag for non-tagged elements.
* @param string $standalone adds 'standalone' header tag, values 'yes'/'no'
*
* @return string
*/
public static function serialize(
array $array,
$rootName,
$defaultTag = null,
$standalone = null
) {
$xmlVersion = '1.0';
$xmlEncoding = 'UTF-8';
if (!is_array($array)) {
return false;
}
$xmlw = new \XmlWriter();
$xmlw->openMemory();
$xmlw->startDocument($xmlVersion, $xmlEncoding, $standalone);
$xmlw->startElement($rootName);
self::_arr2xml($xmlw, $array, $defaultTag);
$xmlw->endElement();
return $xmlw->outputMemory(true);
}
/**
* Takes an array and produces XML based on it.
*
* @param XMLWriter $xmlw XMLWriter object that was previously instanted
* and is used for creating the XML.
* @param array $data Array to be converted to XML
* @param string $defaultTag Default XML tag to be used if none specified.
*
* @return void
*/
private static function _arr2xml(
\XMLWriter $xmlw,
array $data,
$defaultTag = null
) {
foreach ($data as $key => $value) {
if (strcmp($key, '@attributes') == 0) {
foreach ($value as $attributeName => $attributeValue) {
$xmlw->writeAttribute($attributeName, $attributeValue);
}
} elseif (is_array($value)) {
if (!is_int($key)) {
if ($key != Resources::EMPTY_STRING) {
$xmlw->startElement($key);
} else {
$xmlw->startElement($defaultTag);
}
}
self::_arr2xml($xmlw, $value);
if (!is_int($key)) {
$xmlw->endElement();
}
continue;
} else {
$xmlw->writeElement($key, $value);
}
}
}
/**
* Converts string into boolean value.
*
* @param string $obj boolean value in string format.
* @param bool $skipNull If $skipNull is set, will return NULL directly
* when $obj is NULL.
*
* @return bool
*/
public static function toBoolean($obj, $skipNull = false)
{
if ($skipNull && is_null($obj)) {
return null;
}
return filter_var($obj, FILTER_VALIDATE_BOOLEAN);
}
/**
* Converts string into boolean value.
*
* @param bool $obj boolean value to convert.
*
* @return string
*/
public static function booleanToString($obj)
{
return $obj ? 'true' : 'false';
}
/**
* Converts a given date string into \DateTime object
*
* @param string $date windows azure date ins string representation.
*
* @return \DateTime
*/
public static function rfc1123ToDateTime($date)
{
$timeZone = new \DateTimeZone('GMT');
$format = Resources::AZURE_DATE_FORMAT;
return \DateTime::createFromFormat($format, $date, $timeZone);
}
/**
* Generate ISO 8601 compliant date string in UTC time zone
*
* @param \DateTimeInterface $date The date value to convert
*
* @return string
*/
public static function isoDate(\DateTimeInterface $date)
{
$date = clone $date;
$date = $date->setTimezone(new \DateTimeZone('UTC'));
return str_replace('+00:00', 'Z', $date->format('c'));
}
/**
* Converts a DateTime object into an Edm.DaeTime value in UTC timezone,
* represented as a string.
*
* @param mixed $value The datetime value.
*
* @return string
*/
public static function convertToEdmDateTime($value)
{
if (empty($value)) {
return $value;
}
if (is_string($value)) {
$value = self::convertToDateTime($value);
}
Validate::isDate($value);
$cloned = clone $value;
$cloned->setTimezone(new \DateTimeZone('UTC'));
return str_replace('+00:00', 'Z', $cloned->format("Y-m-d\TH:i:s.u0P"));
}
/**
* Converts a string to a \DateTime object. Returns false on failure.
*
* @param string $value The string value to parse.
*
* @return \DateTime
*/
public static function convertToDateTime($value)
{
if ($value instanceof \DateTime) {
return $value;
}
if (substr($value, -1) == 'Z') {
$value = substr($value, 0, strlen($value) - 1);
}
return new \DateTime($value, new \DateTimeZone('UTC'));
}
/**
* Converts string to stream handle.
*
* @param string $string The string contents.
*
* @return resource
*/
public static function stringToStream($string)
{
return fopen('data://text/plain,' . urlencode($string), 'rb');
}
/**
* Sorts an array based on given keys order.
*
* @param array $array The array to sort.
* @param array $order The keys order array.
*
* @return array
*/
public static function orderArray(array $array, array $order)
{
$ordered = array();
foreach ($order as $key) {
if (array_key_exists($key, $array)) {
$ordered[$key] = $array[$key];
}
}
return $ordered;
}
/**
* Checks if a value exists in an array. The comparison is done in a case
* insensitive manner.
*
* @param string $needle The searched value.
* @param array $haystack The array.
*
* @return boolean
*/
public static function inArrayInsensitive($needle, array $haystack)
{
return in_array(strtolower($needle), array_map('strtolower', $haystack));
}
/**
* Checks if the given key exists in the array. The comparison is done in a case
* insensitive manner.
*
* @param string $key The value to check.
* @param array $search The array with keys to check.
*
* @return boolean
*/
public static function arrayKeyExistsInsensitive($key, array $search)
{
return array_key_exists(strtolower($key), array_change_key_case($search));
}
/**
* Returns the specified value of the $key passed from $array and in case that
* this $key doesn't exist, the default value is returned. The key matching is
* done in a case insensitive manner.
*
* @param string $key The array key.
* @param array $haystack The array to be used.
* @param mixed $default The value to return if $key is not found in $array.
*
* @return mixed
*/
public static function tryGetValueInsensitive($key, $haystack, $default = null)
{
$array = array_change_key_case($haystack);
return Utilities::tryGetValue($array, strtolower($key), $default);
}
/**
* Returns a string representation of a version 4 GUID, which uses random
* numbers.There are 6 reserved bits, and the GUIDs have this format:
* xxxxxxxx-xxxx-4xxx-[8|9|a|b]xxx-xxxxxxxxxxxx
* where 'x' is a hexadecimal digit, 0-9a-f.
*
* See http://tools.ietf.org/html/rfc4122 for more information.
*
* Note: This function is available on all platforms, while the
* com_create_guid() is only available for Windows.
*
* @return string A new GUID.
*/
public static function getGuid()
{
// @codingStandardsIgnoreStart
return sprintf(
'%04x%04x-%04x-%04x-%02x%02x-%04x%04x%04x',
mt_rand(0, 65535),
mt_rand(0, 65535), // 32 bits for "time_low"
mt_rand(0, 65535), // 16 bits for "time_mid"
mt_rand(0, 4096) + 16384, // 16 bits for "time_hi_and_version", with
// the most significant 4 bits being 0100
// to indicate randomly generated version
mt_rand(0, 64) + 128, // 8 bits for "clock_seq_hi", with
// the most significant 2 bits being 10,
// required by version 4 GUIDs.
mt_rand(0, 255), // 8 bits for "clock_seq_low"
mt_rand(0, 65535), // 16 bits for "node 0" and "node 1"
mt_rand(0, 65535), // 16 bits for "node 2" and "node 3"
mt_rand(0, 65535) // 16 bits for "node 4" and "node 5"
);
// @codingStandardsIgnoreEnd
}
/**
* Creates a list of objects of type $class from the provided array using static
* create method.
*
* @param array $parsed The object in array representation
* @param string $class The class name. Must have static method create.
*
* @return array
*/
public static function createInstanceList(array $parsed, $class)
{
$list = array();
foreach ($parsed as $value) {
$list[] = $class::create($value);
}
return $list;
}
/**
* Takes a string and return if it ends with the specified character/string.
*
* @param string $haystack The string to search in.
* @param string $needle postfix to match.
* @param boolean $ignoreCase Set true to ignore case during the comparison;
* otherwise, false
*
* @return boolean
*/
public static function endsWith($haystack, $needle, $ignoreCase = false)
{
if ($ignoreCase) {
$haystack = strtolower($haystack);
$needle = strtolower($needle);
}
$length = strlen($needle);
if ($length == 0) {
return true;
}
return (substr($haystack, -$length) === $needle);
}
/**
* Get id from entity object or string.
* If entity is object than validate type and return $entity->$method()
* If entity is string than return this string
*
* @param object|string $entity Entity with id property
* @param string $type Entity type to validate
* @param string $method Methods that gets id (getId by default)
*
* @return string
*/
public static function getEntityId($entity, $type, $method = 'getId')
{
if (is_string($entity)) {
return $entity;
} else {
Validate::isA($entity, $type, 'entity');
Validate::methodExists($entity, $method, $type);
return $entity->$method();
}
}
/**
* Generate a pseudo-random string of bytes using a cryptographically strong
* algorithm.
*
* @param int $length Length of the string in bytes
*
* @return string|boolean Generated string of bytes on success, or FALSE on
* failure.
*/
public static function generateCryptoKey($length)
{
return openssl_random_pseudo_bytes($length);
}
/**
* Convert base 256 number to decimal number.
*
* @param string $number Base 256 number
*
* @return string Decimal number
*/
public static function base256ToDec($number)
{
Validate::canCastAsString($number, 'number');
$result = 0;
$base = 1;
for ($i = strlen($number) - 1; $i >= 0; $i--) {
$result = bcadd($result, bcmul(ord($number[$i]), $base));
$base = bcmul($base, 256);
}
return $result;
}
/**
* To evaluate if the stream is larger than a certain size. To restore
* the stream, it has to be seekable, so will return true if the stream
* is not seekable.
* @param StreamInterface $stream The stream to be evaluated.
* @param int $size The size if the string is larger than.
*
* @return boolean true if the stream is larger than the given size.
*/
public static function isStreamLargerThanSizeOrNotSeekable(StreamInterface $stream, $size)
{
Validate::isInteger($size, 'size');
Validate::isTrue(
$stream instanceof StreamInterface,
sprintf(Resources::INVALID_PARAM_MSG, 'stream', 'Psr\Http\Message\StreamInterface')
);
$result = true;
if ($stream->isSeekable()) {
$position = $stream->tell();
try {
$stream->seek($size);
} catch (\RuntimeException $e) {
$pos = strpos(
$e->getMessage(),
'to seek to stream position '
);
if ($pos == null) {
throw $e;
}
$result = false;
}
if ($stream->eof()) {
$result = false;
} elseif ($stream->read(1) == '') {
$result = false;
}
$stream->seek($position);
}
return $result;
}
/**
* Gets metadata array by parsing them from given headers.
*
* @param array $headers HTTP headers containing metadata elements.
*
* @return array
*/
public static function getMetadataArray(array $headers)
{
$metadata = array();
foreach ($headers as $key => $value) {
$isMetadataHeader = Utilities::startsWith(
strtolower($key),
Resources::X_MS_META_HEADER_PREFIX
);
if ($isMetadataHeader) {
// Metadata name is case-presrved and case insensitive
$MetadataName = str_ireplace(
Resources::X_MS_META_HEADER_PREFIX,
Resources::EMPTY_STRING,
$key
);
$metadata[$MetadataName] = $value;
}
}
return $metadata;
}
/**
* Validates the provided metadata array.
*
* @param array $metadata The metadata array.
*
* @return void
*/
public static function validateMetadata(array $metadata = null)
{
if (!is_null($metadata)) {
Validate::isArray($metadata, 'metadata');
} else {
$metadata = array();
}
foreach ($metadata as $key => $value) {
Validate::canCastAsString($key, 'metadata key');
Validate::canCastAsString($value, 'metadata value');
}
}
/**
* Append the content to file.
* @param string $path The file to append to.
* @param string $content The content to append.
*
* @return void
*/
public static function appendToFile($path, $content)
{
$resource = @fopen($path, 'a+');
if ($resource != null) {
fwrite($resource, $content);
fclose($resource);
}
}
/**
* Check if all the bytes are zero.
*
* @param string $content The content.
* @return bool
*/
public static function allZero($content)
{
$size = strlen($content);
// If all Zero, skip this range
for ($i = 0; $i < $size; $i++) {
if (ord($content[$i]) != 0) {
return false;
}
}
return true;
}
/**
* Append the delimiter to the string. The delimiter will not be added if
* the string already ends with this delimiter.
*
* @param string $string The string to add delimiter to.
* @param string $delimiter The delimiter to be added.
*
* @return string
*/
public static function appendDelimiter($string, $delimiter)
{
if (!self::endsWith($string, $delimiter)) {
$string .= $delimiter;
}
return $string;
}
/**
* Static function used to determine if the request is performed against
* secondary endpoint.
*
* @param Psr\Http\Message\RequestInterface $request The request performed.
* @param array $options The options of the
* request. Must contain
* Resources::ROS_SECONDARY_URI
*
* @return boolean
*/
public static function requestSentToSecondary(
\Psr\Http\Message\RequestInterface $request,
array $options
) {
$uri = $request->getUri();
$secondaryUri = $options[Resources::ROS_SECONDARY_URI];
$isSecondary = false;
if (strpos((string)$uri, (string)$secondaryUri) !== false) {
$isSecondary = true;
}
return $isSecondary;
}
/**
* Gets the location value from the headers.
*
* @param array $headers request/response headers.
*
* @return string
*/
public static function getLocationFromHeaders(array $headers)
{
$value = Utilities::tryGetValue(
$headers,
Resources::X_MS_CONTINUATION_LOCATION_MODE
);
$result = '';
if (\is_string($value)) {
$result = $value;
} elseif (!empty($value)) {
$result = $value[0];
}
return $result;
}
/**
* Gets if the value is a double value or string representation of a double
* value
*
* @param mixed $value The value to be verified.
*
* @return boolean
*/
public static function isDouble($value)
{
return is_numeric($value) && is_double($value + 0);
}
/**
* Calculates the content MD5 which is base64 encoded. This should be align
* with the server calculated MD5.
*
* @param string $content the content to be calculated.
*
* @return string
*/
public static function calculateContentMD5($content)
{
Validate::notNull($content, 'content');
Validate::canCastAsString($content, 'content');
return base64_encode(md5($content, true));
}
/**
* Return if the environment is in 64 bit PHP.
*
* @return bool
*/
public static function is64BitPHP()
{
return PHP_INT_SIZE == 8;
}
}
@@ -0,0 +1,461 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Internal;
use MicrosoftAzure\Storage\Common\Exceptions\InvalidArgumentTypeException;
/**
* Validates against a condition and throws an exception in case of failure.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class Validate
{
/**
* Throws exception if the provided variable type is not array.
*
* @param mixed $var The variable to check.
* @param string $name The parameter name.
*
* @throws InvalidArgumentTypeException.
*
* @return void
*/
public static function isArray($var, $name)
{
if (!is_array($var)) {
throw new InvalidArgumentTypeException(gettype(array()), $name);
}
}
/**
* Throws exception if the provided variable can not convert to a string.
*
* @param mixed $var The variable to check.
* @param string $name The parameter name.
*
* @throws InvalidArgumentTypeException
*
* @return void
*/
public static function canCastAsString($var, $name)
{
try {
(string)$var;
} catch (\Exception $e) {
throw new InvalidArgumentTypeException(gettype(''), $name);
}
}
/**
* Throws exception if the provided variable type is not boolean.
*
* @param mixed $var variable to check against.
*
* @throws InvalidArgumentTypeException
*
* @return void
*/
public static function isBoolean($var)
{
(bool)$var;
}
/**
* Throws exception if the provided variable is set to null.
*
* @param mixed $var The variable to check.
* @param string $name The parameter name.
*
* @throws \InvalidArgumentException
*
* @return void
*/
public static function notNullOrEmpty($var, $name)
{
if (is_null($var) || (empty($var) && $var != '0')) {
throw new \InvalidArgumentException(
sprintf(Resources::NULL_OR_EMPTY_MSG, $name)
);
}
}
/**
* Throws exception if the provided variable is not double.
*
* @param mixed $var The variable to check.
* @param string $name The parameter name.
*
* @throws \InvalidArgumentException
*
* @return void
*/
public static function isDouble($var, $name)
{
if (!is_numeric($var)) {
throw new InvalidArgumentTypeException('double', $name);
}
}
/**
* Throws exception if the provided variable type is not integer.
*
* @param mixed $var The variable to check.
* @param string $name The parameter name.
*
* @throws InvalidArgumentTypeException
*
* @return void
*/
public static function isInteger($var, $name)
{
try {
(int)$var;
} catch (\Exception $e) {
throw new InvalidArgumentTypeException(gettype(123), $name);
}
}
/**
* Returns whether the variable is an empty or null string.
*
* @param string $var value.
*
* @return boolean
*/
public static function isNullOrEmptyString($var)
{
try {
(string)$var;
} catch (\Exception $e) {
return false;
}
return (!isset($var) || trim($var)==='');
}
/**
* Throws exception if the provided condition is not satisfied.
*
* @param bool $isSatisfied condition result.
* @param string $failureMessage the exception message
*
* @throws \Exception
*
* @return void
*/
public static function isTrue($isSatisfied, $failureMessage)
{
if (!$isSatisfied) {
throw new \InvalidArgumentException($failureMessage);
}
}
/**
* Throws exception if the provided $date doesn't implement \DateTimeInterface
*
* @param mixed $date variable to check against.
*
* @throws InvalidArgumentTypeException
*
* @return void
*/
public static function isDate($date)
{
if (gettype($date) != 'object' || !($date instanceof \DateTimeInterface)) {
throw new InvalidArgumentTypeException('DateTimeInterface');
}
}
/**
* Throws exception if the provided variable is set to null.
*
* @param mixed $var The variable to check.
* @param string $name The parameter name.
*
* @throws \InvalidArgumentException
*
* @return void
*/
public static function notNull($var, $name)
{
if (is_null($var)) {
throw new \InvalidArgumentException(sprintf(Resources::NULL_MSG, $name));
}
}
/**
* Throws exception if the object is not of the specified class type.
*
* @param mixed $objectInstance An object that requires class type validation.
* @param mixed $classInstance The instance of the class the the
* object instance should be.
* @param string $name The name of the object.
*
* @throws \InvalidArgumentException
*
* @return void
*/
public static function isInstanceOf($objectInstance, $classInstance, $name)
{
Validate::notNull($classInstance, 'classInstance');
if (is_null($objectInstance)) {
return true;
}
$objectType = gettype($objectInstance);
$classType = gettype($classInstance);
if ($objectType === $classType) {
return true;
} else {
throw new \InvalidArgumentException(
sprintf(
Resources::INSTANCE_TYPE_VALIDATION_MSG,
$name,
$objectType,
$classType
)
);
}
}
/**
* Creates an anonymous function that checks if the given hostname is valid or not.
*
* @return callable
*/
public static function getIsValidHostname()
{
return function ($hostname) {
return Validate::isValidHostname($hostname);
};
}
/**
* Throws an exception if the string is not of a valid hostname.
*
* @param string $hostname String to check.
*
* @throws \InvalidArgumentException
*
* @return boolean
*/
public static function isValidHostname($hostname)
{
if (defined('FILTER_VALIDATE_DOMAIN')) {
$isValid = filter_var($hostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
} else {
// (less accurate) fallback for PHP < 7.0
$isValid = preg_match('/^[a-z0-9_-]+(\.[a-z0-9_-]+)*$/i', $hostname);
}
if ($isValid) {
return true;
} else {
throw new \RuntimeException(
sprintf(Resources::INVALID_CONFIG_HOSTNAME, $hostname)
);
}
}
/**
* Creates a anonymous function that check if the given uri is valid or not.
*
* @return callable
*/
public static function getIsValidUri()
{
return function ($uri) {
return Validate::isValidUri($uri);
};
}
/**
* Throws exception if the string is not of a valid uri.
*
* @param string $uri String to check.
*
* @throws \InvalidArgumentException
*
* @return boolean
*/
public static function isValidUri($uri)
{
$isValid = filter_var($uri, FILTER_VALIDATE_URL);
if ($isValid) {
return true;
} else {
throw new \RuntimeException(
sprintf(Resources::INVALID_CONFIG_URI, $uri)
);
}
}
/**
* Throws exception if the provided variable type is not object.
*
* @param mixed $var The variable to check.
* @param string $name The parameter name.
*
* @throws InvalidArgumentTypeException.
*
* @return boolean
*/
public static function isObject($var, $name)
{
if (!is_object($var)) {
throw new InvalidArgumentTypeException('object', $name);
}
return true;
}
/**
* Throws exception if the object is not of the specified class type.
*
* @param mixed $objectInstance An object that requires class type validation.
* @param string $class The class the object instance should be.
* @param string $name The parameter name.
*
* @throws \InvalidArgumentException
*
* @return boolean
*/
public static function isA($objectInstance, $class, $name)
{
Validate::canCastAsString($class, 'class');
Validate::notNull($objectInstance, 'objectInstance');
Validate::isObject($objectInstance, 'objectInstance');
$objectType = get_class($objectInstance);
if (is_a($objectInstance, $class)) {
return true;
} else {
throw new \InvalidArgumentException(
sprintf(
Resources::INSTANCE_TYPE_VALIDATION_MSG,
$name,
$objectType,
$class
)
);
}
}
/**
* Validate if method exists in object
*
* @param object $objectInstance An object that requires method existing
* validation
* @param string $method Method name
* @param string $name The parameter name
*
* @return boolean
*/
public static function methodExists($objectInstance, $method, $name)
{
Validate::canCastAsString($method, 'method');
Validate::notNull($objectInstance, 'objectInstance');
Validate::isObject($objectInstance, 'objectInstance');
if (method_exists($objectInstance, $method)) {
return true;
} else {
throw new \InvalidArgumentException(
sprintf(
Resources::ERROR_METHOD_NOT_FOUND,
$method,
$name
)
);
}
}
/**
* Validate if string is date formatted
*
* @param string $value Value to validate
* @param string $name Name of parameter to insert in erro message
*
* @throws \InvalidArgumentException
*
* @return boolean
*/
public static function isDateString($value, $name)
{
Validate::canCastAsString($value, 'value');
try {
new \DateTime($value);
return true;
} catch (\Exception $e) {
throw new \InvalidArgumentException(
sprintf(
Resources::ERROR_INVALID_DATE_STRING,
$name,
$value
)
);
}
}
/**
* Validate if the provided array has key, throw exception otherwise.
*
* @param string $key The key to be searched.
* @param string $name The name of the array.
* @param array $array The array to be validated.
*
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
*
* @return boolean
*/
public static function hasKey($key, $name, array $array)
{
Validate::isArray($array, $name);
if (!array_key_exists($key, $array)) {
throw new \UnexpectedValueException(
sprintf(
Resources::INVALID_VALUE_MSG,
$name,
sprintf(Resources::ERROR_KEY_NOT_EXIST, $key)
)
);
}
return true;
}
}
@@ -0,0 +1,53 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common;
/**
* Location mode for the service.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class LocationMode
{
//Request will only be sent to primary endpoint, except for
//getServiceStats APIs.
const PRIMARY_ONLY = 'PrimaryOnly';
//Request will only be sent to secondary endpoint.
const SECONDARY_ONLY = 'SecondaryOnly';
//Request will be sent to primary endpoint first, and retry for secondary
//endpoint.
const PRIMARY_THEN_SECONDARY = 'PrimaryThenSecondary';
//Request will be sent to secondary endpoint first, and retry for primary
//endpoint.
const SECONDARY_THEN_PRIMARY = 'SecondaryThenPrimary';
}
@@ -0,0 +1,77 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common;
use MicrosoftAzure\Storage\Common\Internal\Resources;
/**
* Logger class for debugging purpose.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class Logger
{
/**
* @var string
*/
private static $_filePath;
/**
* Logs $var to file.
*
* @param mixed $var The data to log.
* @param string $tip The help message.
*
* @return void
*/
public static function log($var, $tip = Resources::EMPTY_STRING)
{
if (!empty($tip)) {
error_log($tip . "\n", 3, self::$_filePath);
}
if (is_array($var) || is_object($var)) {
error_log(print_r($var, true), 3, self::$_filePath);
} else {
error_log($var . "\n", 3, self::$_filePath);
}
}
/**
* Sets file path to use.
*
* @param string $filePath The log file path.
* @return void
*/
public static function setLogFile($filePath)
{
self::$_filePath = $filePath;
}
}
@@ -0,0 +1,109 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @ignore
* @category Microsoft
* @package MicrosoftAzure\Storage\Common
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common;
use MicrosoftAzure\Storage\Common\Models\MarkerContinuationToken;
/**
* Trait implementing logic for continuation tokens that has nextMarker.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
trait MarkerContinuationTokenTrait
{
private $continuationToken;
/**
* Setter for continuationToken
*
* @param MarkerContinuationToken|null $continuationToken the continuation
* token to be set.
*/
public function setContinuationToken(MarkerContinuationToken $continuationToken = null)
{
$this->continuationToken = $continuationToken;
}
public function setMarker($marker)
{
if ($this->continuationToken == null) {
$this->continuationToken = new MarkerContinuationToken();
};
$this->continuationToken->setNextMarker($marker);
}
/**
* Getter for continuationToken
*
* @return MarkerContinuationToken
*/
public function getContinuationToken()
{
return $this->continuationToken;
}
/**
* Gets the next marker to list/query items.
*
* @return string
*/
public function getNextMarker()
{
if ($this->continuationToken == null) {
return null;
}
return $this->continuationToken->getNextMarker();
}
/**
* Gets for location for previous request.
*
* @return string
*/
public function getLocation()
{
if ($this->continuationToken == null) {
return null;
}
return $this->continuationToken->getLocation();
}
public function getLocationMode()
{
if ($this->continuationToken == null) {
return parent::getLocationMode();
} elseif ($this->continuationToken->getLocation() == '') {
return parent::getLocationMode();
} else {
return $this->getLocation();
}
}
}
@@ -0,0 +1,200 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
use MicrosoftAzure\Storage\Common\Internal\Validate;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
use MicrosoftAzure\Storage\Common\Internal\Serialization\MessageSerializer;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Promise\RejectedPromise;
/**
* This class provides the functionality to log the requests/options/responses.
* Logging large number of entries without providing a file path may exhaust
* the memory.
*
* The middleware should be pushed into client options if the logging is
* intended to persist between different API calls.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class HistoryMiddleware extends MiddlewareBase
{
private $history;
private $path;
private $count;
const TITLE_LENGTH = 120;
/**
* Gets the saved paried history.
*
* @return array
*/
public function getHistory()
{
return $this->history;
}
/**
* Constructor
*
* @param string $path the path to save the history. If path is provided,
* no data is going to be saved to memory and the
* entries are going to be serialized and saved to given
* path.
*
*/
public function __construct($path = '')
{
$this->history = array();
$this->path = $path;
$this->count = 0;
}
/**
* Add an entry to history
*
* @param array $entry the entry to be added.
*/
public function addHistory(array $entry)
{
if ($this->path !== '') {
$this->appendNewEntryToPath($entry);
} else {
Validate::isTrue(
array_key_exists('request', $entry) &&
array_key_exists('options', $entry) &&
(array_key_exists('response', $entry) ||
array_key_exists('reason', $entry)),
'Given history entry not in correct format'
);
$this->history[] = $entry;
}
++$this->count;
}
/**
* Clear the history
*
* @return void
*/
public function clearHistory()
{
$this->history = array();
$this->count = 0;
}
/**
* This function will be invoked after the request is sent, if
* the promise is fulfilled.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onFulfilled(RequestInterface $request, array $options)
{
$reflection = $this;
return function (ResponseInterface $response) use (
$reflection,
$request,
$options
) {
$reflection->addHistory([
'request' => $request,
'response' => $response,
'options' => $options
]);
return $response;
};
}
/**
* This function will be executed after the request is sent, if
* the promise is rejected.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onRejected(RequestInterface $request, array $options)
{
$reflection = $this;
return function ($reason) use (
$reflection,
$request,
$options
) {
$reflection->addHistory([
'request' => $request,
'reason' => $reason,
'options' => $options
]);
return new RejectedPromise($reason);
};
}
/**
* Append the new entry to saved file path.
*
* @param array $entry the entry to be added.
*
* @return void
*/
private function appendNewEntryToPath(array $entry)
{
$entryNoString = "Entry " . $this->count;
$delimiter = str_pad(
$entryNoString,
self::TITLE_LENGTH,
'-',
STR_PAD_BOTH
) . PHP_EOL;
$entryString = $delimiter;
$entryString .= sprintf(
"Time: %s\n",
(new \DateTime("now", new \DateTimeZone('UTC')))->format('Y-m-d H:i:s')
);
$entryString .= MessageSerializer::objectSerialize($entry['request']);
if (array_key_exists('reason', $entry)) {
$entryString .= MessageSerializer::objectSerialize($entry['reason']);
} elseif (array_key_exists('response', $entry)) {
$entryString .= MessageSerializer::objectSerialize($entry['response']);
}
$entryString .= $delimiter;
Utilities::appendToFile($this->path, $entryString);
}
}
@@ -0,0 +1,71 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
/**
* IMiddleware is called before sending the request and after receiving the
* response.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
interface IMiddleware
{
/**
* This function will return a callable with $request and $options as
* its parameters and returns a promise. The callable can modify the
* request, fulfilled response or rejected reason when invoked with certain
* conditions. Sample middleware implementation:
*
* ```
* return function (
* RequestInterface $request,
* array $options
* ) use ($handler) {
* //do something prior to sending the request.
* $promise = $handler($request, $options);
* return $promise->then(
* function (ResponseInterface $response) use ($request, $options) {
* //do something
* return $response;
* },
* function ($reason) use ($request, $options) {
* //do something
* return new GuzzleHttp\Promise\RejectedPromise($reason);
* }
* );
* };
* ```
*
* @param callable $handler The next handler.
* @return callable
*/
public function __invoke(callable $handler);
}
@@ -0,0 +1,115 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Promise\RejectedPromise;
/**
* This class provides the base structure of middleware that can be used for
* doing customized behavior including modifying the request, response or
* other behaviors like logging, retrying and debugging.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class MiddlewareBase implements IMiddleware
{
/**
* Middleware augments the functionality of handlers by invoking them
* in the process of generating responses. And it returns a function
* that accepts the next handler to invoke. Refer to
* http://docs.guzzlephp.org/en/latest/handlers-and-middleware.html#middleware
* for more detailed information.
*
* @param callable The handler function.
*
* @return callable The function that accepts the next handler to invoke.
*/
public function __invoke(callable $handler)
{
$reflection = $this;
return function ($request, $options) use ($handler, $reflection) {
$request = $reflection->onRequest($request);
return $handler($request, $options)->then(
$reflection->onFulfilled($request, $options),
$reflection->onRejected($request, $options)
);
};
}
/**
* This function will be executed before the request is sent.
*
* @param RequestInterface $request the request before altered.
*
* @return RequestInterface the request after altered.
*/
protected function onRequest(RequestInterface $request)
{
//do nothing
return $request;
}
/**
* This function will be invoked after the request is sent, if
* the promise is fulfilled.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onFulfilled(RequestInterface $request, array $options)
{
return function (ResponseInterface $response) {
//do nothing
return $response;
};
}
/**
* This function will be executed after the request is sent, if
* the promise is rejected.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onRejected(RequestInterface $request, array $options)
{
return function ($reason) {
//do nothing
return new RejectedPromise($reason);
};
}
}
@@ -0,0 +1,70 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
/**
* This class provides the stack that handles the logic of applying each
* middlewares to the request or the response.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class MiddlewareStack
{
private $middlewares = array();
/**
* Push the given middleware into the middleware stack.
*
* @param IMiddleware|callable $middleware The middleware to be pushed.
*
* @return void
*/
public function push($middleware)
{
array_unshift($this->middlewares, $middleware);
}
/**
* Apply the middlewares to the handler.
*
* @param callable $handler the handler to which the middleware applies.
*
* @return callable
*/
public function apply(callable $handler)
{
$result = $handler;
foreach ($this->middlewares as $middleware) {
$result = $middleware($result);
}
return $result;
}
}
@@ -0,0 +1,181 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
use MicrosoftAzure\Storage\Common\LocationMode;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Promise\RejectedPromise;
/**
* This class provides the functionality of a middleware that handles all the
* retry logic for the request.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class RetryMiddleware extends MiddlewareBase
{
private $intervalCalculator;
private $decider;
public function __construct(
callable $intervalCalculator,
callable $decider
) {
$this->intervalCalculator = $intervalCalculator;
$this->decider = $decider;
}
/**
* This function will be invoked after the request is sent, if
* the promise is fulfilled.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onFulfilled(RequestInterface $request, array $options)
{
return function (ResponseInterface $response) use ($request, $options) {
$isSecondary = Utilities::requestSentToSecondary($request, $options);
if (!isset($options['retries'])) {
$options['retries'] = 0;
}
if (call_user_func(
$this->decider,
$options['retries'],
$request,
$response,
null,
$isSecondary
)) {
return $this->retry($request, $options, $response);
}
//Add the header that indicates the endpoint to be used if
//continuation token is used for subsequent request.
if ($isSecondary) {
$response = $response->withHeader(
Resources::X_MS_CONTINUATION_LOCATION_MODE,
LocationMode::SECONDARY_ONLY
);
} else {
$response = $response->withHeader(
Resources::X_MS_CONTINUATION_LOCATION_MODE,
LocationMode::PRIMARY_ONLY
);
}
return $response;
};
}
/**
* This function will be executed after the request is sent, if
* the promise is rejected.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onRejected(RequestInterface $request, array $options)
{
return function ($reason) use ($request, $options) {
$isSecondary = Utilities::requestSentToSecondary($request, $options);
if (!isset($options['retries'])) {
$options['retries'] = 0;
}
if (call_user_func(
$this->decider,
$options['retries'],
$request,
null,
$reason,
$isSecondary
)) {
return $this->retry($request, $options);
}
return new RejectedPromise($reason);
};
}
/**
* This function does the real retry job.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
* @param ResponseInterface $response the response of the request
*
* @return callable
*/
private function retry(
RequestInterface $request,
array $options,
ResponseInterface $response = null
) {
$options['delay'] = call_user_func(
$this->intervalCalculator,
++$options['retries']
);
//Change the request URI according to the location mode.
if (array_key_exists(Resources::ROS_LOCATION_MODE, $options)) {
$locationMode = $options[Resources::ROS_LOCATION_MODE];
//If have RA-GRS enabled for the request, switch between
//primary and secondary.
if ($locationMode == LocationMode::PRIMARY_THEN_SECONDARY ||
$locationMode == LocationMode::SECONDARY_THEN_PRIMARY) {
$primaryUri = $options[Resources::ROS_PRIMARY_URI];
$secondaryUri = $options[Resources::ROS_SECONDARY_URI];
$target = $request->getRequestTarget();
if (Utilities::startsWith($target, '/')) {
$target = substr($target, 1);
$primaryUri = new Uri($primaryUri . $target);
$secondaryUri = new Uri($secondaryUri . $target);
}
//substitute the uri.
if ((string)$request->getUri() == (string)$primaryUri) {
$request = $request->withUri($secondaryUri);
} elseif ((string)$request->getUri() == (string)$secondaryUri) {
$request = $request->withUri($primaryUri);
}
}
}
$handler = $options[Resources::ROS_HANDLER];
return \call_user_func($handler, $request, $options);
}
}
@@ -0,0 +1,271 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Validate;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
/**
* This class provides static functions that creates retry handlers for Guzzle
* HTTP clients to handle retry policy.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class RetryMiddlewareFactory
{
//The interval will be increased linearly, the nth retry will have a
//wait time equal to n * interval.
const LINEAR_INTERVAL_ACCUMULATION = 'Linear';
//The interval will be increased exponentially, the nth retry will have a
//wait time equal to pow(2, n) * interval.
const EXPONENTIAL_INTERVAL_ACCUMULATION = 'Exponential';
//This is for the general type of logic that handles retry.
const GENERAL_RETRY_TYPE = 'General';
//This is for the append blob retry only.
const APPEND_BLOB_RETRY_TYPE = 'Append Blob Retry';
/**
* Create the retry handler for the Guzzle client, according to the given
* attributes.
*
* @param string $type The type that controls the logic of
* the decider of the retry handler.
* Possible value can be
* self::GENERAL_RETRY_TYPE or
* self::APPEND_BLOB_RETRY_TYPE
* @param int $numberOfRetries The maximum number of retries.
* @param int $interval The minimum interval between each retry
* @param string $accumulationMethod If the interval increases linearly or
* exponentially.
* Possible value can be
* self::LINEAR_INTERVAL_ACCUMULATION or
* self::EXPONENTIAL_INTERVAL_ACCUMULATION
* @param bool $retryConnect Whether to retry on connection failures.
* @return RetryMiddleware A RetryMiddleware object that contains
* the logic of how the request should be
* handled after a response.
*/
public static function create(
$type = self::GENERAL_RETRY_TYPE,
$numberOfRetries = Resources::DEFAULT_NUMBER_OF_RETRIES,
$interval = Resources::DEFAULT_RETRY_INTERVAL,
$accumulationMethod = self::LINEAR_INTERVAL_ACCUMULATION,
$retryConnect = false
) {
//Validate the input parameters
//type
Validate::isTrue(
$type == self::GENERAL_RETRY_TYPE ||
$type == self::APPEND_BLOB_RETRY_TYPE,
sprintf(
Resources::INVALID_PARAM_GENERAL,
'type'
)
);
//numberOfRetries
Validate::isTrue(
$numberOfRetries > 0,
sprintf(
Resources::INVALID_NEGATIVE_PARAM,
'numberOfRetries'
)
);
//interval
Validate::isTrue(
$interval > 0,
sprintf(
Resources::INVALID_NEGATIVE_PARAM,
'interval'
)
);
//accumulationMethod
Validate::isTrue(
$accumulationMethod == self::LINEAR_INTERVAL_ACCUMULATION ||
$accumulationMethod == self::EXPONENTIAL_INTERVAL_ACCUMULATION,
sprintf(
Resources::INVALID_PARAM_GENERAL,
'accumulationMethod'
)
);
//retryConnect
Validate::isBoolean($retryConnect);
//Get the interval calculator according to the type of the
//accumulation method.
$intervalCalculator =
$accumulationMethod == self::LINEAR_INTERVAL_ACCUMULATION ?
static::createLinearDelayCalculator($interval) :
static::createExponentialDelayCalculator($interval);
//Get the retry decider according to the type of the retry and
//the number of retries.
$retryDecider = static::createRetryDecider($type, $numberOfRetries, $retryConnect);
//construct the retry middle ware.
return new RetryMiddleware($intervalCalculator, $retryDecider);
}
/**
* Create the retry decider for the retry handler. It will return a callable
* that accepts the number of retries, the request, the response and the
* exception, and return the decision for a retry.
*
* @param string $type The type of the retry handler.
* @param int $maxRetries The maximum number of retries to be done.
* @param bool $retryConnect Whether to retry on connection failures.
*
* @return callable The callable that will return if the request should
* be retried.
*/
protected static function createRetryDecider($type, $maxRetries, $retryConnect)
{
return function (
$retries,
$request,
$response = null,
$exception = null,
$isSecondary = false
) use (
$type,
$maxRetries,
$retryConnect
) {
//Exceeds the retry limit. No retry.
if ($retries >= $maxRetries) {
return false;
}
if (!$response) {
if (!$exception || !($exception instanceof RequestException)) {
return false;
} elseif ($exception instanceof ConnectException) {
return $retryConnect;
} else {
$response = $exception->getResponse();
if (!$response) {
return true;
}
}
}
if ($type == self::GENERAL_RETRY_TYPE) {
return static::generalRetryDecider(
$response->getStatusCode(),
$isSecondary
);
} else {
return static::appendBlobRetryDecider(
$response->getStatusCode(),
$isSecondary
);
}
return true;
};
}
/**
* Decide if the given status code indicate the request should be retried.
*
* @param int $statusCode Status code of the previous request.
* @param bool $isSecondary Whether the request is sent to secondary endpoint.
*
* @return bool true if the request should be retried.
*/
protected static function generalRetryDecider($statusCode, $isSecondary)
{
$retry = false;
if ($statusCode == 408) {
$retry = true;
} elseif ($statusCode >= 500) {
if ($statusCode != 501 && $statusCode != 505) {
$retry = true;
}
} elseif ($isSecondary && $statusCode == 404) {
$retry = true;
}
return $retry;
}
/**
* Decide if the given status code indicate the request should be retried.
* This is for append blob.
*
* @param int $statusCode Status code of the previous request.
* @param bool $isSecondary Whether the request is sent to secondary endpoint.
*
* @return bool true if the request should be retried.
*/
protected static function appendBlobRetryDecider($statusCode, $isSecondary)
{
//The retry logic is different for append blob.
//First it will need to record the former status code if it is
//server error. Then if the following request is 412 then it
//needs to be retried. Currently this is not implemented so will
//only adapt to the general retry decider.
//TODO: add logic for append blob's retry when implemented.
$retry = static::generalRetryDecider($statusCode, $isSecondary);
return $retry;
}
/**
* Create the delay calculator that increases the interval linearly
* according to the number of retries.
*
* @param int $interval the minimum interval of the retry.
*
* @return callable a calculator that will return the interval
* according to the number of retries.
*/
protected static function createLinearDelayCalculator($interval)
{
return function ($retries) use ($interval) {
return $retries * $interval;
};
}
/**
* Create the delay calculator that increases the interval exponentially
* according to the number of retries.
*
* @param int $interval the minimum interval of the retry.
*
* @return callable a calculator that will return the interval
* according to the number of retries.
*/
protected static function createExponentialDelayCalculator($interval)
{
return function ($retries) use ($interval) {
return $interval * ((int)\pow(2, $retries));
};
}
}
@@ -0,0 +1,218 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
use MicrosoftAzure\Storage\Common\Internal\Validate;
use MicrosoftAzure\Storage\Common\Internal\Resources;
/**
* Holds access policy elements
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
abstract class AccessPolicy
{
private $start;
private $expiry;
private $permission;
private $resourceType;
/**
* Get the valid permissions for the given resource.
*
* @return array
*/
abstract protected static function getResourceValidPermissions();
/**
* Constructor
*
* @param string $resourceType the resource type of this access policy.
*/
public function __construct($resourceType)
{
Validate::canCastAsString($resourceType, 'resourceType');
Validate::isTrue(
$resourceType == Resources::RESOURCE_TYPE_BLOB ||
$resourceType == Resources::RESOURCE_TYPE_CONTAINER ||
$resourceType == Resources::RESOURCE_TYPE_QUEUE ||
$resourceType == Resources::RESOURCE_TYPE_TABLE ||
$resourceType == Resources::RESOURCE_TYPE_FILE ||
$resourceType == Resources::RESOURCE_TYPE_SHARE,
Resources::ERROR_RESOURCE_TYPE_NOT_SUPPORTED
);
$this->resourceType = $resourceType;
}
/**
* Gets start.
*
* @return \DateTime.
*/
public function getStart()
{
return $this->start;
}
/**
* Sets start.
*
* @param \DateTime $start value.
*
* @return void
*/
public function setStart(\DateTime $start = null)
{
if ($start != null) {
Validate::isDate($start);
}
$this->start = $start;
}
/**
* Gets expiry.
*
* @return \DateTime.
*/
public function getExpiry()
{
return $this->expiry;
}
/**
* Sets expiry.
*
* @param \DateTime $expiry value.
*
* @return void
*/
public function setExpiry($expiry)
{
Validate::isDate($expiry);
$this->expiry = $expiry;
}
/**
* Gets permission.
*
* @return string.
*/
public function getPermission()
{
return $this->permission;
}
/**
* Sets permission.
*
* @param string $permission value.
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPermission($permission)
{
$this->permission = $this->validatePermission($permission);
}
/**
* Gets resource type.
*
* @return string.
*/
public function getResourceType()
{
return $this->resourceType;
}
/**
* Validate the permission against its corresponding allowed permissions
*
* @param string $permission The permission to be validated.
*
* @throws \InvalidArgumentException
*
* @return string
*/
private function validatePermission($permission)
{
$validPermissions = static::getResourceValidPermissions();
$result = '';
foreach ($validPermissions as $validPermission) {
if (strpos($permission, $validPermission) !== false) {
//append the valid permission to result.
$result .= $validPermission;
//remove all the character that represents the permission.
$permission = str_replace(
$validPermission,
'',
$permission
);
}
}
//After filtering all the permissions, if there is still characters
//left in the given permission, throw exception.
Validate::isTrue(
$permission == '',
sprintf(
Resources::INVALID_PERMISSION_PROVIDED,
$this->getResourceType(),
implode(', ', $validPermissions)
)
);
return $result;
}
/**
* Converts this current object to XML representation.
*
* @internal
*
* @return array
*/
public function toArray()
{
$array = array();
if ($this->getStart() != null) {
$array[Resources::XTAG_SIGNED_START] =
Utilities::convertToEdmDateTime($this->getStart());
}
$array[Resources::XTAG_SIGNED_EXPIRY] =
Utilities::convertToEdmDateTime($this->getExpiry());
$array[Resources::XTAG_SIGNED_PERMISSION] = $this->getPermission();
return $array;
}
}
@@ -0,0 +1,269 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Validate;
/**
* Provides functionality and data structure for Cross-Origin Resource Sharing
* rules.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class CORS
{
private $allowedOrigins;
private $allowedMethods;
private $allowedHeaders;
private $exposedHeaders;
private $maxAgeInSeconds;
/**
* Constructor of the class.
*
* @param string[] $allowedOrigins The origin domains that are permitted
* to make request against the storage
* service via CORS.
* @param string[] $allowedMethods The methods (HTTP request verbs) that
* the origin domain may use for a CORS
* request.
* @param string[] $allowedHeaders The request headers that the origin
* domain may specify on the CORS request.
* @param string[] $exposedHeaders The response headers that may be sent in
* the response to the CORS request and
* exposed by the browser to the request
* issuer.
* @param int $maxAgeInSeconds The maximum amount of time that a
* browser should cache the preflight
* OPTIONS request.
*/
public function __construct(
array $allowedOrigins,
array $allowedMethods,
array $allowedHeaders,
array $exposedHeaders,
$maxAgeInSeconds
) {
$this->setAllowedOrigins($allowedOrigins);
$this->setAllowedMethods($allowedMethods);
$this->setAllowedHeaders($allowedHeaders);
$this->setExposedHeaders($exposedHeaders);
$this->setMaxedAgeInSeconds($maxAgeInSeconds);
}
/**
* Create an instance with parsed XML response with 'CORS' root.
*
* @param array $parsedResponse The response used to create an instance.
*
* @internal
*
* @return CORS
*/
public static function create(array $parsedResponse)
{
Validate::hasKey(
Resources::XTAG_ALLOWED_ORIGINS,
'parsedResponse',
$parsedResponse
);
Validate::hasKey(
Resources::XTAG_ALLOWED_METHODS,
'parsedResponse',
$parsedResponse
);
Validate::hasKey(
Resources::XTAG_ALLOWED_HEADERS,
'parsedResponse',
$parsedResponse
);
Validate::hasKey(
Resources::XTAG_EXPOSED_HEADERS,
'parsedResponse',
$parsedResponse
);
Validate::hasKey(
Resources::XTAG_MAX_AGE_IN_SECONDS,
'parsedResponse',
$parsedResponse
);
// Get the values from the parsed response.
$allowedOrigins = array_filter(explode(
',',
$parsedResponse[Resources::XTAG_ALLOWED_ORIGINS]
));
$allowedMethods = array_filter(explode(
',',
$parsedResponse[Resources::XTAG_ALLOWED_METHODS]
));
$allowedHeaders = array_filter(explode(
',',
$parsedResponse[Resources::XTAG_ALLOWED_HEADERS]
));
$exposedHeaders = array_filter(explode(
',',
$parsedResponse[Resources::XTAG_EXPOSED_HEADERS]
));
$maxAgeInSeconds = intval(
$parsedResponse[Resources::XTAG_MAX_AGE_IN_SECONDS]
);
return new CORS(
$allowedOrigins,
$allowedMethods,
$allowedHeaders,
$exposedHeaders,
$maxAgeInSeconds
);
}
/**
* Converts this object to array with XML tags
*
* @return array
*/
public function toArray()
{
return array(
Resources::XTAG_ALLOWED_ORIGINS =>
implode(',', $this->getAllowedOrigins()),
Resources::XTAG_ALLOWED_METHODS =>
implode(',', $this->getAllowedMethods()),
Resources::XTAG_ALLOWED_HEADERS =>
implode(',', $this->getAllowedHeaders()),
Resources::XTAG_EXPOSED_HEADERS =>
implode(',', $this->getExposedHeaders()),
Resources::XTAG_MAX_AGE_IN_SECONDS =>
$this->getMaxedAgeInSeconds()
);
}
/**
* Setter for allowedOrigins
*
* @param string[] $allowedOrigins the allowed origins to be set.
*/
public function setAllowedOrigins(array $allowedOrigins)
{
$this->allowedOrigins = $allowedOrigins;
}
/**
* Getter for allowedOrigins
*
* @return string[]
*/
public function getAllowedOrigins()
{
return $this->allowedOrigins;
}
/**
* Setter for allowedMethods
*
* @param string[] $allowedMethods the allowed methods to be set.
*/
public function setAllowedMethods(array $allowedMethods)
{
$this->allowedMethods = $allowedMethods;
}
/**
* Getter for allowedMethods
*
* @return string[]
*/
public function getAllowedMethods()
{
return $this->allowedMethods;
}
/**
* Setter for allowedHeaders
*
* @param string[] $allowedHeaders the allowed headers to be set.
*/
public function setAllowedHeaders(array $allowedHeaders)
{
$this->allowedHeaders = $allowedHeaders;
}
/**
* Getter for allowedHeaders
*
* @return string[]
*/
public function getAllowedHeaders()
{
return $this->allowedHeaders;
}
/**
* Setter for exposedHeaders
*
* @param string[] $exposedHeaders the exposed headers to be set.
*/
public function setExposedHeaders(array $exposedHeaders)
{
$this->exposedHeaders = $exposedHeaders;
}
/**
* Getter for exposedHeaders
*
* @return string[]
*/
public function getExposedHeaders()
{
return $this->exposedHeaders;
}
/**
* Setter for maxAgeInSeconds
*
* @param int $maxAgeInSeconds the max age in seconds to be set.
*/
public function setMaxedAgeInSeconds($maxAgeInSeconds)
{
$this->maxAgeInSeconds = $maxAgeInSeconds;
}
/**
* Getter for maxAgeInSeconds
*
* @return int
*/
public function getMaxedAgeInSeconds()
{
return $this->maxAgeInSeconds;
}
}
@@ -0,0 +1,82 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
use MicrosoftAzure\Storage\Common\Internal\Validate;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\LocationMode;
/**
* Provides functionality and data structure for continuation token.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class ContinuationToken
{
private $location;
public function __construct(
$location = ''
) {
$this->setLocation($location);
}
/**
* Setter for location
*
* @param string $location the location to be set.
*/
public function setLocation($location)
{
Validate::canCastAsString($location, 'location');
Validate::isTrue(
$location == LocationMode::PRIMARY_ONLY ||
$location == LocationMode::SECONDARY_ONLY ||
$location == '',
sprintf(
Resources::INVALID_VALUE_MSG,
'location',
LocationMode::PRIMARY_ONLY . ' or ' . LocationMode::SECONDARY_ONLY
)
);
$this->location = $location;
}
/**
* Getter for location
*
* @return string
*/
public function getLocation()
{
return $this->location;
}
}
@@ -0,0 +1,78 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
/**
* Result from calling GetServiceProperties REST wrapper.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class GetServicePropertiesResult
{
private $_serviceProperties;
/**
* Creates object from $parsedResponse.
*
* @internal
* @param array $parsedResponse XML response parsed into array.
*
* @return \MicrosoftAzure\Storage\Common\Models\GetServicePropertiesResult
*/
public static function create(array $parsedResponse)
{
$result = new GetServicePropertiesResult();
$result->setValue(ServiceProperties::create($parsedResponse));
return $result;
}
/**
* Gets service properties object.
*
* @return \MicrosoftAzure\Storage\Common\Models\ServiceProperties
*/
public function getValue()
{
return $this->_serviceProperties;
}
/**
* Sets service properties object.
*
* @param ServiceProperties $serviceProperties object to use.
*
* @return void
*/
protected function setValue($serviceProperties)
{
$this->_serviceProperties = clone $serviceProperties;
}
}
@@ -0,0 +1,118 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
/**
* Result from calling get service stats REST wrapper.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class GetServiceStatsResult
{
private $status;
private $lastSyncTime;
/**
* Creates object from $parsedResponse.
*
* @internal
* @param array $parsedResponse XML response parsed into array.
*
* @return \MicrosoftAzure\Storage\Common\Models\GetServiceStatsResult
*/
public static function create(array $parsedResponse)
{
$result = new GetServiceStatsResult();
if (Utilities::arrayKeyExistsInsensitive(
Resources::XTAG_GEO_REPLICATION,
$parsedResponse
)) {
$geoReplication = $parsedResponse[Resources::XTAG_GEO_REPLICATION];
if (Utilities::arrayKeyExistsInsensitive(
Resources::XTAG_STATUS,
$geoReplication
)) {
$result->setStatus($geoReplication[Resources::XTAG_STATUS]);
}
if (Utilities::arrayKeyExistsInsensitive(
Resources::XTAG_LAST_SYNC_TIME,
$geoReplication
)) {
$lastSyncTime = $geoReplication[Resources::XTAG_LAST_SYNC_TIME];
$result->setLastSyncTime(Utilities::convertToDateTime($lastSyncTime));
}
}
return $result;
}
/**
* Gets status of the result.
*
* @return string
*/
public function getStatus()
{
return $this->status;
}
/**
* Gets the last sync time.
* @return \DateTime
*/
public function getLastSyncTime()
{
return $this->lastSyncTime;
}
/**
* Sets status of the result.
*
* @return void
*/
protected function setStatus($status)
{
$this->status = $status;
}
/**
* Sets the last sync time.
*
* @return void
*/
protected function setLastSyncTime(\DateTime $lastSyncTime)
{
$this->lastSyncTime = $lastSyncTime;
}
}
@@ -0,0 +1,198 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
/**
* Holds elements of queue properties logging field.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class Logging
{
private $_version;
private $_delete;
private $_read;
private $_write;
private $_retentionPolicy;
/**
* Creates object from $parsedResponse.
*
* @internal
* @param array $parsedResponse XML response parsed into array.
*
* @return Logging
*/
public static function create(array $parsedResponse)
{
$result = new Logging();
$result->setVersion($parsedResponse['Version']);
$result->setDelete(Utilities::toBoolean($parsedResponse['Delete']));
$result->setRead(Utilities::toBoolean($parsedResponse['Read']));
$result->setWrite(Utilities::toBoolean($parsedResponse['Write']));
$result->setRetentionPolicy(
RetentionPolicy::create($parsedResponse['RetentionPolicy'])
);
return $result;
}
/**
* Gets the retention policy
*
* @return MicrosoftAzure\Storage\Common\Models\RetentionPolicy
*
*/
public function getRetentionPolicy()
{
return $this->_retentionPolicy;
}
/**
* Sets retention policy
*
* @param RetentionPolicy $policy object to use
*
* @return void
*/
public function setRetentionPolicy(RetentionPolicy $policy)
{
$this->_retentionPolicy = $policy;
}
/**
* Gets whether all write requests should be logged.
*
* @return bool.
*/
public function getWrite()
{
return $this->_write;
}
/**
* Sets whether all write requests should be logged.
*
* @param bool $write new value.
*
* @return void
*/
public function setWrite($write)
{
$this->_write = $write;
}
/**
* Gets whether all read requests should be logged.
*
* @return bool
*/
public function getRead()
{
return $this->_read;
}
/**
* Sets whether all read requests should be logged.
*
* @param bool $read new value.
*
* @return void
*/
public function setRead($read)
{
$this->_read = $read;
}
/**
* Gets whether all delete requests should be logged.
*
* @return void
*/
public function getDelete()
{
return $this->_delete;
}
/**
* Sets whether all delete requests should be logged.
*
* @param bool $delete new value.
*
* @return void
*/
public function setDelete($delete)
{
$this->_delete = $delete;
}
/**
* Gets the version of Storage Analytics to configure
*
* @return string
*/
public function getVersion()
{
return $this->_version;
}
/**
* Sets the version of Storage Analytics to configure
*
* @param string $version new value.
*
* @return void
*/
public function setVersion($version)
{
$this->_version = $version;
}
/**
* Converts this object to array with XML tags
*
* @internal
* @return array
*/
public function toArray()
{
return array(
'Version' => $this->_version,
'Delete' => Utilities::booleanToString($this->_delete),
'Read' => Utilities::booleanToString($this->_read),
'Write' => Utilities::booleanToString($this->_write),
'RetentionPolicy' => !empty($this->_retentionPolicy)
? $this->_retentionPolicy->toArray()
: null
);
}
}
@@ -0,0 +1,72 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
use MicrosoftAzure\Storage\Common\Internal\Validate;
/**
* Provides functionality and data structure for continuation token that
* contains next marker.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class MarkerContinuationToken extends ContinuationToken
{
private $nextMarker;
public function __construct(
$nextMarker = '',
$location = ''
) {
parent::__construct($location);
$this->setNextMarker($nextMarker);
}
/**
* Setter for nextMarker
*
* @param string $nextMarker the next marker to be set.
*/
public function setNextMarker($nextMarker)
{
Validate::canCastAsString($nextMarker, 'nextMarker');
$this->nextMarker = $nextMarker;
}
/**
* Getter for nextMarker
*
* @return string
*/
public function getNextMarker()
{
return $this->nextMarker;
}
}
@@ -0,0 +1,181 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
/**
* Holds elements of queue properties metrics field.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class Metrics
{
private $_version;
private $_enabled;
private $_includeAPIs;
private $_retentionPolicy;
/**
* Creates object from $parsedResponse.
*
* @internal
* @param array $parsedResponse XML response parsed into array.
*
* @return Metrics
*/
public static function create(array $parsedResponse)
{
$result = new Metrics();
$result->setVersion($parsedResponse['Version']);
$result->setEnabled(Utilities::toBoolean($parsedResponse['Enabled']));
if ($result->getEnabled()) {
$result->setIncludeAPIs(
Utilities::toBoolean($parsedResponse['IncludeAPIs'])
);
}
$result->setRetentionPolicy(
RetentionPolicy::create($parsedResponse['RetentionPolicy'])
);
return $result;
}
/**
* Gets retention policy
*
* @return RetentionPolicy
*
*/
public function getRetentionPolicy()
{
return $this->_retentionPolicy;
}
/**
* Sets retention policy
*
* @param RetentionPolicy $policy object to use
*
* @return void
*/
public function setRetentionPolicy(RetentionPolicy $policy)
{
$this->_retentionPolicy = $policy;
}
/**
* Gets include APIs.
*
* @return bool
*/
public function getIncludeAPIs()
{
return $this->_includeAPIs;
}
/**
* Sets include APIs.
*
* @param bool $includeAPIs value to use.
*
* @return void
*/
public function setIncludeAPIs($includeAPIs)
{
$this->_includeAPIs = $includeAPIs;
}
/**
* Gets enabled.
*
* @return bool
*/
public function getEnabled()
{
return $this->_enabled;
}
/**
* Sets enabled.
*
* @param bool $enabled value to use.
*
* @return void
*/
public function setEnabled($enabled)
{
$this->_enabled = $enabled;
}
/**
* Gets version
*
* @return string
*/
public function getVersion()
{
return $this->_version;
}
/**
* Sets version
*
* @param string $version new value.
*
* @return void
*/
public function setVersion($version)
{
$this->_version = $version;
}
/**
* Converts this object to array with XML tags
*
* @internal
* @return array
*/
public function toArray()
{
$array = array(
'Version' => $this->_version,
'Enabled' => Utilities::booleanToString($this->_enabled)
);
if ($this->_enabled) {
$array['IncludeAPIs'] = Utilities::booleanToString($this->_includeAPIs);
}
$array['RetentionPolicy'] = !empty($this->_retentionPolicy)
? $this->_retentionPolicy->toArray()
: null;
return $array;
}
}
@@ -0,0 +1,142 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
/**
* Holds info about resource+ range used in HTTP requests
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class Range
{
private $start;
private $end;
/**
* Constructor
*
* @param integer $start the resource start value
* @param integer $end the resource end value
*
* @return Range
*/
public function __construct($start, $end = null)
{
$this->start = $start;
$this->end = $end;
}
/**
* Sets resource start range
*
* @param integer $start the resource range start
*
* @return void
*/
public function setStart($start)
{
$this->start = $start;
}
/**
* Gets resource start range
*
* @return integer
*/
public function getStart()
{
return $this->start;
}
/**
* Sets resource end range
*
* @param integer $end the resource range end
*
* @return void
*/
public function setEnd($end)
{
$this->end = $end;
}
/**
* Gets resource end range
*
* @return integer
*/
public function getEnd()
{
return $this->end;
}
/**
* Gets resource range length
*
* @return integer
*/
public function getLength()
{
if ($this->end != null) {
return $this->end - $this->start + 1;
} else {
return null;
}
}
/**
* Sets resource range length
*
* @param integer $value new resource range
*
* @return void
*/
public function setLength($value)
{
$this->end = $this->start + $value - 1;
}
/**
* Constructs the range string according to the set start and end
*
* @return string
*/
public function getRangeString()
{
$rangeString = '';
$rangeString .= ('bytes=' . $this->start . '-');
if ($this->end != null) {
$rangeString .= $this->end;
}
return $rangeString;
}
}
@@ -0,0 +1,75 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
/**
* Holds info about page blob range diffs
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class RangeDiff extends Range
{
private $isClearedPageRange;
/**
* Constructor
*
* @param integer $start the resource start value
* @param integer $end the resource end value
* @param bool $isClearedPageRange true if the page range is a cleared range, false otherwise.
*/
public function __construct($start, $end = null, $isClearedPageRange = false)
{
parent::__construct($start, $end);
$this->isClearedPageRange = $isClearedPageRange;
}
/**
* True if the page range is a cleared range, false otherwise
*
* @return bool
*/
public function isClearedPageRange()
{
return $this->isClearedPageRange;
}
/**
* Sets the isClearedPageRange property
*
* @param bool $isClearedPageRange
*
* @return bool
*/
public function setIsClearedPageRange($isClearedPageRange)
{
$this->isClearedPageRange = $isClearedPageRange;
}
}
@@ -0,0 +1,124 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
/**
* Holds elements of queue properties retention policy field.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class RetentionPolicy
{
private $_enabled;
private $_days;
/**
* Creates object from $parsedResponse.
*
* @param array $parsedResponse XML response parsed into array.
*
* @internal
*
* @return MicrosoftAzure\Storage\Common\Models\RetentionPolicy
*/
public static function create(array $parsedResponse = null)
{
$result = new RetentionPolicy();
$result->setEnabled(Utilities::toBoolean($parsedResponse['Enabled']));
if ($result->getEnabled()) {
$result->setDays(intval($parsedResponse['Days']));
}
return $result;
}
/**
* Gets enabled.
*
* @return bool
*/
public function getEnabled()
{
return $this->_enabled;
}
/**
* Sets enabled.
*
* @param bool $enabled value to use.
*
* @return void
*/
public function setEnabled($enabled)
{
$this->_enabled = $enabled;
}
/**
* Gets days field.
*
* @return int
*/
public function getDays()
{
return $this->_days;
}
/**
* Sets days field.
*
* @param int $days value to use.
*
* @return void
*/
public function setDays($days)
{
$this->_days = $days;
}
/**
* Converts this object to array with XML tags
*
* @internal
*
* @return array
*/
public function toArray()
{
$array = array('Enabled' => Utilities::booleanToString($this->_enabled));
if (isset($this->_days)) {
$array['Days'] = strval($this->_days);
}
return $array;
}
}
@@ -0,0 +1,309 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
use MicrosoftAzure\Storage\Common\LocationMode;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Validate;
use MicrosoftAzure\Storage\Common\Middlewares\MiddlewareStack;
use MicrosoftAzure\Storage\Common\Middlewares\IMiddleware;
/**
* This class provides the base structure of service options, granting user to
* send with different options for each individual API call.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class ServiceOptions
{
/**
* The middlewares to be applied using the operation.
* @internal
*/
protected $middlewares;
/**
* The middleware stack used for the operation.
* @internal
*/
protected $middlewareStack;
/**
* The number of concurrency when performing concurrent requests.
* @internal
*/
protected $numberOfConcurrency;
/**
* If streamming is used for the operation.
* @internal
*/
protected $isStreaming;
/**
* The location mode of the operation.
* @internal
*/
protected $locationMode;
/**
* If to decode the content of the response body.
* @internal
*/
protected $decodeContent;
/**
* The timeout of the operation
* @internal
*/
protected $timeout;
/**
* Initialize the properties to default value.
*/
public function __construct(ServiceOptions $options = null)
{
if ($options == null) {
$this->setNumberOfConcurrency(Resources::NUMBER_OF_CONCURRENCY);
$this->setLocationMode(LocationMode::PRIMARY_ONLY);
$this->setIsStreaming(false);
$this->setDecodeContent(false);
$this->middlewares = array();
$this->middlewareStack = null;
} else {
$this->setNumberOfConcurrency($options->getNumberOfConcurrency());
$this->setLocationMode($options->getLocationMode());
$this->setIsStreaming($options->getIsStreaming());
$this->setDecodeContent($options->getDecodeContent());
$this->middlewares = $options->getMiddlewares();
$this->middlewareStack = $options->getMiddlewareStack();
}
}
/**
* Push a middleware into the middlewares.
* @param callable|IMiddleware $middleware middleware to be pushed.
*
* @return void
*/
public function pushMiddleware($middleware)
{
self::validateIsMiddleware($middleware);
$this->middlewares[] = $middleware;
}
/**
* Gets the middlewares.
*
* @return array
*/
public function getMiddlewares()
{
return $this->middlewares;
}
/**
* Sets middlewares.
*
* @param array $middlewares value.
*
* @return void
*/
public function setMiddlewares(array $middlewares)
{
foreach ($middlewares as $middleware) {
self::validateIsMiddleware($middleware);
}
$this->middlewares = $middlewares;
}
/**
* Gets the middleware stack
*
* @return MiddlewareStack
*/
public function getMiddlewareStack()
{
return $this->middlewareStack;
}
/**
* Sets the middleware stack.
*
* @param MiddlewareStack $middlewareStack value.
*
* @return void
*/
public function setMiddlewareStack(MiddlewareStack $middlewareStack)
{
$this->middlewareStack = $middlewareStack;
}
/**
* Gets the number of concurrency value
*
* @return int
*/
public function getNumberOfConcurrency()
{
return $this->numberOfConcurrency;
}
/**
* Sets number of concurrency.
*
* @param int $numberOfConcurrency value.
*
* @return void
*/
public function setNumberOfConcurrency($numberOfConcurrency)
{
$this->numberOfConcurrency = $numberOfConcurrency;
}
/**
* Gets the isStreaming value
*
* @return bool
*/
public function getIsStreaming()
{
return $this->isStreaming;
}
/**
* Sets isStreaming.
*
* @param bool $isStreaming value.
*
* @return void
*/
public function setIsStreaming($isStreaming)
{
$this->isStreaming = $isStreaming;
}
/**
* Gets the locationMode value
*
* @return string
*/
public function getLocationMode()
{
return $this->locationMode;
}
/**
* Sets locationMode.
*
* @param string $locationMode value.
*
* @return void
*/
public function setLocationMode($locationMode)
{
$this->locationMode = $locationMode;
}
/**
* Gets the decodeContent value
*
* @return bool
*/
public function getDecodeContent()
{
return $this->decodeContent;
}
/**
* Sets decodeContent.
*
* @param bool $decodeContent value.
*
* @return void
*/
public function setDecodeContent($decodeContent)
{
$this->decodeContent = $decodeContent;
}
/**
* Gets the timeout value
*
* @return string
*/
public function getTimeout()
{
return $this->timeout;
}
/**
* Sets timeout.
*
* @param string $timeout value.
*
* @return void
*/
public function setTimeout($timeout)
{
$this->timeout = $timeout;
}
/**
* Generate request options using the input options and saved properties.
*
* @param array $options The options to be merged for the request options.
*
* @return array
*/
public function generateRequestOptions(array $options)
{
$result = array();
return $result;
}
/**
* Validate if the given middleware is of callable or IMiddleware.
*
* @param void $middleware the middleware to be validated.
*
* @return void
*/
private static function validateIsMiddleware($middleware)
{
if (!(is_callable($middleware) || $middleware instanceof IMiddleware)) {
Validate::isTrue(
false,
Resources::INVALID_TYPE_MSG . 'callable or IMiddleware'
);
}
}
}
@@ -0,0 +1,279 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Serialization\XmlSerializer;
/**
* Encapsulates service properties
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class ServiceProperties
{
private $logging;
private $hourMetrics;
private $minuteMetrics;
private $corses;
private $defaultServiceVersion;
private static $xmlRootName = 'StorageServiceProperties';
/**
* Creates ServiceProperties object from parsed XML response.
*
* @internal
* @param array $parsedResponse XML response parsed into array.
*
* @return ServiceProperties.
*/
public static function create(array $parsedResponse)
{
$result = new ServiceProperties();
if (array_key_exists(Resources::XTAG_DEFAULT_SERVICE_VERSION, $parsedResponse) &&
$parsedResponse[Resources::XTAG_DEFAULT_SERVICE_VERSION] != null) {
$result->setDefaultServiceVersion($parsedResponse[Resources::XTAG_DEFAULT_SERVICE_VERSION]);
}
if (array_key_exists(Resources::XTAG_LOGGING, $parsedResponse)) {
$result->setLogging(Logging::create($parsedResponse[Resources::XTAG_LOGGING]));
}
$result->setHourMetrics(Metrics::create($parsedResponse[Resources::XTAG_HOUR_METRICS]));
if (array_key_exists(Resources::XTAG_MINUTE_METRICS, $parsedResponse)) {
$result->setMinuteMetrics(Metrics::create($parsedResponse[Resources::XTAG_MINUTE_METRICS]));
}
if (array_key_exists(Resources::XTAG_CORS, $parsedResponse) &&
$parsedResponse[Resources::XTAG_CORS] != null) {
//There could be multiple CORS rules, so need to extract them all.
$corses = array();
$corsArray =
$parsedResponse[Resources::XTAG_CORS][Resources::XTAG_CORS_RULE];
if (count(array_filter(array_keys($corsArray), 'is_string')) > 0) {
//single cors rule
$corses[] = CORS::create($corsArray);
} else {
//multiple cors rule
foreach ($corsArray as $cors) {
$corses[] = CORS::create($cors);
}
}
$result->setCorses($corses);
} else {
$result->setCorses(array());
}
return $result;
}
/**
* Gets logging element.
*
* @return Logging
*/
public function getLogging()
{
return $this->logging;
}
/**
* Sets logging element.
*
* @param Logging $logging new element.
*
* @return void
*/
public function setLogging(Logging $logging)
{
$this->logging = clone $logging;
}
/**
* Gets hour metrics element.
*
* @return Metrics
*/
public function getHourMetrics()
{
return $this->hourMetrics;
}
/**
* Sets hour metrics element.
*
* @param Metrics $metrics new element.
*
* @return void
*/
public function setHourMetrics(Metrics $hourMetrics)
{
$this->hourMetrics = clone $hourMetrics;
}
/**
* Gets minute metrics element.
*
* @return Metrics
*/
public function getMinuteMetrics()
{
return $this->minuteMetrics;
}
/**
* Sets minute metrics element.
*
* @param Metrics $metrics new element.
*
* @return void
*/
public function setMinuteMetrics(Metrics $minuteMetrics)
{
$this->minuteMetrics = clone $minuteMetrics;
}
/**
* Gets corses element.
*
* @return CORS[]
*/
public function getCorses()
{
return $this->corses;
}
/**
* Sets corses element.
*
* @param CORS[] $corses new elements.
*
* @return void
*/
public function setCorses(array $corses)
{
$this->corses = $corses;
}
/**
* Gets the default service version.
*
* @return string
*/
public function getDefaultServiceVersion()
{
return $this->defaultServiceVersion;
}
/**
* Sets the default service version. This can obly be set for the blob service.
*
* @param string $defaultServiceVersion the default service version
*
* @return void
*/
public function setDefaultServiceVersion($defaultServiceVersion)
{
$this->defaultServiceVersion = $defaultServiceVersion;
}
/**
* Converts this object to array with XML tags
*
* @internal
* @return array
*/
public function toArray()
{
$result = array();
if (!empty($this->getLogging())) {
$result[Resources::XTAG_LOGGING] =
$this->getLogging()->toArray();
}
if (!empty($this->getHourMetrics())) {
$result[Resources::XTAG_HOUR_METRICS] =
$this->getHourMetrics()->toArray();
}
if (!empty($this->getMinuteMetrics())) {
$result[Resources::XTAG_MINUTE_METRICS] =
$this->getMinuteMetrics()->toArray();
}
$corsesArray = $this->getCorsesArray();
if (!empty($corsesArray)) {
$result[Resources::XTAG_CORS] =$corsesArray;
}
if ($this->defaultServiceVersion != null) {
$result[Resources::XTAG_DEFAULT_SERVICE_VERSION] = $this->defaultServiceVersion;
}
return $result;
}
/**
* Gets the array that contains all the CORSes.
*
* @return array
*/
private function getCorsesArray()
{
$corsesArray = array();
if (count($this->getCorses()) == 1) {
$corsesArray = array(
Resources::XTAG_CORS_RULE => $this->getCorses()[0]->toArray()
);
} elseif ($this->getCorses() != array()) {
foreach ($this->getCorses() as $cors) {
$corsesArray[] = [Resources::XTAG_CORS_RULE => $cors->toArray()];
}
}
return $corsesArray;
}
/**
* Converts this current object to XML representation.
*
* @internal
* @param XmlSerializer $xmlSerializer The XML serializer.
*
* @return string
*/
public function toXml(XmlSerializer $xmlSerializer)
{
$properties = array(XmlSerializer::ROOT_NAME => self::$xmlRootName);
return $xmlSerializer->serialize($this->toArray(), $properties);
}
}
@@ -0,0 +1,118 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
use MicrosoftAzure\Storage\Common\Internal\Resources;
/**
* Holds signed identifiers.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class SignedIdentifier
{
private $id;
private $accessPolicy;
/**
* Constructor
*
* @param string $id The id of this signed identifier.
* @param AccessPolicy|null $accessPolicy The access policy.
*/
public function __construct($id = '', AccessPolicy $accessPolicy = null)
{
$this->setId($id);
$this->setAccessPolicy($accessPolicy);
}
/**
* Gets id.
*
* @return string
*/
public function getId()
{
return $this->id;
}
/**
* Sets id.
*
* @param string $id value.
*
* @return void
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Gets accessPolicy.
*
* @return AccessPolicy
*/
public function getAccessPolicy()
{
return $this->accessPolicy;
}
/**
* Sets accessPolicy.
*
* @param AccessPolicy|null $accessPolicy value.
*
* @return void
*/
public function setAccessPolicy(AccessPolicy $accessPolicy = null)
{
$this->accessPolicy = $accessPolicy;
}
/**
* Converts this current object to XML representation.
*
* @internal
*
* @return array
*/
public function toArray()
{
$array = array();
$accessPolicyArray = array();
$accessPolicyArray[Resources::XTAG_SIGNED_ID] = $this->getId();
$accessPolicyArray[Resources::XTAG_ACCESS_POLICY] =
$this->getAccessPolicy()->toArray();
$array[Resources::XTAG_SIGNED_IDENTIFIER] = $accessPolicyArray;
return $array;
}
}
@@ -0,0 +1,64 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2018 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Models;
/**
* Trait implementing setting and getting useTransactionalMD5 for
* option classes which need support transactional MD5 validation
* during data transferring.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Models
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2018 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
trait TransactionalMD5Trait
{
/** @var $useTransactionalMD5 boolean */
private $useTransactionalMD5;
/**
* Gets whether using transactional MD5 validation.
*
* @return boolean
*/
public function getUseTransactionalMD5()
{
return $this->useTransactionalMD5;
}
/**
* Sets whether using transactional MD5 validation.
*
* @param boolean $useTransactionalMD5 whether enable transactional
* MD5 validation.
*/
public function setUseTransactionalMD5($useTransactionalMD5)
{
$this->useTransactionalMD5 = $useTransactionalMD5;
}
}
@@ -0,0 +1,331 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Internal\Authentication
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
use MicrosoftAzure\Storage\Common\Internal\Validate;
/**
* Provides methods to generate Azure Storage Shared Access Signature
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class SharedAccessSignatureHelper
{
protected $accountName;
protected $accountKey;
/**
* Constructor.
*
* @param string $accountName the name of the storage account.
* @param string $accountKey the shared key of the storage account
*
*/
public function __construct($accountName, $accountKey)
{
Validate::canCastAsString($accountName, 'accountName');
Validate::notNullOrEmpty($accountName, 'accountName');
Validate::canCastAsString($accountKey, 'accountKey');
Validate::notNullOrEmpty($accountKey, 'accountKey');
$this->accountName = urldecode($accountName);
$this->accountKey = $accountKey;
}
/**
* Generates a shared access signature at the account level.
*
* @param string $signedVersion Specifies the signed version to use.
* @param string $signedPermissions Specifies the signed permissions for
* the account SAS.
* @param string $signedService Specifies the signed services
* accessible with the account SAS.
* @param string $signedResourceType Specifies the signed resource types
* that are accessible with the account
* SAS.
* @param \Datetime|string $signedExpiry The time at which the shared access
* signature becomes invalid, in an ISO
* 8601 format.
* @param \Datetime|string $signedStart The time at which the SAS becomes
* valid, in an ISO 8601 format.
* @param string $signedIP Specifies an IP address or a range
* of IP addresses from which to accept
* requests.
* @param string $signedProtocol Specifies the protocol permitted for
* a request made with the account SAS.
*
* @see Constructing an account SAS at
* https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/constructing-an-account-sas
*
* @return string
*/
public function generateAccountSharedAccessSignatureToken(
$signedVersion,
$signedPermissions,
$signedService,
$signedResourceType,
$signedExpiry,
$signedStart = "",
$signedIP = "",
$signedProtocol = ""
) {
// check that version is valid
Validate::canCastAsString($signedVersion, 'signedVersion');
Validate::notNullOrEmpty($signedVersion, 'signedVersion');
Validate::isDateString($signedVersion, 'signedVersion');
// validate and sanitize signed service
$signedService = $this->validateAndSanitizeSignedService($signedService);
// validate and sanitize signed resource type
$signedResourceType = $this->validateAndSanitizeSignedResourceType($signedResourceType);
// validate and sanitize signed permissions
$signedPermissions = $this->validateAndSanitizeSignedPermissions($signedPermissions);
// check that expiracy is valid
if ($signedExpiry instanceof \Datetime) {
$signedExpiry = Utilities::isoDate($signedExpiry);
}
Validate::canCastAsString($signedExpiry, 'signedExpiry');
Validate::notNullOrEmpty($signedExpiry, 'signedExpiry');
Validate::isDateString($signedExpiry, 'signedExpiry');
// check that signed start is valid
if ($signedStart instanceof \Datetime) {
$signedStart = Utilities::isoDate($signedStart);
}
Validate::canCastAsString($signedStart, 'signedStart');
if (strlen($signedStart) > 0) {
Validate::isDateString($signedStart, 'signedStart');
}
// check that signed IP is valid
Validate::canCastAsString($signedIP, 'signedIP');
// validate and sanitize signed protocol
$signedProtocol = $this->validateAndSanitizeSignedProtocol($signedProtocol);
// construct an array with the parameters to generate the shared access signature at the account level
$parameters = array();
$parameters[] = $this->accountName;
$parameters[] = $signedPermissions;
$parameters[] = $signedService;
$parameters[] = $signedResourceType;
$parameters[] = $signedStart;
$parameters[] = $signedExpiry;
$parameters[] = $signedIP;
$parameters[] = $signedProtocol;
$parameters[] = $signedVersion;
// implode the parameters into a string
$stringToSign = utf8_encode(implode("\n", $parameters) . "\n");
// decode the account key from base64
$decodedAccountKey = base64_decode($this->accountKey);
// create the signature with hmac sha256
$signature = hash_hmac("sha256", $stringToSign, $decodedAccountKey, true);
// encode the signature as base64 and url encode.
$sig = urlencode(base64_encode($signature));
//adding all the components for account SAS together.
$sas = 'sv=' . $signedVersion;
$sas .= '&ss=' . $signedService;
$sas .= '&srt=' . $signedResourceType;
$sas .= '&sp=' . $signedPermissions;
$sas .= '&se=' . $signedExpiry;
$sas .= $signedStart === ''? '' : '&st=' . $signedStart;
$sas .= $signedIP === ''? '' : '&sip=' . $signedIP;
$sas .= '&spr=' . $signedProtocol;
$sas .= '&sig=' . $sig;
// return the signature
return $sas;
}
/**
* Validates and sanitizes the signed service parameter
*
* @param string $signedService Specifies the signed services accessible
* with the account SAS.
*
* @return string
*/
protected function validateAndSanitizeSignedService($signedService)
{
// validate signed service is not null or empty
Validate::canCastAsString($signedService, 'signedService');
Validate::notNullOrEmpty($signedService, 'signedService');
// The signed service should only be a combination of the letters b(lob) q(ueue) t(able) or f(ile)
$validServices = ['b', 'q', 't', 'f'];
return $this->validateAndSanitizeStringWithArray(
strtolower($signedService),
$validServices
);
}
/**
* Validates and sanitizes the signed resource type parameter
*
* @param string $signedResourceType Specifies the signed resource types
* that are accessible with the account
* SAS.
*
* @return string
*/
protected function validateAndSanitizeSignedResourceType($signedResourceType)
{
// validate signed resource type is not null or empty
Validate::canCastAsString($signedResourceType, 'signedResourceType');
Validate::notNullOrEmpty($signedResourceType, 'signedResourceType');
// The signed resource type should only be a combination of the letters s(ervice) c(container) or o(bject)
$validResourceTypes = ['s', 'c', 'o'];
return $this->validateAndSanitizeStringWithArray(
strtolower($signedResourceType),
$validResourceTypes
);
}
/**
* Validates and sanitizes the signed permissions parameter
*
* @param string $signedPermissions Specifies the signed permissions for the
* account SAS.
*
* @return string
*/
protected function validateAndSanitizeSignedPermissions(
$signedPermissions
) {
// validate signed permissions are not null or empty
Validate::canCastAsString($signedPermissions, 'signedPermissions');
Validate::notNullOrEmpty($signedPermissions, 'signedPermissions');
$validPermissions = ['r', 'w', 'd', 'l', 'a', 'c', 'u', 'p'];
return $this->validateAndSanitizeStringWithArray(
strtolower($signedPermissions),
$validPermissions
);
}
/**
* Validates and sanitizes the signed protocol parameter
*
* @param string $signedProtocol Specifies the signed protocol for the
* account SAS.
* @return string
*/
protected function validateAndSanitizeSignedProtocol($signedProtocol)
{
Validate::canCastAsString($signedProtocol, 'signedProtocol');
// sanitize string
$sanitizedSignedProtocol = strtolower($signedProtocol);
if (strlen($sanitizedSignedProtocol) > 0) {
if (strcmp($sanitizedSignedProtocol, "https") != 0 && strcmp($sanitizedSignedProtocol, "https,http") != 0) {
throw new \InvalidArgumentException(Resources::SIGNED_PROTOCOL_INVALID_VALIDATION_MSG);
}
}
return $sanitizedSignedProtocol;
}
/**
* Removes duplicate characters from a string
*
* @param string $input The input string.
* @return string
*/
protected function validateAndSanitizeStringWithArray($input, array $array)
{
$result = '';
foreach ($array as $value) {
if (strpos($input, $value) !== false) {
//append the valid permission to result.
$result .= $value;
//remove all the character that represents the permission.
$input = str_replace(
$value,
'',
$input
);
}
}
Validate::isTrue(
strlen($input) == 0,
sprintf(
Resources::STRING_NOT_WITH_GIVEN_COMBINATION,
implode(', ', $array)
)
);
return $result;
}
/**
* Generate the canonical resource using the given account name, service
* type and resource.
*
* @param string $accountName The account name of the service.
* @param string $service The service name of the service.
* @param string $resource The name of the resource.
*
* @return string
*/
protected static function generateCanonicalResource(
$accountName,
$service,
$resource
) {
static $serviceMap = array(
Resources::RESOURCE_TYPE_BLOB => 'blob',
Resources::RESOURCE_TYPE_FILE => 'file',
Resources::RESOURCE_TYPE_QUEUE => 'queue',
Resources::RESOURCE_TYPE_TABLE => 'table',
);
$serviceName = $serviceMap[$service];
if (Utilities::startsWith($resource, '/')) {
$resource = substr($resource, 1);
}
return urldecode(sprintf('/%s/%s/%s', $serviceName, $accountName, $resource));
}
}