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

/www/system/library/Zend/Queue/Adapter/Memcacheq.php

https://bitbucket.org/vmihailenco/zf-blog
PHP | 428 lines | 191 code | 64 blank | 173 comment | 28 complexity | aded6b6dda960032cae86d10b38d3d30 MD5 | raw file
  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_Queue
  17. * @subpackage Adapter
  18. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Memcacheq.php 20096 2010-01-06 02:05:09Z bkarwin $
  21. */
  22. /**
  23. * @see Zend_Queue_Adapter_AdapterAbstract
  24. */
  25. /**
  26. * Class for using connecting to a Zend_Cache-based queuing system
  27. *
  28. * @category Zend
  29. * @package Zend_Queue
  30. * @subpackage Adapter
  31. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  32. * @license http://framework.zend.com/license/new-bsd New BSD License
  33. */
  34. class Zend_Queue_Adapter_Memcacheq extends Zend_Queue_Adapter_AdapterAbstract
  35. {
  36. const DEFAULT_HOST = '127.0.0.1';
  37. const DEFAULT_PORT = 22201;
  38. const EOL = "\r\n";
  39. /**
  40. * @var Memcache
  41. */
  42. protected $_cache = null;
  43. /**
  44. * @var string
  45. */
  46. protected $_host = null;
  47. /**
  48. * @var integer
  49. */
  50. protected $_port = null;
  51. /**
  52. * @var resource
  53. */
  54. protected $_socket = null;
  55. /********************************************************************
  56. * Constructor / Destructor
  57. *********************************************************************/
  58. /**
  59. * Constructor
  60. *
  61. * @param array|Zend_Config $options
  62. * @param null|Zend_Queue $queue
  63. * @return void
  64. */
  65. public function __construct($options, Zend_Queue $queue = null)
  66. {
  67. if (!extension_loaded('memcache')) {
  68. throw new Zend_Queue_Exception('Memcache extension does not appear to be loaded');
  69. }
  70. parent::__construct($options, $queue);
  71. $options = &$this->_options['driverOptions'];
  72. if (!array_key_exists('host', $options)) {
  73. $options['host'] = self::DEFAULT_HOST;
  74. }
  75. if (!array_key_exists('port', $options)) {
  76. $options['port'] = self::DEFAULT_PORT;
  77. }
  78. $this->_cache = new Memcache();
  79. $result = $this->_cache->connect($options['host'], $options['port']);
  80. if ($result === false) {
  81. throw new Zend_Queue_Exception('Could not connect to MemcacheQ');
  82. }
  83. $this->_host = $options['host'];
  84. $this->_port = (int)$options['port'];
  85. }
  86. /**
  87. * Destructor
  88. *
  89. * @return void
  90. */
  91. public function __destruct()
  92. {
  93. if ($this->_cache instanceof Memcache) {
  94. $this->_cache->close();
  95. }
  96. if (is_resource($this->_socket)) {
  97. $cmd = 'quit' . self::EOL;
  98. fwrite($this->_socket, $cmd);
  99. fclose($this->_socket);
  100. }
  101. }
  102. /********************************************************************
  103. * Queue management functions
  104. *********************************************************************/
  105. /**
  106. * Does a queue already exist?
  107. *
  108. * Throws an exception if the adapter cannot determine if a queue exists.
  109. * use isSupported('isExists') to determine if an adapter can test for
  110. * queue existance.
  111. *
  112. * @param string $name
  113. * @return boolean
  114. * @throws Zend_Queue_Exception
  115. */
  116. public function isExists($name)
  117. {
  118. if (empty($this->_queues)) {
  119. $this->getQueues();
  120. }
  121. return in_array($name, $this->_queues);
  122. }
  123. /**
  124. * Create a new queue
  125. *
  126. * Visibility timeout is how long a message is left in the queue "invisible"
  127. * to other readers. If the message is acknowleged (deleted) before the
  128. * timeout, then the message is deleted. However, if the timeout expires
  129. * then the message will be made available to other queue readers.
  130. *
  131. * @param string $name queue name
  132. * @param integer $timeout default visibility timeout
  133. * @return boolean
  134. * @throws Zend_Queue_Exception
  135. */
  136. public function create($name, $timeout=null)
  137. {
  138. if ($this->isExists($name)) {
  139. return false;
  140. }
  141. if ($timeout === null) {
  142. $timeout = self::CREATE_TIMEOUT_DEFAULT;
  143. }
  144. // MemcacheQ does not have a method to "create" a queue
  145. // queues are created upon sending a packet.
  146. // We cannot use the send() and receive() functions because those
  147. // depend on the current name.
  148. $result = $this->_cache->set($name, 'creating queue', 0, 15);
  149. $result = $this->_cache->get($name);
  150. $this->_queues[] = $name;
  151. return true;
  152. }
  153. /**
  154. * Delete a queue and all of it's messages
  155. *
  156. * Returns false if the queue is not found, true if the queue exists
  157. *
  158. * @param string $name queue name
  159. * @return boolean
  160. * @throws Zend_Queue_Exception
  161. */
  162. public function delete($name)
  163. {
  164. $response = $this->_sendCommand('delete ' . $name, array('DELETED', 'NOT_FOUND'), true);
  165. if (in_array('DELETED', $response)) {
  166. $key = array_search($name, $this->_queues);
  167. if ($key !== false) {
  168. unset($this->_queues[$key]);
  169. }
  170. return true;
  171. }
  172. return false;
  173. }
  174. /**
  175. * Get an array of all available queues
  176. *
  177. * Not all adapters support getQueues(), use isSupported('getQueues')
  178. * to determine if the adapter supports this feature.
  179. *
  180. * @return array
  181. * @throws Zend_Queue_Exception
  182. */
  183. public function getQueues()
  184. {
  185. $this->_queues = array();
  186. $response = $this->_sendCommand('stats queue', array('END'));
  187. foreach ($response as $i => $line) {
  188. $this->_queues[] = str_replace('STAT ', '', $line);
  189. }
  190. return $this->_queues;
  191. }
  192. /**
  193. * Return the approximate number of messages in the queue
  194. *
  195. * @param Zend_Queue $queue
  196. * @return integer
  197. * @throws Zend_Queue_Exception (not supported)
  198. */
  199. public function count(Zend_Queue $queue=null)
  200. {
  201. throw new Zend_Queue_Exception('count() is not supported in this adapter');
  202. }
  203. /********************************************************************
  204. * Messsage management functions
  205. *********************************************************************/
  206. /**
  207. * Send a message to the queue
  208. *
  209. * @param string $message Message to send to the active queue
  210. * @param Zend_Queue $queue
  211. * @return Zend_Queue_Message
  212. * @throws Zend_Queue_Exception
  213. */
  214. public function send($message, Zend_Queue $queue=null)
  215. {
  216. if ($queue === null) {
  217. $queue = $this->_queue;
  218. }
  219. if (!$this->isExists($queue->getName())) {
  220. throw new Zend_Queue_Exception('Queue does not exist:' . $queue->getName());
  221. }
  222. $message = (string) $message;
  223. $data = array(
  224. 'message_id' => md5(uniqid(rand(), true)),
  225. 'handle' => null,
  226. 'body' => $message,
  227. 'md5' => md5($message),
  228. );
  229. $result = $this->_cache->set($queue->getName(), $message, 0, 0);
  230. if ($result === false) {
  231. throw new Zend_Queue_Exception('failed to insert message into queue:' . $queue->getName());
  232. }
  233. $options = array(
  234. 'queue' => $queue,
  235. 'data' => $data,
  236. );
  237. $classname = $queue->getMessageClass();
  238. if (!class_exists($classname)) {
  239. Zend_Loader::loadClass($classname);
  240. }
  241. return new $classname($options);
  242. }
  243. /**
  244. * Get messages in the queue
  245. *
  246. * @param integer $maxMessages Maximum number of messages to return
  247. * @param integer $timeout Visibility timeout for these messages
  248. * @param Zend_Queue $queue
  249. * @return Zend_Queue_Message_Iterator
  250. * @throws Zend_Queue_Exception
  251. */
  252. public function receive($maxMessages=null, $timeout=null, Zend_Queue $queue=null)
  253. {
  254. if ($maxMessages === null) {
  255. $maxMessages = 1;
  256. }
  257. if ($timeout === null) {
  258. $timeout = self::RECEIVE_TIMEOUT_DEFAULT;
  259. }
  260. if ($queue === null) {
  261. $queue = $this->_queue;
  262. }
  263. $msgs = array();
  264. if ($maxMessages > 0 ) {
  265. for ($i = 0; $i < $maxMessages; $i++) {
  266. $data = array(
  267. 'handle' => md5(uniqid(rand(), true)),
  268. 'body' => $this->_cache->get($queue->getName()),
  269. );
  270. $msgs[] = $data;
  271. }
  272. }
  273. $options = array(
  274. 'queue' => $queue,
  275. 'data' => $msgs,
  276. 'messageClass' => $queue->getMessageClass(),
  277. );
  278. $classname = $queue->getMessageSetClass();
  279. if (!class_exists($classname)) {
  280. Zend_Loader::loadClass($classname);
  281. }
  282. return new $classname($options);
  283. }
  284. /**
  285. * Delete a message from the queue
  286. *
  287. * Returns true if the message is deleted, false if the deletion is
  288. * unsuccessful.
  289. *
  290. * @param Zend_Queue_Message $message
  291. * @return boolean
  292. * @throws Zend_Queue_Exception (unsupported)
  293. */
  294. public function deleteMessage(Zend_Queue_Message $message)
  295. {
  296. throw new Zend_Queue_Exception('deleteMessage() is not supported in ' . get_class($this));
  297. }
  298. /********************************************************************
  299. * Supporting functions
  300. *********************************************************************/
  301. /**
  302. * Return a list of queue capabilities functions
  303. *
  304. * $array['function name'] = true or false
  305. * true is supported, false is not supported.
  306. *
  307. * @param string $name
  308. * @return array
  309. */
  310. public function getCapabilities()
  311. {
  312. return array(
  313. 'create' => true,
  314. 'delete' => true,
  315. 'send' => true,
  316. 'receive' => true,
  317. 'deleteMessage' => false,
  318. 'getQueues' => true,
  319. 'count' => false,
  320. 'isExists' => true,
  321. );
  322. }
  323. /********************************************************************
  324. * Functions that are not part of the Zend_Queue_Adapter_Abstract
  325. *********************************************************************/
  326. /**
  327. * sends a command to MemcacheQ
  328. *
  329. * The memcache functions by php cannot handle all types of requests
  330. * supported by MemcacheQ
  331. * Non-standard requests are handled by this function.
  332. *
  333. * @param string $command - command to send to memcacheQ
  334. * @param array $terminator - strings to indicate end of memcacheQ response
  335. * @param boolean $include_term - include terminator in response
  336. * @return array
  337. * @throws Zend_Queue_Exception if connection cannot be opened
  338. */
  339. protected function _sendCommand($command, array $terminator, $include_term=false)
  340. {
  341. if (!is_resource($this->_socket)) {
  342. $this->_socket = fsockopen($this->_host, $this->_port, $errno, $errstr, 10);
  343. }
  344. if ($this->_socket === false) {
  345. throw new Zend_Queue_Exception("Could not open a connection to $this->_host:$this->_port errno=$errno : $errstr");
  346. }
  347. $response = array();
  348. $cmd = $command . self::EOL;
  349. fwrite($this->_socket, $cmd);
  350. $continue_reading = true;
  351. while (!feof($this->_socket) && $continue_reading) {
  352. $resp = trim(fgets($this->_socket, 1024));
  353. if (in_array($resp, $terminator)) {
  354. if ($include_term) {
  355. $response[] = $resp;
  356. }
  357. $continue_reading = false;
  358. } else {
  359. $response[] = $resp;
  360. }
  361. }
  362. return $response;
  363. }
  364. }