PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/MoodleWebRole/azure/Microsoft/WindowsAzure/Storage/Queue.php

#
PHP | 552 lines | 291 code | 57 blank | 204 comment | 82 complexity | 8c6c6c4ed1da2cbdeefd47e0d5b35ddc MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, LGPL-2.0, GPL-2.0
  1. <?php
  2. /**
  3. * Copyright (c) 2009, 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, RealDolmen (http://www.realdolmen.com)
  32. * @license http://todo name_todo
  33. * @version $Id: Blob.php 24241 2009-07-22 09:43:13Z unknown $
  34. */
  35. /**
  36. * @see Microsoft_WindowsAzure_SharedKeyCredentials
  37. */
  38. require_once 'Microsoft/WindowsAzure/SharedKeyCredentials.php';
  39. /**
  40. * @see Microsoft_WindowsAzure_RetryPolicy
  41. */
  42. require_once 'Microsoft/WindowsAzure/RetryPolicy.php';
  43. /**
  44. * @see Microsoft_Http_Transport
  45. */
  46. require_once 'Microsoft/Http/Transport.php';
  47. /**
  48. * @see Microsoft_Http_Response
  49. */
  50. require_once 'Microsoft/Http/Response.php';
  51. /**
  52. * @see Microsoft_WindowsAzure_Storage
  53. */
  54. require_once 'Microsoft/WindowsAzure/Storage.php';
  55. /**
  56. * Microsoft_WindowsAzure_Storage_QueueInstance
  57. */
  58. require_once 'Microsoft/WindowsAzure/Storage/QueueInstance.php';
  59. /**
  60. * Microsoft_WindowsAzure_Storage_QueueMessage
  61. */
  62. require_once 'Microsoft/WindowsAzure/Storage/QueueMessage.php';
  63. /**
  64. * @see Microsoft_WindowsAzure_Exception
  65. */
  66. require_once 'Microsoft/WindowsAzure/Exception.php';
  67. /**
  68. * @category Microsoft
  69. * @package Microsoft_WindowsAzure
  70. * @subpackage Storage
  71. * @copyright Copyright (c) 2009, RealDolmen (http://www.realdolmen.com)
  72. * @license http://phpazure.codeplex.com/license
  73. */
  74. class Microsoft_WindowsAzure_Storage_Queue extends Microsoft_WindowsAzure_Storage
  75. {
  76. /**
  77. * Maximal message size (in bytes)
  78. */
  79. const MAX_MESSAGE_SIZE = 8388608;
  80. /**
  81. * Maximal message ttl (in seconds)
  82. */
  83. const MAX_MESSAGE_TTL = 604800;
  84. /**
  85. * Creates a new Microsoft_WindowsAzure_Storage_Queue instance
  86. *
  87. * @param string $host Storage host name
  88. * @param string $accountName Account name for Windows Azure
  89. * @param string $accountKey Account key for Windows Azure
  90. * @param boolean $usePathStyleUri Use path-style URI's
  91. * @param Microsoft_WindowsAzure_RetryPolicy $retryPolicy Retry policy to use when making requests
  92. */
  93. public function __construct($host = Microsoft_WindowsAzure_Storage::URL_DEV_QUEUE, $accountName = Microsoft_WindowsAzure_SharedKeyCredentials::DEVSTORE_ACCOUNT, $accountKey = Microsoft_WindowsAzure_SharedKeyCredentials::DEVSTORE_KEY, $usePathStyleUri = false, Microsoft_WindowsAzure_RetryPolicy $retryPolicy = null)
  94. {
  95. parent::__construct($host, $accountName, $accountKey, $usePathStyleUri, $retryPolicy);
  96. // API version
  97. $this->_apiVersion = '2009-04-14';
  98. }
  99. /**
  100. * Check if a queue exists
  101. *
  102. * @param string $queueName Queue name
  103. * @return boolean
  104. */
  105. public function queueExists($queueName = '')
  106. {
  107. if ($queueName === '')
  108. throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.');
  109. if (!self::isValidQueueName($queueName))
  110. throw new Microsoft_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
  111. // List queues
  112. $queues = $this->listQueues($queueName, 1);
  113. foreach ($queues as $queue)
  114. {
  115. if ($queue->Name == $queueName)
  116. return true;
  117. }
  118. return false;
  119. }
  120. /**
  121. * Create queue
  122. *
  123. * @param string $queueName Queue name
  124. * @param array $metadata Key/value pairs of meta data
  125. * @return object Queue properties
  126. * @throws Microsoft_WindowsAzure_Exception
  127. */
  128. public function createQueue($queueName = '', $metadata = array())
  129. {
  130. if ($queueName === '')
  131. throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.');
  132. if (!self::isValidQueueName($queueName))
  133. throw new Microsoft_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
  134. // Create metadata headers
  135. $headers = array();
  136. foreach ($metadata as $key => $value)
  137. {
  138. $headers["x-ms-meta-" . strtolower($key)] = $value;
  139. }
  140. // Perform request
  141. $response = $this->performRequest($queueName, '', Microsoft_Http_Transport::VERB_PUT, $headers);
  142. if ($response->isSuccessful())
  143. {
  144. return new Microsoft_WindowsAzure_Storage_QueueInstance(
  145. $queueName,
  146. $metadata
  147. );
  148. }
  149. else
  150. {
  151. throw new Microsoft_WindowsAzure_Exception($this->getErrorMessage($response, 'Resource could not be accessed.'));
  152. }
  153. }
  154. /**
  155. * Get queue
  156. *
  157. * @param string $queueName Queue name
  158. * @return Microsoft_WindowsAzure_Storage_QueueInstance
  159. * @throws Microsoft_WindowsAzure_Exception
  160. */
  161. public function getQueue($queueName = '')
  162. {
  163. if ($queueName === '')
  164. throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.');
  165. if (!self::isValidQueueName($queueName))
  166. throw new Microsoft_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
  167. // Perform request
  168. $response = $this->performRequest($queueName, '?comp=metadata', Microsoft_Http_Transport::VERB_GET);
  169. if ($response->isSuccessful())
  170. {
  171. // Parse metadata
  172. $metadata = array();
  173. foreach ($response->getHeaders() as $key => $value)
  174. {
  175. if (substr(strtolower($key), 0, 10) == "x-ms-meta-")
  176. {
  177. $metadata[str_replace("x-ms-meta-", '', strtolower($key))] = $value;
  178. }
  179. }
  180. // Return queue
  181. $queue = new Microsoft_WindowsAzure_Storage_QueueInstance(
  182. $queueName,
  183. $metadata
  184. );
  185. $queue->ApproximateMessageCount = intval($response->getHeader('x-ms-approximate-message-count'));
  186. return $queue;
  187. }
  188. else
  189. {
  190. throw new Microsoft_WindowsAzure_Exception($this->getErrorMessage($response, 'Resource could not be accessed.'));
  191. }
  192. }
  193. /**
  194. * Get queue metadata
  195. *
  196. * @param string $queueName Queue name
  197. * @return array Key/value pairs of meta data
  198. * @throws Microsoft_WindowsAzure_Exception
  199. */
  200. public function getQueueMetadata($queueName = '')
  201. {
  202. if ($queueName === '')
  203. throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.');
  204. if (!self::isValidQueueName($queueName))
  205. throw new Microsoft_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
  206. return $this->getQueue($queueName)->Metadata;
  207. }
  208. /**
  209. * Set queue metadata
  210. *
  211. * Calling the Set Queue Metadata operation overwrites all existing metadata that is associated with the queue. It's not possible to modify an individual name/value pair.
  212. *
  213. * @param string $queueName Queue name
  214. * @param array $metadata Key/value pairs of meta data
  215. * @throws Microsoft_WindowsAzure_Exception
  216. */
  217. public function setQueueMetadata($queueName = '', $metadata = array())
  218. {
  219. if ($queueName === '')
  220. throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.');
  221. if (!self::isValidQueueName($queueName))
  222. throw new Microsoft_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
  223. if (count($metadata) == 0)
  224. return;
  225. // Create metadata headers
  226. $headers = array();
  227. foreach ($metadata as $key => $value)
  228. {
  229. $headers["x-ms-meta-" . strtolower($key)] = $value;
  230. }
  231. // Perform request
  232. $response = $this->performRequest($queueName, '?comp=metadata', Microsoft_Http_Transport::VERB_PUT, $headers);
  233. if (!$response->isSuccessful())
  234. throw new Microsoft_WindowsAzure_Exception($this->getErrorMessage($response, 'Resource could not be accessed.'));
  235. }
  236. /**
  237. * Delete queue
  238. *
  239. * @param string $queueName Queue name
  240. * @throws Microsoft_WindowsAzure_Exception
  241. */
  242. public function deleteQueue($queueName = '')
  243. {
  244. if ($queueName === '')
  245. throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.');
  246. if (!self::isValidQueueName($queueName))
  247. throw new Microsoft_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
  248. // Perform request
  249. $response = $this->performRequest($queueName, '', Microsoft_Http_Transport::VERB_DELETE);
  250. if (!$response->isSuccessful())
  251. throw new Microsoft_WindowsAzure_Exception($this->getErrorMessage($response, 'Resource could not be accessed.'));
  252. }
  253. /**
  254. * List queues
  255. *
  256. * @param string $prefix Optional. Filters the results to return only queues whose name begins with the specified prefix.
  257. * @param int $maxResults Optional. Specifies the maximum number of queues to return per call to Azure storage. This does NOT affect list size returned by this function. (maximum: 5000)
  258. * @param string $marker Optional string value that identifies the portion of the list to be returned with the next list operation.
  259. * @param int $currentResultCount Current result count (internal use)
  260. * @return array
  261. * @throws Microsoft_WindowsAzure_Exception
  262. */
  263. public function listQueues($prefix = null, $maxResults = null, $marker = null, $currentResultCount = 0)
  264. {
  265. // Build query string
  266. $queryString = '?comp=list';
  267. if (!is_null($prefix))
  268. $queryString .= '&prefix=' . $prefix;
  269. if (!is_null($maxResults))
  270. $queryString .= '&maxresults=' . $maxResults;
  271. if (!is_null($marker))
  272. $queryString .= '&marker=' . $marker;
  273. // Perform request
  274. $response = $this->performRequest('', $queryString, Microsoft_Http_Transport::VERB_GET);
  275. if ($response->isSuccessful())
  276. {
  277. $xmlQueues = $this->parseResponse($response)->Queues->Queue;
  278. $xmlMarker = (string)$this->parseResponse($response)->NextMarker;
  279. $queues = array();
  280. if (!is_null($xmlQueues))
  281. {
  282. for ($i = 0; $i < count($xmlQueues); $i++)
  283. {
  284. $queues[] = new Microsoft_WindowsAzure_Storage_QueueInstance(
  285. (string)$xmlQueues[$i]->QueueName
  286. );
  287. }
  288. }
  289. $currentResultCount = $currentResultCount + count($queues);
  290. if (!is_null($maxResults) && $currentResultCount < $maxResults)
  291. {
  292. if (!is_null($xmlMarker) && $xmlMarker != '')
  293. {
  294. $queues = array_merge($queues, $this->listQueues($prefix, $maxResults, $xmlMarker, $currentResultCount));
  295. }
  296. }
  297. if (!is_null($maxResults) && count($queues) > $maxResults)
  298. $queues = array_slice($queues, 0, $maxResults);
  299. return $queues;
  300. }
  301. else
  302. {
  303. throw new Microsoft_WindowsAzure_Exception($this->getErrorMessage($response, 'Resource could not be accessed.'));
  304. }
  305. }
  306. /**
  307. * Put message into queue
  308. *
  309. * @param string $queueName Queue name
  310. * @param string $message Message
  311. * @param int $ttl Message Time-To-Live (in seconds). Defaults to 7 days if the parameter is omitted.
  312. * @throws Microsoft_WindowsAzure_Exception
  313. */
  314. public function putMessage($queueName = '', $message = '', $ttl = null)
  315. {
  316. if ($queueName === '')
  317. throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.');
  318. if (!self::isValidQueueName($queueName))
  319. throw new Microsoft_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
  320. if (strlen($message) > self::MAX_MESSAGE_SIZE)
  321. throw new Microsoft_WindowsAzure_Exception('Message is too big. Message content should be < 8KB.');
  322. if ($message == '')
  323. throw new Microsoft_WindowsAzure_Exception('Message is not specified.');
  324. if (!is_null($ttl) && ($ttl <= 0 || $ttl > self::MAX_MESSAGE_SIZE))
  325. throw new Microsoft_WindowsAzure_Exception('Message TTL is invalid. Maximal TTL is 7 days (' . self::MAX_MESSAGE_SIZE . ' seconds) and should be greater than zero.');
  326. // Build query string
  327. $queryString = '';
  328. if (!is_null($ttl))
  329. $queryString .= '?messagettl=' . $ttl;
  330. // Build body
  331. $rawData = '';
  332. $rawData .= '<QueueMessage>';
  333. $rawData .= ' <MessageText>' . base64_encode($message) . '</MessageText>';
  334. $rawData .= '</QueueMessage>';
  335. // Perform request
  336. $response = $this->performRequest($queueName . '/messages', $queryString, Microsoft_Http_Transport::VERB_POST, array(), false, $rawData);
  337. if (!$response->isSuccessful())
  338. {
  339. throw new Microsoft_WindowsAzure_Exception('Error putting message into queue.');
  340. }
  341. }
  342. /**
  343. * Get queue messages
  344. *
  345. * @param string $queueName Queue name
  346. * @param string $numOfMessages Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a maximum of 32. By default, a single message is retrieved from the queue with this operation.
  347. * @param int $visibilityTimeout Optional. An integer value that specifies the message's visibility timeout in seconds. The maximum value is 2 hours. The default message visibility timeout is 30 seconds.
  348. * @param string $peek Peek only?
  349. * @return array
  350. * @throws Microsoft_WindowsAzure_Exception
  351. */
  352. public function getMessages($queueName = '', $numOfMessages = 1, $visibilityTimeout = null, $peek = false)
  353. {
  354. if ($queueName === '')
  355. throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.');
  356. if (!self::isValidQueueName($queueName))
  357. throw new Microsoft_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
  358. if ($numOfMessages < 1 || $numOfMessages > 32 || intval($numOfMessages) != $numOfMessages)
  359. throw new Microsoft_WindowsAzure_Exception('Invalid number of messages to retrieve.');
  360. if (!is_null($visibilityTimeout) && ($visibilityTimeout <= 0 || $visibilityTimeout > 7200))
  361. throw new Microsoft_WindowsAzure_Exception('Visibility timeout is invalid. Maximum value is 2 hours (7200 seconds) and should be greater than zero.');
  362. // Build query string
  363. $query = array();
  364. if ($peek)
  365. $query[] = 'peekonly=true';
  366. if ($numOfMessages > 1)
  367. $query[] = 'numofmessages=' . $numOfMessages;
  368. if (!$peek && !is_null($visibilityTimeout))
  369. $query[] = 'visibilitytimeout=' . $visibilityTimeout;
  370. $queryString = '?' . implode('&', $query);
  371. // Perform request
  372. $response = $this->performRequest($queueName . '/messages', $queryString, Microsoft_Http_Transport::VERB_GET);
  373. if ($response->isSuccessful())
  374. {
  375. // Parse results
  376. $result = $this->parseResponse($response);
  377. if (!$result)
  378. return array();
  379. $xmlMessages = null;
  380. if (count($result->QueueMessage) > 1)
  381. {
  382. $xmlMessages = $result->QueueMessage;
  383. }
  384. else
  385. {
  386. $xmlMessages = array($result->QueueMessage);
  387. }
  388. $messages = array();
  389. for ($i = 0; $i < count($xmlMessages); $i++)
  390. {
  391. $messages[] = new Microsoft_WindowsAzure_Storage_QueueMessage(
  392. (string)$xmlMessages[$i]->MessageId,
  393. (string)$xmlMessages[$i]->InsertionTime,
  394. (string)$xmlMessages[$i]->ExpirationTime,
  395. ($peek ? '' : (string)$xmlMessages[$i]->PopReceipt),
  396. ($peek ? '' : (string)$xmlMessages[$i]->TimeNextVisible),
  397. base64_decode((string)$xmlMessages[$i]->MessageText)
  398. );
  399. }
  400. return $messages;
  401. }
  402. else
  403. {
  404. throw new Microsoft_WindowsAzure_Exception($this->getErrorMessage($response, 'Resource could not be accessed.'));
  405. }
  406. }
  407. /**
  408. * Peek queue messages
  409. *
  410. * @param string $queueName Queue name
  411. * @param string $numOfMessages Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a maximum of 32. By default, a single message is retrieved from the queue with this operation.
  412. * @return array
  413. * @throws Microsoft_WindowsAzure_Exception
  414. */
  415. public function peekMessages($queueName = '', $numOfMessages = 1)
  416. {
  417. return $this->getMessages($queueName, $numOfMessages, null, true);
  418. }
  419. /**
  420. * Clear queue messages
  421. *
  422. * @param string $queueName Queue name
  423. * @throws Microsoft_WindowsAzure_Exception
  424. */
  425. public function clearMessages($queueName = '')
  426. {
  427. if ($queueName === '')
  428. throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.');
  429. if (!self::isValidQueueName($queueName))
  430. throw new Microsoft_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
  431. // Perform request
  432. $response = $this->performRequest($queueName . '/messages', '', Microsoft_Http_Transport::VERB_DELETE);
  433. if (!$response->isSuccessful())
  434. {
  435. throw new Microsoft_WindowsAzure_Exception('Error clearing messages from queue.');
  436. }
  437. }
  438. /**
  439. * Delete queue message
  440. *
  441. * @param string $queueName Queue name
  442. * @param Microsoft_WindowsAzure_Storage_QueueMessage $message Message to delete from queue. A message retrieved using "peekMessages" can NOT be deleted!
  443. * @throws Microsoft_WindowsAzure_Exception
  444. */
  445. public function deleteMessage($queueName = '', Microsoft_WindowsAzure_Storage_QueueMessage $message)
  446. {
  447. if ($queueName === '')
  448. throw new Microsoft_WindowsAzure_Exception('Queue name is not specified.');
  449. if (!self::isValidQueueName($queueName))
  450. throw new Microsoft_WindowsAzure_Exception('Queue name does not adhere to queue naming conventions. See http://msdn.microsoft.com/en-us/library/dd179349.aspx for more information.');
  451. if ($message->PopReceipt == '')
  452. throw new Microsoft_WindowsAzure_Exception('A message retrieved using "peekMessages" can NOT be deleted! Use "getMessages" instead.');
  453. // Perform request
  454. $response = $this->performRequest($queueName . '/messages/' . $message->MessageId, '?popreceipt=' . $message->PopReceipt, Microsoft_Http_Transport::VERB_DELETE);
  455. if (!$response->isSuccessful())
  456. {
  457. throw new Microsoft_WindowsAzure_Exception($this->getErrorMessage($response, 'Resource could not be accessed.'));
  458. }
  459. }
  460. /**
  461. * Is valid queue name?
  462. *
  463. * @param string $queueName Queue name
  464. * @return boolean
  465. */
  466. public static function isValidQueueName($queueName = '')
  467. {
  468. if (!ereg("^[a-z0-9][a-z0-9-]*$", $queueName))
  469. return false;
  470. if (strpos($queueName, '--') !== false)
  471. return false;
  472. if (strtolower($queueName) != $queueName)
  473. return false;
  474. if (strlen($queueName) < 3 || strlen($queueName) > 63)
  475. return false;
  476. if (substr($queueName, -1) == '-')
  477. return false;
  478. return true;
  479. }
  480. /**
  481. * Get error message from Microsoft_Http_Response
  482. *
  483. * @param Microsoft_Http_Response $response Repsonse
  484. * @param string $alternativeError Alternative error message
  485. * @return string
  486. */
  487. protected function getErrorMessage(Microsoft_Http_Response $response, $alternativeError = 'Unknown error.')
  488. {
  489. $response = $this->parseResponse($response);
  490. if ($response && $response->Message)
  491. return (string)$response->Message;
  492. else
  493. return $alternativeError;
  494. }
  495. }