PageRenderTime 100ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Zend/Service/WindowsAzure/Storage/Queue.php

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