PageRenderTime 61ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 1ms

/3.3/Pubnub.php

https://github.com/camcima/pubnub-php-api
PHP | 513 lines | 289 code | 88 blank | 136 comment | 46 complexity | d546768656aa8c713538c68bd9760fd3 MD5 | raw file
  1. <?php
  2. require_once('PubnubAES.php');
  3. /**
  4. * PubNub 3.3 Real-time Push Cloud API
  5. * @package Pubnub
  6. */
  7. class Pubnub
  8. {
  9. private $ORIGIN = 'pubsub.pubnub.com';
  10. private $PUBLISH_KEY = 'demo';
  11. private $SUBSCRIBE_KEY = 'demo';
  12. private $SECRET_KEY = false;
  13. private $CIPHER_KEY = '';
  14. private $SSL = false;
  15. private $SESSION_UUID = '';
  16. /**
  17. * Pubnub
  18. *
  19. * Init the Pubnub Client API
  20. *
  21. * @param string $publish_key required key to send messages.
  22. * @param string $subscribe_key required key to receive messages.
  23. * @param string $secret_key optional key to sign messages.
  24. * @param string $origin optional setting for cloud origin.
  25. * @param boolean $ssl required for 2048 bit encrypted messages.
  26. */
  27. function Pubnub(
  28. $publish_key = 'demo',
  29. $subscribe_key = 'demo',
  30. $secret_key = false,
  31. $cipher_key = false,
  32. $ssl = false,
  33. $origin = false
  34. )
  35. {
  36. $this->SESSION_UUID = $this->uuid();
  37. $this->PUBLISH_KEY = $publish_key;
  38. $this->SUBSCRIBE_KEY = $subscribe_key;
  39. $this->SECRET_KEY = $secret_key;
  40. if (!isBlank($cipher_key)) {
  41. $this->CIPHER_KEY = $cipher_key;
  42. }
  43. $this->SSL = $ssl;
  44. if ($origin)
  45. $this->ORIGIN = $origin;
  46. if ($ssl)
  47. $this->ORIGIN = 'https://' . $this->ORIGIN;
  48. else
  49. $this->ORIGIN = 'http://' . $this->ORIGIN;
  50. }
  51. /**
  52. * Publish
  53. *
  54. * Send a message to a channel.
  55. *
  56. * @param array $args with channel and message.
  57. * @return array success information.
  58. */
  59. function publish($args)
  60. {
  61. ## Fail if bad input.
  62. if (!(isset($args['channel']) && isset($args['message']))) {
  63. echo('Missing Channel or Message');
  64. return false;
  65. }
  66. ## Capture User Input
  67. $channel = $args['channel'];
  68. $message_org = $args['message'];
  69. $message = $this->sendMessage($message_org);
  70. ## Sign Message
  71. $signature = "0";
  72. if ($this->SECRET_KEY) {
  73. ## Generate String to Sign
  74. $string_to_sign = implode('/', array(
  75. $this->PUBLISH_KEY,
  76. $this->SUBSCRIBE_KEY,
  77. $this->SECRET_KEY,
  78. $channel,
  79. $message
  80. ));
  81. $signature = md5($string_to_sign);
  82. }
  83. ## Send Message
  84. $publishResponse = $this->_request(array(
  85. 'publish',
  86. $this->PUBLISH_KEY,
  87. $this->SUBSCRIBE_KEY,
  88. $signature,
  89. $channel,
  90. '0',
  91. $message
  92. ));
  93. if ($publishResponse == null)
  94. return array(0, "Error during publish.");
  95. else
  96. return $publishResponse;
  97. }
  98. public function sendMessage($message_org)
  99. {
  100. if ($this->CIPHER_KEY != false) {
  101. $message = json_encode(encrypt(json_encode($message_org), $this->CIPHER_KEY));
  102. } else {
  103. $message = json_encode($message_org);
  104. }
  105. return $message;
  106. }
  107. function here_now($args)
  108. {
  109. if (!($args['channel'])) {
  110. echo('Missing Channel');
  111. return false;
  112. }
  113. ## Capture User Input
  114. $channel = $args['channel'];
  115. return $this->_request(array(
  116. 'v2',
  117. 'presence',
  118. 'sub_key',
  119. $this->SUBSCRIBE_KEY,
  120. 'channel',
  121. $channel
  122. ));
  123. }
  124. /**
  125. * Subscribe
  126. *
  127. * This is BLOCKING.
  128. * Listen for a message on a channel.
  129. *
  130. * @param array $args with channel and message.
  131. * @return mixed false on fail, array on success.
  132. */
  133. function subscribe($args, $presence = false)
  134. {
  135. ## Capture User Input
  136. $channel = $args['channel'];
  137. $callback = $args['callback'];
  138. $timetoken = isset($args['timetoken']) ? $args['timetoken'] : '0';
  139. ## Fail if missing channel
  140. if (!$channel) {
  141. echo("Missing Channel.\n");
  142. return false;
  143. }
  144. ## Fail if missing callback
  145. if (!$callback) {
  146. echo("Missing Callback.\n");
  147. return false;
  148. }
  149. if ($presence == true) {
  150. $mode = "presence";
  151. } else
  152. $mode = "default";
  153. while (1) {
  154. try {
  155. ## Wait for Message
  156. $response = $this->_request(array(
  157. 'subscribe',
  158. $this->SUBSCRIBE_KEY,
  159. $channel,
  160. '0',
  161. $timetoken
  162. ));
  163. if ($response == "_PUBNUB_TIMEOUT") {
  164. continue;
  165. } elseif ($response == "_PUBNUB_MESSAGE_TOO_LARGE") {
  166. $timetoken = $this->throwAndResetTimetoken($callback, "Message Too Large");
  167. continue;
  168. } elseif ($response == null || $timetoken == null) {
  169. $timetoken = $this->throwAndResetTimetoken($callback, "Bad server response.");
  170. continue;
  171. }
  172. $messages = $response[0];
  173. $timetoken = $response[1];
  174. if (!count($messages)) {
  175. continue;
  176. }
  177. $receivedMessages = $this->decodeAndDecrypt($messages, $mode);
  178. $returnArray = array($receivedMessages, $timetoken);
  179. $cbReturn = $callback($returnArray);
  180. if ($cbReturn == false) {
  181. return;
  182. }
  183. } catch (Exception $error) {
  184. $this->handleError($error, $args);
  185. $timetoken = $this->throwAndResetTimetoken($callback, "Unknown error.");
  186. continue;
  187. }
  188. }
  189. }
  190. public function throwAndResetTimetoken($callback, $errorMessage)
  191. {
  192. $callback(array(0, $errorMessage));
  193. $timetoken = "0";
  194. return $timetoken;
  195. }
  196. public function decodeAndDecrypt($messages, $mode = "default")
  197. {
  198. $receivedMessages = array();
  199. if ($mode == "presence") {
  200. return $messages;
  201. } elseif ($mode == "default") {
  202. $messageArray = $messages;
  203. $receivedMessages = $this->decodeDecryptLoop($messageArray);
  204. } elseif ($mode == "detailedHistory") {
  205. $messageArray = $messages[0];
  206. $receivedMessages = $this->decodeDecryptLoop($messageArray);
  207. }
  208. return $receivedMessages;
  209. }
  210. public function decodeDecryptLoop($messageArray)
  211. {
  212. $receivedMessages = array();
  213. foreach ($messageArray as $message) {
  214. if ($this->CIPHER_KEY) {
  215. $decryptedMessage = decrypt($message, $this->CIPHER_KEY);
  216. $message = json_decode($decryptedMessage, true);
  217. }
  218. array_push($receivedMessages, $message);
  219. }
  220. return $receivedMessages;
  221. }
  222. public function handleError($error, $args)
  223. {
  224. $errorMsg = 'Error on line ' . $error->getLine() . ' in ' . $error->getFile() . $error->getMessage();
  225. trigger_error($errorMsg, E_COMPILE_WARNING);
  226. sleep(1);
  227. }
  228. /**
  229. * Presence
  230. *
  231. * This is BLOCKING.
  232. * Listen for a message on a channel.
  233. *
  234. * @param array $args with channel and message.
  235. * @return mixed false on fail, array on success.
  236. */
  237. function presence($args)
  238. {
  239. ## Capture User Input
  240. $args['channel'] = ($args['channel'] . "-pnpres");
  241. $this->subscribe($args, true);
  242. }
  243. /**
  244. * Detailed History
  245. *
  246. * Load history from a channel.
  247. *
  248. * @param array $args with 'channel' and 'limit'.
  249. * @return mixed false on fail, array on success.
  250. */
  251. function detailedHistory($args)
  252. {
  253. ## Capture User Input
  254. ## Fail if bad input.
  255. if (!$args['channel']) {
  256. echo('Missing Channel');
  257. return false;
  258. }
  259. $channel = $args['channel'];
  260. $urlParams = "";
  261. if ($args['count'] || $args['start'] || $args['end'] || $args['reverse']) {
  262. $urlParamSep = "?";
  263. if (isset($args['count'])) {
  264. $urlParams .= $urlParamSep . "count=" . $args['count'];
  265. $urlParamSep = "&";
  266. }
  267. if (isset($args['start'])) {
  268. $urlParams .= $urlParamSep . "start=" . $args['start'];
  269. $urlParamSep = "&";
  270. }
  271. if (isset($args['end'])) {
  272. $urlParams .= $urlParamSep . "end=" . $args['end'];
  273. $urlParamSep = "&";
  274. }
  275. if (isset($args['reverse'])) {
  276. $urlParams .= $urlParamSep . "reverse=" . $args['reverse'];
  277. }
  278. }
  279. $response = $this->_request(array(
  280. 'v2',
  281. 'history',
  282. "sub-key",
  283. $this->SUBSCRIBE_KEY,
  284. "channel",
  285. $channel
  286. ), $urlParams);
  287. ;
  288. $receivedMessages = $this->decodeAndDecrypt($response, "detailedHistory");
  289. return $receivedMessages;
  290. }
  291. /**
  292. * History
  293. *
  294. * Load history from a channel.
  295. *
  296. * @param array $args with 'channel' and 'limit'.
  297. * @return mixed false on fail, array on success.
  298. */
  299. function history($args)
  300. {
  301. ## Capture User Input
  302. $limit = +$args['limit'] ? +$args['limit'] : 10;
  303. $channel = $args['channel'];
  304. ## Fail if bad input.
  305. if (!$channel) {
  306. echo('Missing Channel');
  307. return false;
  308. }
  309. ## Get History
  310. $response = $this->_request(array(
  311. 'history',
  312. $this->SUBSCRIBE_KEY,
  313. $channel,
  314. '0',
  315. $limit
  316. ));
  317. ;
  318. $receivedMessages = $this->decodeAndDecrypt($response);
  319. return $receivedMessages;
  320. }
  321. /**
  322. * Time
  323. *
  324. * Timestamp from PubNub Cloud.
  325. *
  326. * @return int timestamp.
  327. */
  328. function time()
  329. {
  330. ## Get History
  331. $response = $this->_request(array(
  332. 'time',
  333. '0'
  334. ));
  335. return $response[0];
  336. }
  337. /**
  338. * UUID
  339. *
  340. * UUID generator
  341. *
  342. * @return UUID
  343. */
  344. function uuid()
  345. {
  346. if (function_exists('com_create_guid') === true) {
  347. return trim(com_create_guid(), '{}');
  348. }
  349. return sprintf('%04X%04X-%04X-%04X-%04X-%04X%04X%04X', mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(16384, 20479), mt_rand(32768, 49151), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535));
  350. }
  351. /**
  352. * Request URL
  353. *
  354. * @param array $request of url directories.
  355. * @return array from JSON response.
  356. */
  357. private function _request($request, $urlParams = false)
  358. {
  359. $request = array_map('Pubnub::_encode', $request);
  360. array_unshift($request, $this->ORIGIN);
  361. if (($request[1] === 'presence') || ($request[1] === 'subscribe')) {
  362. array_push($request, '?uuid=' . $this->SESSION_UUID);
  363. }
  364. $urlString = implode('/', $request);
  365. if ($urlParams) {
  366. $urlString .= $urlParams;
  367. }
  368. $ch = curl_init();
  369. $pubnubHeaders = array("V: 3.3", "Accept: */*");
  370. curl_setopt($ch, CURLOPT_HTTPHEADER, $pubnubHeaders);
  371. curl_setopt($ch, CURLOPT_USERAGENT, "PHP");
  372. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  373. curl_setopt($ch, CURLOPT_TIMEOUT, 300);
  374. curl_setopt($ch, CURLOPT_URL, $urlString);
  375. if ($this->SSL) {
  376. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
  377. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
  378. curl_setopt($ch, CURLOPT_CAINFO, getcwd() . "/pubnub.com.pem");
  379. }
  380. $output = curl_exec($ch);
  381. $curlError = curl_errno($ch);
  382. $curlResponseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  383. curl_close($ch);
  384. $JSONdecodedResponse = json_decode($output, true);
  385. if ($JSONdecodedResponse != null)
  386. return $JSONdecodedResponse;
  387. elseif ($curlError == 28)
  388. return "_PUBNUB_TIMEOUT";
  389. elseif ($curlResponseCode == 400 || $curlResponseCode == 404)
  390. return "_PUBNUB_MESSAGE_TOO_LARGE";
  391. }
  392. /**
  393. * Encode
  394. *
  395. * @param string $part of url directories.
  396. * @return string encoded string.
  397. */
  398. private static function _encode($part)
  399. {
  400. $pieces = array_map('Pubnub::_encode_char', str_split($part));
  401. return implode('', $pieces);
  402. }
  403. /**
  404. * Encode Char
  405. *
  406. * @param string $char val.
  407. * @return string encoded char.
  408. */
  409. private static function _encode_char($char)
  410. {
  411. if (strpos(' ~`!@#$%^&*()+=[]\\{}|;\':",./<>?', $char) === false)
  412. return $char;
  413. else
  414. return rawurlencode($char);
  415. }
  416. }
  417. ?>