PageRenderTime 418ms CodeModel.GetById 111ms app.highlight 155ms RepoModel.GetById 87ms app.codeStats 1ms

/vendor/Microsoft/WindowsAzure/Storage.php

https://bitbucket.org/ktos/tinyshare
PHP | 629 lines | 294 code | 67 blank | 268 comment | 46 complexity | de921bfdecab59c9f14120b1d644ff4f MD5 | raw file
  1<?php
  2/**
  3 * Copyright (c) 2009 - 2011, RealDolmen
  4 * All rights reserved.
  5 *
  6 * Redistribution and use in source and binary forms, with or without
  7 * modification, are permitted provided that the following conditions are met:
  8 *     * Redistributions of source code must retain the above copyright
  9 *       notice, this list of conditions and the following disclaimer.
 10 *     * Redistributions in binary form must reproduce the above copyright
 11 *       notice, this list of conditions and the following disclaimer in the
 12 *       documentation and/or other materials provided with the distribution.
 13 *     * Neither the name of RealDolmen nor the
 14 *       names of its contributors may be used to endorse or promote products
 15 *       derived from this software without specific prior written permission.
 16 *
 17 * THIS SOFTWARE IS PROVIDED BY RealDolmen ''AS IS'' AND ANY
 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 20 * DISCLAIMED. IN NO EVENT SHALL RealDolmen BE LIABLE FOR ANY
 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 27 *
 28 * @category   Microsoft
 29 * @package    Microsoft_WindowsAzure
 30 * @subpackage Storage
 31 * @copyright  Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
 32 * @license    http://phpazure.codeplex.com/license
 33 * @version    $Id: Storage.php 66505 2011-12-02 08:45:51Z unknown $
 34 */
 35
 36/**
 37 * @see Microsoft_AutoLoader
 38 */
 39require_once dirname(__FILE__) . '/../AutoLoader.php';
 40
 41/**
 42 * @category   Microsoft
 43 * @package    Microsoft_WindowsAzure
 44 * @subpackage Storage
 45 * @copyright  Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
 46 * @license    http://phpazure.codeplex.com/license
 47 */
 48class Microsoft_WindowsAzure_Storage
 49{
 50	/**
 51	 * Development storage URLS
 52	 */
 53	const URL_DEV_BLOB      = "http://127.0.0.1:10000";
 54	const URL_DEV_QUEUE     = "http://127.0.0.1:10001";
 55	const URL_DEV_TABLE     = "http://127.0.0.1:10002";
 56	
 57	/**
 58	 * Live storage URLS
 59	 */
 60	const URL_CLOUD_BLOB    = "http://blob.core.windows.net";
 61	const URL_CLOUD_QUEUE   = "http://queue.core.windows.net";
 62	const URL_CLOUD_TABLE   = "http://table.core.windows.net";
 63	const URL_CLOUD_BLOB_HTTPS    = "ssl://blob.core.windows.net";
 64	const URL_CLOUD_QUEUE_HTTPS   = "ssl://queue.core.windows.net";
 65	const URL_CLOUD_TABLE_HTTPS   = "ssl://table.core.windows.net";
 66	
 67	/**
 68	 * Resource types
 69	 */
 70	const RESOURCE_UNKNOWN     = "unknown";
 71	const RESOURCE_CONTAINER   = "c";
 72	const RESOURCE_BLOB        = "b";
 73	const RESOURCE_TABLE       = "t";
 74	const RESOURCE_ENTITY      = "e";
 75	const RESOURCE_QUEUE       = "q";
 76	
 77	/**
 78	 * HTTP header prefixes
 79	 */
 80	const PREFIX_PROPERTIES      = "x-ms-prop-";
 81	const PREFIX_METADATA        = "x-ms-meta-";
 82	const PREFIX_STORAGE_HEADER  = "x-ms-";
 83	
 84	/**
 85	 * Protocols
 86	 */
 87	const PROTOCOL_HTTP  = 'http://';
 88	const PROTOCOL_HTTPS = 'https://';
 89	const PROTOCOL_SSL   = 'ssl://';
 90	
 91	/**
 92	 * Current API version
 93	 * 
 94	 * @var string
 95	 */
 96	protected $_apiVersion = '2009-09-19';
 97	
 98	/**
 99	 * Storage protocol
100	 *
101	 * @var string
102	 */
103	protected $_protocol = 'http://';
104	
105	/**
106	 * Storage host name
107	 *
108	 * @var string
109	 */
110	protected $_host = '';
111	
112	/**
113	 * Account name for Windows Azure
114	 *
115	 * @var string
116	 */
117	protected $_accountName = '';
118	
119	/**
120	 * Account key for Windows Azure
121	 *
122	 * @var string
123	 */
124	protected $_accountKey = '';
125	
126	/**
127	 * Use path-style URI's
128	 *
129	 * @var boolean
130	 */
131	protected $_usePathStyleUri = false;
132	
133	/**
134	 * Microsoft_WindowsAzure_Credentials_CredentialsAbstract instance
135	 *
136	 * @var Microsoft_WindowsAzure_Credentials_CredentialsAbstract
137	 */
138	protected $_credentials = null;
139	
140	/**
141	 * Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract instance
142	 * 
143	 * @var Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract
144	 */
145	protected $_retryPolicy = null;
146	
147	/**
148	 * Microsoft_Http_Client channel used for communication with REST services
149	 * 
150	 * @var Microsoft_Http_Client
151	 */
152	protected $_httpClientChannel = null;
153	
154	/**
155	 * Use proxy?
156	 * 
157	 * @var boolean
158	 */
159	protected $_useProxy = false;
160	
161	/**
162	 * Proxy url
163	 * 
164	 * @var string
165	 */
166	protected $_proxyUrl = '';
167	
168	/**
169	 * Proxy port
170	 * 
171	 * @var int
172	 */
173	protected $_proxyPort = 80;
174	
175	/**
176	 * Proxy credentials
177	 * 
178	 * @var string
179	 */
180	protected $_proxyCredentials = '';
181	
182	/**
183	 * Creates a new Microsoft_WindowsAzure_Storage instance
184	 *
185	 * @param string $host Storage host name
186	 * @param string $accountName Account name for Windows Azure
187	 * @param string $accountKey Account key for Windows Azure
188	 * @param boolean $usePathStyleUri Use path-style URI's
189	 * @param Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
190	 */
191	public function __construct(
192		$host = self::URL_DEV_BLOB,
193		$accountName = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT,
194		$accountKey = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY,
195		$usePathStyleUri = false,
196		Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null
197	) {
198		if (strpos($host, self::PROTOCOL_HTTP) !== false) {
199			$this->_protocol = self::PROTOCOL_HTTP;
200			$this->_host = str_replace(self::PROTOCOL_HTTP, '', $host);
201		} else if (strpos($host, self::PROTOCOL_HTTPS) !== false) {
202			$this->_protocol = self::PROTOCOL_HTTPS;
203			$this->_host = str_replace(self::PROTOCOL_HTTPS, '', $host);
204		} else if (strpos($host, self::PROTOCOL_SSL) !== false) {
205			$this->_protocol = self::PROTOCOL_SSL;
206			$this->_host = str_replace(self::PROTOCOL_SSL, '', $host);
207		} else {
208			$this->_protocol = self::PROTOCOL_HTTP;
209			$this->_host = $host;
210		}
211		$this->_accountName = $accountName;
212		$this->_accountKey = $accountKey;
213		$this->_usePathStyleUri = $usePathStyleUri;
214
215		// Using local storage?
216		if (!$this->_usePathStyleUri
217			&& ($this->_protocol . $this->_host == self::URL_DEV_BLOB
218				|| $this->_protocol . $this->_host == self::URL_DEV_QUEUE
219				|| $this->_protocol . $this->_host == self::URL_DEV_TABLE)
220		) {
221			// Local storage
222			$this->_usePathStyleUri = true;
223		}
224		
225		if (is_null($this->_credentials)) {
226		    $this->_credentials = new Microsoft_WindowsAzure_Credentials_SharedKey(
227		    	$this->_accountName, $this->_accountKey, $this->_usePathStyleUri);
228		}
229		
230		$this->_retryPolicy = $retryPolicy;
231		if (is_null($this->_retryPolicy)) {
232		    $this->_retryPolicy = Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry();
233		}
234		
235		// Setup default Microsoft_Http_Client channel
236		$options = array(
237			'adapter' => 'Microsoft_Http_Client_Adapter_Proxy'
238		);
239		if (function_exists('curl_init')) {
240			// Set cURL options if cURL is used afterwards
241			$options['curloptions'] = array(
242					CURLOPT_FOLLOWLOCATION => true,
243					CURLOPT_TIMEOUT => 120,
244			);
245		}
246		$this->_httpClientChannel = new Microsoft_Http_Client(null, $options);
247	}
248	
249	/**
250	 * Set the HTTP client channel to use
251	 * 
252	 * @param Microsoft_Http_Client_Adapter_Interface|string $adapterInstance Adapter instance or adapter class name.
253	 */
254	public function setHttpClientChannel($adapterInstance = 'Microsoft_Http_Client_Adapter_Proxy')
255	{
256		$this->_httpClientChannel->setAdapter($adapterInstance);
257	}
258	
259    /**
260     * Retrieve HTTP client channel
261     * 
262     * @return Microsoft_Http_Client_Adapter_Interface
263     */
264    public function getHttpClientChannel()
265    {
266        return $this->_httpClientChannel;
267    }
268	
269	/**
270	 * Set retry policy to use when making requests
271	 *
272	 * @param Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
273	 */
274	public function setRetryPolicy(Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
275	{
276		$this->_retryPolicy = $retryPolicy;
277		if (is_null($this->_retryPolicy)) {
278		    $this->_retryPolicy = Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry();
279		}
280	}
281	
282	/**
283	 * Set proxy
284	 * 
285	 * @param boolean $useProxy         Use proxy?
286	 * @param string  $proxyUrl         Proxy URL
287	 * @param int     $proxyPort        Proxy port
288	 * @param string  $proxyCredentials Proxy credentials
289	 */
290	public function setProxy($useProxy = false, $proxyUrl = '', $proxyPort = 80, $proxyCredentials = '')
291	{
292	    $this->_useProxy         = $useProxy;
293	    $this->_proxyUrl         = $proxyUrl;
294	    $this->_proxyPort        = $proxyPort;
295	    $this->_proxyCredentials = $proxyCredentials;
296	    
297	    if ($this->_useProxy) {
298	    	$credentials = explode(':', $this->_proxyCredentials);
299	    	
300	    	$this->_httpClientChannel->setConfig(array(
301				'proxy_host' => $this->_proxyUrl,
302	    		'proxy_port' => $this->_proxyPort,
303	    		'proxy_user' => $credentials[0],
304	    		'proxy_pass' => $credentials[1],
305	    	));
306	    } else {
307			$this->_httpClientChannel->setConfig(array(
308				'proxy_host' => '',
309	    		'proxy_port' => 8080,
310	    		'proxy_user' => '',
311	    		'proxy_pass' => '',
312	    	));
313	    }
314	}
315	
316	/**
317	 * Returns the Windows Azure account name
318	 * 
319	 * @return string
320	 */
321	public function getAccountName()
322	{
323		return $this->_accountName;
324	}
325	
326	/**
327	 * Get base URL for creating requests
328	 *
329	 * @return string
330	 */
331	public function getBaseUrl()
332	{
333		if ($this->_usePathStyleUri) {
334			return $this->_protocol . $this->_host . '/' . $this->_accountName;
335		} else {
336			return $this->_protocol . $this->_accountName . '.' . $this->_host;
337		}
338	}
339	
340	/**
341	 * Set Microsoft_WindowsAzure_Credentials_CredentialsAbstract instance
342	 * 
343	 * @param Microsoft_WindowsAzure_Credentials_CredentialsAbstract $credentials Microsoft_WindowsAzure_Credentials_CredentialsAbstract instance to use for request signing.
344	 */
345	public function setCredentials(Microsoft_WindowsAzure_Credentials_CredentialsAbstract $credentials)
346	{
347	    $this->_credentials = $credentials;
348	    $this->_credentials->setAccountName($this->_accountName);
349	    $this->_credentials->setAccountkey($this->_accountKey);
350	    $this->_credentials->setUsePathStyleUri($this->_usePathStyleUri);
351	}
352	
353	/**
354	 * Get Microsoft_WindowsAzure_Credentials_CredentialsAbstract instance
355	 * 
356	 * @return Microsoft_WindowsAzure_Credentials_CredentialsAbstract
357	 */
358	public function getCredentials()
359	{
360	    return $this->_credentials;
361	}
362	
363	/**
364	 * Returns the properties of a storage service. 
365	 * Service properties include Logging (no connection with the logging components of this SDK) 
366	 * and Metrics details.
367	 * Returned strucutre:
368	 * array(
369	 *   '<Area>' => array('<Property>' => string|array)
370	 * );
371	 * <Area> can be: Logging, Metrics or other service areas.
372	 * 
373	 * @return array
374	 */
375	public function getServiceProperties()
376	{
377		// Perform request
378		$response = $this->_performRequest('/', '?restype=service&comp=properties');
379		if (!$response->isSuccessful()) {
380			throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage(
381				$response, 'Cannot obtain service properties.'
382			));
383		}
384		
385		// turn the response from a SimpleXML object to an array
386		$parsedResponse = $this->_parseResponse($response);
387		
388		$returnArray = array();
389		foreach ($parsedResponse as $key => $propertyAsXmlNode) {
390			$returnArray[$key] = $this->_parseServicePropertyResponseNode($propertyAsXmlNode);
391		}
392		
393		return $returnArray;
394	}
395	
396	/**
397	 * Parses a node of the service property response. A node is a direct child of the root
398	 * element (StorageServiceProperties). 
399	 * Returns the array representation of that node.
400	 * 
401	 * @param $responseNode
402	 * @return array
403	 */
404	protected function _parseServicePropertyResponseNode($responseNode)
405	{
406		if ($responseNode->count() > 0) {
407			$returnArray = array();
408			foreach ($responseNode as $key => $childNode) {
409				$returnArray[$key] = $this->_parseServicePropertyResponseNode($childNode);
410			}
411			return $returnArray;
412		} else {
413			return (string)$responseNode;
414		}
415	}
416	
417	/**
418	 * Perform request using Microsoft_Http_Client channel
419	 *
420	 * @param string $path Path
421	 * @param array $query Query parameters
422	 * @param string $httpVerb HTTP verb the request will use
423	 * @param array $headers x-ms headers to add
424	 * @param boolean $forTableStorage Is the request for table storage?
425	 * @param mixed $rawData Optional RAW HTTP data to be sent over the wire
426	 * @param string $resourceType Resource type
427	 * @param string $requiredPermission Required permission
428	 * @return Microsoft_Http_Response
429	 */
430	protected function _performRequest(
431		$path = '/',
432		$query = array(),
433		$httpVerb = Microsoft_Http_Client::GET,
434		$headers = array(),
435		$forTableStorage = false,
436		$rawData = null,
437		$resourceType = Microsoft_WindowsAzure_Storage::RESOURCE_UNKNOWN,
438		$requiredPermission = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
439	) {
440	    // Clean path
441		if (strpos($path, '/') !== 0) {
442			$path = '/' . $path;
443		}
444			
445		// Clean headers
446		if (is_null($headers)) {
447		    $headers = array();
448		}
449		
450		// Ensure cUrl will also work correctly:
451		//  - disable Content-Type if required
452		//  - disable Expect: 100 Continue
453		if (!isset($headers["Content-Type"])) {
454			$headers["Content-Type"] = '';
455		}
456		$headers["Expect"]= '';
457
458		// Add version header
459		$headers['x-ms-version'] = $this->_apiVersion;
460		    
461		// Generate URL
462		$path = str_replace(' ', '%20', $path);
463		$requestUrl = $this->getBaseUrl() . $path;
464		if (count($query) > 0) {
465			$queryString = '';
466			foreach ($query as $key => $value) {
467				$queryString .= ($queryString ? '&' : '?') . rawurlencode($key) . '=' . rawurlencode($value);
468			}			
469			$requestUrl .= $queryString;
470		}
471		
472		// Sign request
473		$requestUrl     = $this->_credentials
474						  ->signRequestUrl($requestUrl, $resourceType, $requiredPermission);
475		$requestHeaders = $this->_credentials
476						  ->signRequestHeaders($httpVerb, $path, $query, $headers, $forTableStorage, $resourceType, $requiredPermission, $rawData);
477
478		// Prepare request 
479		$this->_httpClientChannel->resetParameters(true);
480		$this->_httpClientChannel->setUri($requestUrl);
481		$this->_httpClientChannel->setHeaders($requestHeaders);
482		$this->_httpClientChannel->setRawData($rawData);
483				
484		// Execute request
485		$response = $this->_retryPolicy->execute(
486		    array($this->_httpClientChannel, 'request'),
487		    array($httpVerb)
488		);
489		
490		return $response;
491	}
492	
493	/** 
494	 * Parse result from Microsoft_Http_Response
495	 *
496	 * @param Microsoft_Http_Response $response Response from HTTP call
497	 * @return object
498	 * @throws Microsoft_WindowsAzure_Exception
499	 */
500	protected function _parseResponse(Microsoft_Http_Response $response = null)
501	{
502		if (is_null($response)) {
503			throw new Microsoft_WindowsAzure_Exception('Response should not be null.');
504		}
505		
506        $xml = @simplexml_load_string($response->getBody());
507        
508        if ($xml !== false) {
509            // Fetch all namespaces 
510            $namespaces = array_merge($xml->getNamespaces(true), $xml->getDocNamespaces(true)); 
511            
512            // Register all namespace prefixes
513            foreach ($namespaces as $prefix => $ns) { 
514                if ($prefix != '') {
515                    $xml->registerXPathNamespace($prefix, $ns);
516                } 
517            } 
518        }
519        
520        return $xml;
521	}
522	
523	/**
524	 * Generate metadata headers
525	 * 
526	 * @param array $metadata
527	 * @return HTTP headers containing metadata
528	 */
529	protected function _generateMetadataHeaders($metadata = array())
530	{
531		// Validate
532		if (!is_array($metadata)) {
533			return array();
534		}
535		
536		// Return headers
537		$headers = array();
538		foreach ($metadata as $key => $value) {
539			if (strpos($value, "\r") !== false || strpos($value, "\n") !== false) {
540				throw new Microsoft_WindowsAzure_Exception('Metadata cannot contain newline characters.');
541			}
542			
543			if (!self::isValidMetadataName($key)) {
544		    	throw new Microsoft_WindowsAzure_Exception('Metadata name does not adhere to metadata naming conventions. See http://msdn.microsoft.com/en-us/library/aa664670(VS.71).aspx for more information.');
545			}
546			
547		    $headers["x-ms-meta-" . strtolower($key)] = $value;
548		}
549		return $headers;
550	}
551	
552	/**
553	 * Parse metadata headers
554	 * 
555	 * @param array $headers HTTP headers containing metadata
556	 * @return array
557	 */
558	protected function _parseMetadataHeaders($headers = array())
559	{
560		// Validate
561		if (!is_array($headers)) {
562			return array();
563		}
564		
565		// Return metadata
566		$metadata = array();
567		foreach ($headers as $key => $value) {
568		    if (substr(strtolower($key), 0, 10) == "x-ms-meta-") {
569		        $metadata[str_replace("x-ms-meta-", '', strtolower($key))] = $value;
570		    }
571		}
572		return $metadata;
573	}
574	
575	/**
576	 * Parse metadata XML
577	 * 
578	 * @param SimpleXMLElement $parentElement Element containing the Metadata element.
579	 * @return array
580	 */
581	protected function _parseMetadataElement($element = null)
582	{
583		// Metadata present?
584		if (!is_null($element) && isset($element->Metadata) && !is_null($element->Metadata)) {
585			return get_object_vars($element->Metadata);
586		}
587
588		return array();
589	}
590	
591	/**
592	 * Generate ISO 8601 compliant date string in UTC time zone
593	 * 
594	 * @param int $timestamp
595	 * @return string
596	 */
597	public function isoDate($timestamp = null) 
598	{        
599	    $tz = @date_default_timezone_get();
600	    @date_default_timezone_set('UTC');
601	    
602	    if (is_null($timestamp)) {
603	        $timestamp = time();
604	    }
605	        
606	    $returnValue = str_replace('+00:00', '.0000000Z', @date('c', $timestamp));
607	    @date_default_timezone_set($tz);
608	    return $returnValue;
609	}
610	
611	/**
612	 * Is valid metadata name?
613	 *
614	 * @param string $metadataName Metadata name
615	 * @return boolean
616	 */
617    public static function isValidMetadataName($metadataName = '')
618    {
619        if (preg_match("/^[a-zA-Z0-9_@][a-zA-Z0-9_]*$/", $metadataName) === 0) {
620            return false;
621        }
622    
623        if ($metadataName == '') {
624            return false;
625        }
626
627        return true;
628    }
629}