PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/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
Possible License(s): BSD-3-Clause
  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. * @see Microsoft_AutoLoader
  37. */
  38. require_once dirname(__FILE__) . '/../AutoLoader.php';
  39. /**
  40. * @category Microsoft
  41. * @package Microsoft_WindowsAzure
  42. * @subpackage Storage
  43. * @copyright Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
  44. * @license http://phpazure.codeplex.com/license
  45. */
  46. class Microsoft_WindowsAzure_Storage
  47. {
  48. /**
  49. * Development storage URLS
  50. */
  51. const URL_DEV_BLOB = "http://127.0.0.1:10000";
  52. const URL_DEV_QUEUE = "http://127.0.0.1:10001";
  53. const URL_DEV_TABLE = "http://127.0.0.1:10002";
  54. /**
  55. * Live storage URLS
  56. */
  57. const URL_CLOUD_BLOB = "http://blob.core.windows.net";
  58. const URL_CLOUD_QUEUE = "http://queue.core.windows.net";
  59. const URL_CLOUD_TABLE = "http://table.core.windows.net";
  60. const URL_CLOUD_BLOB_HTTPS = "ssl://blob.core.windows.net";
  61. const URL_CLOUD_QUEUE_HTTPS = "ssl://queue.core.windows.net";
  62. const URL_CLOUD_TABLE_HTTPS = "ssl://table.core.windows.net";
  63. /**
  64. * Resource types
  65. */
  66. const RESOURCE_UNKNOWN = "unknown";
  67. const RESOURCE_CONTAINER = "c";
  68. const RESOURCE_BLOB = "b";
  69. const RESOURCE_TABLE = "t";
  70. const RESOURCE_ENTITY = "e";
  71. const RESOURCE_QUEUE = "q";
  72. /**
  73. * HTTP header prefixes
  74. */
  75. const PREFIX_PROPERTIES = "x-ms-prop-";
  76. const PREFIX_METADATA = "x-ms-meta-";
  77. const PREFIX_STORAGE_HEADER = "x-ms-";
  78. /**
  79. * Protocols
  80. */
  81. const PROTOCOL_HTTP = 'http://';
  82. const PROTOCOL_HTTPS = 'https://';
  83. const PROTOCOL_SSL = 'ssl://';
  84. /**
  85. * Current API version
  86. *
  87. * @var string
  88. */
  89. protected $_apiVersion = '2009-09-19';
  90. /**
  91. * Storage protocol
  92. *
  93. * @var string
  94. */
  95. protected $_protocol = 'http://';
  96. /**
  97. * Storage host name
  98. *
  99. * @var string
  100. */
  101. protected $_host = '';
  102. /**
  103. * Account name for Windows Azure
  104. *
  105. * @var string
  106. */
  107. protected $_accountName = '';
  108. /**
  109. * Account key for Windows Azure
  110. *
  111. * @var string
  112. */
  113. protected $_accountKey = '';
  114. /**
  115. * Use path-style URI's
  116. *
  117. * @var boolean
  118. */
  119. protected $_usePathStyleUri = false;
  120. /**
  121. * Microsoft_WindowsAzure_Credentials_CredentialsAbstract instance
  122. *
  123. * @var Microsoft_WindowsAzure_Credentials_CredentialsAbstract
  124. */
  125. protected $_credentials = null;
  126. /**
  127. * Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract instance
  128. *
  129. * @var Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract
  130. */
  131. protected $_retryPolicy = null;
  132. /**
  133. * Microsoft_Http_Client channel used for communication with REST services
  134. *
  135. * @var Microsoft_Http_Client
  136. */
  137. protected $_httpClientChannel = null;
  138. /**
  139. * Use proxy?
  140. *
  141. * @var boolean
  142. */
  143. protected $_useProxy = false;
  144. /**
  145. * Proxy url
  146. *
  147. * @var string
  148. */
  149. protected $_proxyUrl = '';
  150. /**
  151. * Proxy port
  152. *
  153. * @var int
  154. */
  155. protected $_proxyPort = 80;
  156. /**
  157. * Proxy credentials
  158. *
  159. * @var string
  160. */
  161. protected $_proxyCredentials = '';
  162. /**
  163. * Creates a new Microsoft_WindowsAzure_Storage instance
  164. *
  165. * @param string $host Storage host name
  166. * @param string $accountName Account name for Windows Azure
  167. * @param string $accountKey Account key for Windows Azure
  168. * @param boolean $usePathStyleUri Use path-style URI's
  169. * @param Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
  170. */
  171. public function __construct(
  172. $host = self::URL_DEV_BLOB,
  173. $accountName = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT,
  174. $accountKey = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY,
  175. $usePathStyleUri = false,
  176. Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null
  177. ) {
  178. if (strpos($host, self::PROTOCOL_HTTP) !== false) {
  179. $this->_protocol = self::PROTOCOL_HTTP;
  180. $this->_host = str_replace(self::PROTOCOL_HTTP, '', $host);
  181. } else if (strpos($host, self::PROTOCOL_HTTPS) !== false) {
  182. $this->_protocol = self::PROTOCOL_HTTPS;
  183. $this->_host = str_replace(self::PROTOCOL_HTTPS, '', $host);
  184. } else if (strpos($host, self::PROTOCOL_SSL) !== false) {
  185. $this->_protocol = self::PROTOCOL_SSL;
  186. $this->_host = str_replace(self::PROTOCOL_SSL, '', $host);
  187. } else {
  188. $this->_protocol = self::PROTOCOL_HTTP;
  189. $this->_host = $host;
  190. }
  191. $this->_accountName = $accountName;
  192. $this->_accountKey = $accountKey;
  193. $this->_usePathStyleUri = $usePathStyleUri;
  194. // Using local storage?
  195. if (!$this->_usePathStyleUri
  196. && ($this->_protocol . $this->_host == self::URL_DEV_BLOB
  197. || $this->_protocol . $this->_host == self::URL_DEV_QUEUE
  198. || $this->_protocol . $this->_host == self::URL_DEV_TABLE)
  199. ) {
  200. // Local storage
  201. $this->_usePathStyleUri = true;
  202. }
  203. if (is_null($this->_credentials)) {
  204. $this->_credentials = new Microsoft_WindowsAzure_Credentials_SharedKey(
  205. $this->_accountName, $this->_accountKey, $this->_usePathStyleUri);
  206. }
  207. $this->_retryPolicy = $retryPolicy;
  208. if (is_null($this->_retryPolicy)) {
  209. $this->_retryPolicy = Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry();
  210. }
  211. // Setup default Microsoft_Http_Client channel
  212. $options = array(
  213. 'adapter' => 'Microsoft_Http_Client_Adapter_Proxy'
  214. );
  215. if (function_exists('curl_init')) {
  216. // Set cURL options if cURL is used afterwards
  217. $options['curloptions'] = array(
  218. CURLOPT_FOLLOWLOCATION => true,
  219. CURLOPT_TIMEOUT => 120,
  220. );
  221. }
  222. $this->_httpClientChannel = new Microsoft_Http_Client(null, $options);
  223. }
  224. /**
  225. * Set the HTTP client channel to use
  226. *
  227. * @param Microsoft_Http_Client_Adapter_Interface|string $adapterInstance Adapter instance or adapter class name.
  228. */
  229. public function setHttpClientChannel($adapterInstance = 'Microsoft_Http_Client_Adapter_Proxy')
  230. {
  231. $this->_httpClientChannel->setAdapter($adapterInstance);
  232. }
  233. /**
  234. * Retrieve HTTP client channel
  235. *
  236. * @return Microsoft_Http_Client_Adapter_Interface
  237. */
  238. public function getHttpClientChannel()
  239. {
  240. return $this->_httpClientChannel;
  241. }
  242. /**
  243. * Set retry policy to use when making requests
  244. *
  245. * @param Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests
  246. */
  247. public function setRetryPolicy(Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null)
  248. {
  249. $this->_retryPolicy = $retryPolicy;
  250. if (is_null($this->_retryPolicy)) {
  251. $this->_retryPolicy = Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry();
  252. }
  253. }
  254. /**
  255. * Set proxy
  256. *
  257. * @param boolean $useProxy Use proxy?
  258. * @param string $proxyUrl Proxy URL
  259. * @param int $proxyPort Proxy port
  260. * @param string $proxyCredentials Proxy credentials
  261. */
  262. public function setProxy($useProxy = false, $proxyUrl = '', $proxyPort = 80, $proxyCredentials = '')
  263. {
  264. $this->_useProxy = $useProxy;
  265. $this->_proxyUrl = $proxyUrl;
  266. $this->_proxyPort = $proxyPort;
  267. $this->_proxyCredentials = $proxyCredentials;
  268. if ($this->_useProxy) {
  269. $credentials = explode(':', $this->_proxyCredentials);
  270. $this->_httpClientChannel->setConfig(array(
  271. 'proxy_host' => $this->_proxyUrl,
  272. 'proxy_port' => $this->_proxyPort,
  273. 'proxy_user' => $credentials[0],
  274. 'proxy_pass' => $credentials[1],
  275. ));
  276. } else {
  277. $this->_httpClientChannel->setConfig(array(
  278. 'proxy_host' => '',
  279. 'proxy_port' => 8080,
  280. 'proxy_user' => '',
  281. 'proxy_pass' => '',
  282. ));
  283. }
  284. }
  285. /**
  286. * Returns the Windows Azure account name
  287. *
  288. * @return string
  289. */
  290. public function getAccountName()
  291. {
  292. return $this->_accountName;
  293. }
  294. /**
  295. * Get base URL for creating requests
  296. *
  297. * @return string
  298. */
  299. public function getBaseUrl()
  300. {
  301. if ($this->_usePathStyleUri) {
  302. return $this->_protocol . $this->_host . '/' . $this->_accountName;
  303. } else {
  304. return $this->_protocol . $this->_accountName . '.' . $this->_host;
  305. }
  306. }
  307. /**
  308. * Set Microsoft_WindowsAzure_Credentials_CredentialsAbstract instance
  309. *
  310. * @param Microsoft_WindowsAzure_Credentials_CredentialsAbstract $credentials Microsoft_WindowsAzure_Credentials_CredentialsAbstract instance to use for request signing.
  311. */
  312. public function setCredentials(Microsoft_WindowsAzure_Credentials_CredentialsAbstract $credentials)
  313. {
  314. $this->_credentials = $credentials;
  315. $this->_credentials->setAccountName($this->_accountName);
  316. $this->_credentials->setAccountkey($this->_accountKey);
  317. $this->_credentials->setUsePathStyleUri($this->_usePathStyleUri);
  318. }
  319. /**
  320. * Get Microsoft_WindowsAzure_Credentials_CredentialsAbstract instance
  321. *
  322. * @return Microsoft_WindowsAzure_Credentials_CredentialsAbstract
  323. */
  324. public function getCredentials()
  325. {
  326. return $this->_credentials;
  327. }
  328. /**
  329. * Returns the properties of a storage service.
  330. * Service properties include Logging (no connection with the logging components of this SDK)
  331. * and Metrics details.
  332. * Returned strucutre:
  333. * array(
  334. * '<Area>' => array('<Property>' => string|array)
  335. * );
  336. * <Area> can be: Logging, Metrics or other service areas.
  337. *
  338. * @return array
  339. */
  340. public function getServiceProperties()
  341. {
  342. // Perform request
  343. $response = $this->_performRequest('/', '?restype=service&comp=properties');
  344. if (!$response->isSuccessful()) {
  345. throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage(
  346. $response, 'Cannot obtain service properties.'
  347. ));
  348. }
  349. // turn the response from a SimpleXML object to an array
  350. $parsedResponse = $this->_parseResponse($response);
  351. $returnArray = array();
  352. foreach ($parsedResponse as $key => $propertyAsXmlNode) {
  353. $returnArray[$key] = $this->_parseServicePropertyResponseNode($propertyAsXmlNode);
  354. }
  355. return $returnArray;
  356. }
  357. /**
  358. * Parses a node of the service property response. A node is a direct child of the root
  359. * element (StorageServiceProperties).
  360. * Returns the array representation of that node.
  361. *
  362. * @param $responseNode
  363. * @return array
  364. */
  365. protected function _parseServicePropertyResponseNode($responseNode)
  366. {
  367. if ($responseNode->count() > 0) {
  368. $returnArray = array();
  369. foreach ($responseNode as $key => $childNode) {
  370. $returnArray[$key] = $this->_parseServicePropertyResponseNode($childNode);
  371. }
  372. return $returnArray;
  373. } else {
  374. return (string)$responseNode;
  375. }
  376. }
  377. /**
  378. * Perform request using Microsoft_Http_Client channel
  379. *
  380. * @param string $path Path
  381. * @param array $query Query parameters
  382. * @param string $httpVerb HTTP verb the request will use
  383. * @param array $headers x-ms headers to add
  384. * @param boolean $forTableStorage Is the request for table storage?
  385. * @param mixed $rawData Optional RAW HTTP data to be sent over the wire
  386. * @param string $resourceType Resource type
  387. * @param string $requiredPermission Required permission
  388. * @return Microsoft_Http_Response
  389. */
  390. protected function _performRequest(
  391. $path = '/',
  392. $query = array(),
  393. $httpVerb = Microsoft_Http_Client::GET,
  394. $headers = array(),
  395. $forTableStorage = false,
  396. $rawData = null,
  397. $resourceType = Microsoft_WindowsAzure_Storage::RESOURCE_UNKNOWN,
  398. $requiredPermission = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
  399. ) {
  400. // Clean path
  401. if (strpos($path, '/') !== 0) {
  402. $path = '/' . $path;
  403. }
  404. // Clean headers
  405. if (is_null($headers)) {
  406. $headers = array();
  407. }
  408. // Ensure cUrl will also work correctly:
  409. // - disable Content-Type if required
  410. // - disable Expect: 100 Continue
  411. if (!isset($headers["Content-Type"])) {
  412. $headers["Content-Type"] = '';
  413. }
  414. $headers["Expect"]= '';
  415. // Add version header
  416. $headers['x-ms-version'] = $this->_apiVersion;
  417. // Generate URL
  418. $path = str_replace(' ', '%20', $path);
  419. $requestUrl = $this->getBaseUrl() . $path;
  420. if (count($query) > 0) {
  421. $queryString = '';
  422. foreach ($query as $key => $value) {
  423. $queryString .= ($queryString ? '&' : '?') . rawurlencode($key) . '=' . rawurlencode($value);
  424. }
  425. $requestUrl .= $queryString;
  426. }
  427. // Sign request
  428. $requestUrl = $this->_credentials
  429. ->signRequestUrl($requestUrl, $resourceType, $requiredPermission);
  430. $requestHeaders = $this->_credentials
  431. ->signRequestHeaders($httpVerb, $path, $query, $headers, $forTableStorage, $resourceType, $requiredPermission, $rawData);
  432. // Prepare request
  433. $this->_httpClientChannel->resetParameters(true);
  434. $this->_httpClientChannel->setUri($requestUrl);
  435. $this->_httpClientChannel->setHeaders($requestHeaders);
  436. $this->_httpClientChannel->setRawData($rawData);
  437. // Execute request
  438. $response = $this->_retryPolicy->execute(
  439. array($this->_httpClientChannel, 'request'),
  440. array($httpVerb)
  441. );
  442. return $response;
  443. }
  444. /**
  445. * Parse result from Microsoft_Http_Response
  446. *
  447. * @param Microsoft_Http_Response $response Response from HTTP call
  448. * @return object
  449. * @throws Microsoft_WindowsAzure_Exception
  450. */
  451. protected function _parseResponse(Microsoft_Http_Response $response = null)
  452. {
  453. if (is_null($response)) {
  454. throw new Microsoft_WindowsAzure_Exception('Response should not be null.');
  455. }
  456. $xml = @simplexml_load_string($response->getBody());
  457. if ($xml !== false) {
  458. // Fetch all namespaces
  459. $namespaces = array_merge($xml->getNamespaces(true), $xml->getDocNamespaces(true));
  460. // Register all namespace prefixes
  461. foreach ($namespaces as $prefix => $ns) {
  462. if ($prefix != '') {
  463. $xml->registerXPathNamespace($prefix, $ns);
  464. }
  465. }
  466. }
  467. return $xml;
  468. }
  469. /**
  470. * Generate metadata headers
  471. *
  472. * @param array $metadata
  473. * @return HTTP headers containing metadata
  474. */
  475. protected function _generateMetadataHeaders($metadata = array())
  476. {
  477. // Validate
  478. if (!is_array($metadata)) {
  479. return array();
  480. }
  481. // Return headers
  482. $headers = array();
  483. foreach ($metadata as $key => $value) {
  484. if (strpos($value, "\r") !== false || strpos($value, "\n") !== false) {
  485. throw new Microsoft_WindowsAzure_Exception('Metadata cannot contain newline characters.');
  486. }
  487. if (!self::isValidMetadataName($key)) {
  488. 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.');
  489. }
  490. $headers["x-ms-meta-" . strtolower($key)] = $value;
  491. }
  492. return $headers;
  493. }
  494. /**
  495. * Parse metadata headers
  496. *
  497. * @param array $headers HTTP headers containing metadata
  498. * @return array
  499. */
  500. protected function _parseMetadataHeaders($headers = array())
  501. {
  502. // Validate
  503. if (!is_array($headers)) {
  504. return array();
  505. }
  506. // Return metadata
  507. $metadata = array();
  508. foreach ($headers as $key => $value) {
  509. if (substr(strtolower($key), 0, 10) == "x-ms-meta-") {
  510. $metadata[str_replace("x-ms-meta-", '', strtolower($key))] = $value;
  511. }
  512. }
  513. return $metadata;
  514. }
  515. /**
  516. * Parse metadata XML
  517. *
  518. * @param SimpleXMLElement $parentElement Element containing the Metadata element.
  519. * @return array
  520. */
  521. protected function _parseMetadataElement($element = null)
  522. {
  523. // Metadata present?
  524. if (!is_null($element) && isset($element->Metadata) && !is_null($element->Metadata)) {
  525. return get_object_vars($element->Metadata);
  526. }
  527. return array();
  528. }
  529. /**
  530. * Generate ISO 8601 compliant date string in UTC time zone
  531. *
  532. * @param int $timestamp
  533. * @return string
  534. */
  535. public function isoDate($timestamp = null)
  536. {
  537. $tz = @date_default_timezone_get();
  538. @date_default_timezone_set('UTC');
  539. if (is_null($timestamp)) {
  540. $timestamp = time();
  541. }
  542. $returnValue = str_replace('+00:00', '.0000000Z', @date('c', $timestamp));
  543. @date_default_timezone_set($tz);
  544. return $returnValue;
  545. }
  546. /**
  547. * Is valid metadata name?
  548. *
  549. * @param string $metadataName Metadata name
  550. * @return boolean
  551. */
  552. public static function isValidMetadataName($metadataName = '')
  553. {
  554. if (preg_match("/^[a-zA-Z0-9_@][a-zA-Z0-9_]*$/", $metadataName) === 0) {
  555. return false;
  556. }
  557. if ($metadataName == '') {
  558. return false;
  559. }
  560. return true;
  561. }
  562. }