PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Zend/Mobile/Push/Apns.php

https://gitlab.com/axeltizon/magentoV1.9-demopoweraccess
PHP | 391 lines | 209 code | 36 blank | 146 comment | 30 complexity | 8a9b4c310458933c7af0d067b1da1640 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_Mobile
  17. * @subpackage Zend_Mobile_Push
  18. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  21. */
  22. /** Zend_Mobile_Push_Abstract **/
  23. #require_once 'Zend/Mobile/Push/Abstract.php';
  24. /** Zend_Mobile_Push_Message_Apns **/
  25. #require_once 'Zend/Mobile/Push/Message/Apns.php';
  26. /**
  27. * APNS Push
  28. *
  29. * @category Zend
  30. * @package Zend_Mobile
  31. * @subpackage Zend_Mobile_Push
  32. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. * @version $Id$
  35. */
  36. class Zend_Mobile_Push_Apns extends Zend_Mobile_Push_Abstract
  37. {
  38. /**
  39. * @const int apple server uri constants
  40. */
  41. const SERVER_SANDBOX_URI = 0;
  42. const SERVER_PRODUCTION_URI = 1;
  43. const SERVER_FEEDBACK_SANDBOX_URI = 2;
  44. const SERVER_FEEDBACK_PRODUCTION_URI = 3;
  45. /**
  46. * Apple Server URI's
  47. *
  48. * @var array
  49. */
  50. protected $_serverUriList = array(
  51. 'ssl://gateway.sandbox.push.apple.com:2195',
  52. 'ssl://gateway.push.apple.com:2195',
  53. 'ssl://feedback.sandbox.push.apple.com:2196',
  54. 'ssl://feedback.push.apple.com:2196'
  55. );
  56. /**
  57. * Current Environment
  58. *
  59. * @var int
  60. */
  61. protected $_currentEnv;
  62. /**
  63. * Socket
  64. *
  65. * @var resource
  66. */
  67. protected $_socket;
  68. /**
  69. * Certificate
  70. *
  71. * @var string
  72. */
  73. protected $_certificate;
  74. /**
  75. * Certificate Passphrase
  76. *
  77. * @var string
  78. */
  79. protected $_certificatePassphrase;
  80. /**
  81. * Get Certficiate
  82. *
  83. * @return string
  84. */
  85. public function getCertificate()
  86. {
  87. return $this->_certificate;
  88. }
  89. /**
  90. * Set Certificate
  91. *
  92. * @param string $cert
  93. * @return Zend_Mobile_Push_Apns
  94. * @throws Zend_Mobile_Push_Exception
  95. */
  96. public function setCertificate($cert)
  97. {
  98. if (!is_string($cert)) {
  99. throw new Zend_Mobile_Push_Exception('$cert must be a string');
  100. }
  101. if (!file_exists($cert)) {
  102. throw new Zend_Mobile_Push_Exception('$cert must be a valid path to the certificate');
  103. }
  104. $this->_certificate = $cert;
  105. return $this;
  106. }
  107. /**
  108. * Get Certificate Passphrase
  109. *
  110. * @return string
  111. */
  112. public function getCertificatePassphrase()
  113. {
  114. return $this->_certificatePassphrase;
  115. }
  116. /**
  117. * Set Certificate Passphrase
  118. *
  119. * @param string $passphrase
  120. * @return Zend_Mobile_Push_Apns
  121. * @throws Zend_Mobile_Push_Exception
  122. */
  123. public function setCertificatePassphrase($passphrase)
  124. {
  125. if (!is_string($passphrase)) {
  126. throw new Zend_Mobile_Push_Exception('$passphrase must be a string');
  127. }
  128. $this->_certificatePassphrase = $passphrase;
  129. return $this;
  130. }
  131. /**
  132. * Connect to Socket
  133. *
  134. * @param string $uri
  135. * @return bool
  136. * @throws Zend_Mobile_Push_Exception_ServerUnavailable
  137. */
  138. protected function _connect($uri)
  139. {
  140. $ssl = array(
  141. 'local_cert' => $this->_certificate,
  142. );
  143. if ($this->_certificatePassphrase) {
  144. $ssl['passphrase'] = $this->_certificatePassphrase;
  145. }
  146. $this->_socket = stream_socket_client($uri,
  147. $errno,
  148. $errstr,
  149. ini_get('default_socket_timeout'),
  150. STREAM_CLIENT_CONNECT,
  151. stream_context_create(array(
  152. 'ssl' => $ssl,
  153. ))
  154. );
  155. if (!is_resource($this->_socket)) {
  156. #require_once 'Zend/Mobile/Push/Exception/ServerUnavailable.php';
  157. throw new Zend_Mobile_Push_Exception_ServerUnavailable(sprintf('Unable to connect: %s: %d (%s)',
  158. $uri,
  159. $errno,
  160. $errstr
  161. ));
  162. }
  163. stream_set_blocking($this->_socket, 0);
  164. stream_set_write_buffer($this->_socket, 0);
  165. return true;
  166. }
  167. /**
  168. * Read from the Socket Server
  169. *
  170. * @param int $length
  171. * @return string
  172. */
  173. protected function _read($length) {
  174. $data = false;
  175. if (!feof($this->_socket)) {
  176. $data = fread($this->_socket, $length);
  177. }
  178. return $data;
  179. }
  180. /**
  181. * Write to the Socket Server
  182. *
  183. * @param string $payload
  184. * @return int
  185. */
  186. protected function _write($payload) {
  187. return @fwrite($this->_socket, $payload);
  188. }
  189. /**
  190. * Connect to the Push Server
  191. *
  192. * @param string $env
  193. * @return Zend_Mobile_Push_Abstract
  194. * @throws Zend_Mobile_Push_Exception
  195. * @throws Zend_Mobile_Push_Exception_ServerUnavailable
  196. */
  197. public function connect($env = self::SERVER_PRODUCTION_URI)
  198. {
  199. if ($this->_isConnected) {
  200. if ($this->_currentEnv == self::SERVER_PRODUCTION_URI) {
  201. return $this;
  202. }
  203. $this->close();
  204. }
  205. if (!isset($this->_serverUriList[$env])) {
  206. throw new Zend_Mobile_Push_Exception('$env is not a valid environment');
  207. }
  208. if (!$this->_certificate) {
  209. throw new Zend_Mobile_Push_Exception('A certificate must be set prior to calling ::connect');
  210. }
  211. $this->_connect($this->_serverUriList[$env]);
  212. $this->_currentEnv = $env;
  213. $this->_isConnected = true;
  214. return $this;
  215. }
  216. /**
  217. * Feedback
  218. *
  219. * @return array array w/ key = token and value = time
  220. * @throws Zend_Mobile_Push_Exception
  221. * @throws Zend_Mobile_Push_Exception_ServerUnavailable
  222. */
  223. public function feedback()
  224. {
  225. if (!$this->_isConnected ||
  226. !in_array($this->_currentEnv,
  227. array(self::SERVER_FEEDBACK_SANDBOX_URI, self::SERVER_FEEDBACK_PRODUCTION_URI))) {
  228. $this->connect(self::SERVER_FEEDBACK_PRODUCTION_URI);
  229. }
  230. $tokens = array();
  231. while ($token = $this->_read(38)) {
  232. if (strlen($token) < 38) {
  233. continue;
  234. }
  235. $token = unpack('Ntime/ntokenLength/H*token', $token);
  236. if (!isset($tokens[$token['token']]) || $tokens[$token['token']] < $token['time']) {
  237. $tokens[$token['token']] = $token['time'];
  238. }
  239. }
  240. return $tokens;
  241. }
  242. /**
  243. * Send Message
  244. *
  245. * @param Zend_Mobile_Push_Message_Apns $message
  246. * @return boolean
  247. * @throws Zend_Mobile_Push_Exception
  248. * @throws Zend_Mobile_Push_Exception_ServerUnavailable
  249. * @throws Zend_Mobile_Push_Exception_InvalidToken
  250. * @throws Zend_Mobile_Push_Exception_InvalidTopic
  251. * @throws Zend_Mobile_Push_Exception_InvalidPayload
  252. */
  253. public function send(Zend_Mobile_Push_Message_Abstract $message)
  254. {
  255. if (!$message->validate()) {
  256. throw new Zend_Mobile_Push_Exception('The message is not valid.');
  257. }
  258. if (!$this->_isConnected || !in_array($this->_currentEnv, array(
  259. self::SERVER_SANDBOX_URI,
  260. self::SERVER_PRODUCTION_URI))) {
  261. $this->connect(self::SERVER_PRODUCTION_URI);
  262. }
  263. $payload = array('aps' => array());
  264. $alert = $message->getAlert();
  265. foreach ($alert as $k => $v) {
  266. if ($v == null) {
  267. unset($alert[$k]);
  268. }
  269. }
  270. if (!empty($alert)) {
  271. $payload['aps']['alert'] = $alert;
  272. }
  273. if (!is_null($message->getBadge())) {
  274. $payload['aps']['badge'] = $message->getBadge();
  275. }
  276. $payload['aps']['sound'] = $message->getSound();
  277. foreach($message->getCustomData() as $k => $v) {
  278. $payload[$k] = $v;
  279. }
  280. $payload = json_encode($payload);
  281. $expire = $message->getExpire();
  282. if ($expire > 0) {
  283. $expire += time();
  284. }
  285. $id = $message->getId();
  286. if (empty($id)) {
  287. $id = time();
  288. }
  289. $payload = pack('CNNnH*', 1, $id, $expire, 32, $message->getToken())
  290. . pack('n', strlen($payload))
  291. . $payload;
  292. $ret = $this->_write($payload);
  293. if ($ret === false) {
  294. #require_once 'Zend/Mobile/Push/Exception/ServerUnavailable.php';
  295. throw new Zend_Mobile_Push_Exception_ServerUnavailable('Unable to send message');
  296. }
  297. // check for errors from apple
  298. $err = $this->_read(1024);
  299. if (strlen($err) > 0) {
  300. $err = unpack('Ccmd/Cerrno/Nid', $err);
  301. switch ($err['errno']) {
  302. case 0:
  303. return true;
  304. break;
  305. case 1:
  306. throw new Zend_Mobile_Push_Exception('A processing error has occurred on the apple push notification server.');
  307. break;
  308. case 2:
  309. #require_once 'Zend/Mobile/Push/Exception/InvalidToken.php';
  310. throw new Zend_Mobile_Push_Exception_InvalidToken('Missing token; you must set a token for the message.');
  311. break;
  312. case 3:
  313. #require_once 'Zend/Mobile/Push/Exception/InvalidTopic.php';
  314. throw new Zend_Mobile_Push_Exception_InvalidTopic('Missing id; you must set an id for the message.');
  315. break;
  316. case 4:
  317. #require_once 'Zend/Mobile/Push/Exception/InvalidPayload.php';
  318. throw new Zend_Mobile_Push_Exception_InvalidPayload('Missing message; the message must always have some content.');
  319. break;
  320. case 5:
  321. #require_once 'Zend/Mobile/Push/Exception/InvalidToken.php';
  322. throw new Zend_Mobile_Push_Exception_InvalidToken('Bad token. This token is too big and is not a regular apns token.');
  323. break;
  324. case 6:
  325. #require_once 'Zend/Mobile/Push/Exception/InvalidTopic.php';
  326. throw new Zend_Mobile_Push_Exception_InvalidTopic('The message id is too big; reduce the size of the id.');
  327. break;
  328. case 7:
  329. #require_once 'Zend/Mobile/Push/Exception/InvalidPayload.php';
  330. throw new Zend_Mobile_Push_Exception_InvalidPayload('The message is too big; reduce the size of the message.');
  331. break;
  332. case 8:
  333. #require_once 'Zend/Mobile/Push/Exception/InvalidToken.php';
  334. throw new Zend_Mobile_Push_Exception_InvalidToken('Bad token. Remove this token from being sent to again.');
  335. break;
  336. default:
  337. throw new Zend_Mobile_Push_Exception(sprintf('An unknown error occurred: %d', $err['errno']));
  338. break;
  339. }
  340. }
  341. return true;
  342. }
  343. /**
  344. * Close Connection
  345. *
  346. * @return void
  347. */
  348. public function close()
  349. {
  350. if ($this->_isConnected && is_resource($this->_socket)) {
  351. fclose($this->_socket);
  352. }
  353. $this->_isConnected = false;
  354. }
  355. }