apns-php
 All Data Structures Files Functions Variables Groups Pages
Abstract.php
Go to the documentation of this file.
1 <?php
2 /**
3  * @file
4  * ApnsPHP_Abstract class definition.
5  *
6  * LICENSE
7  *
8  * This source file is subject to the new BSD license that is bundled
9  * with this package in the file LICENSE.txt.
10  * It is also available through the world-wide-web at this URL:
11  * http://code.google.com/p/apns-php/wiki/License
12  * If you did not receive a copy of the license and are unable to
13  * obtain it through the world-wide-web, please send an email
14  * to aldo.armiento@gmail.com so we can send you a copy immediately.
15  *
16  * @author (C) 2010 Aldo Armiento (aldo.armiento@gmail.com)
17  * @version $Id$
18  */
19 
20 /**
21  * @mainpage
22  *
23  * @li ApnsPHP on GitHub: https://github.com/immobiliare/ApnsPHP
24  */
25 
26 /**
27  * @defgroup ApplePushNotificationService ApnsPHP
28  */
29 
30 /**
31  * Abstract class: this is the superclass for all Apple Push Notification Service
32  * classes.
33  *
34  * This class is responsible for the connection to the Apple Push Notification Service
35  * and Feedback.
36  *
37  * @ingroup ApplePushNotificationService
38  * @see http://tinyurl.com/ApplePushNotificationService
39  */
40 abstract class ApnsPHP_Abstract
41 {
42  const ENVIRONMENT_PRODUCTION = 0; /**< @type integer Production environment. */
43  const ENVIRONMENT_SANDBOX = 1; /**< @type integer Sandbox environment. */
44 
45  const DEVICE_BINARY_SIZE = 32; /**< @type integer Device token length. */
46 
47  const WRITE_INTERVAL = 10000; /**< @type integer Default write interval in micro seconds. */
48  const CONNECT_RETRY_INTERVAL = 1000000; /**< @type integer Default connect retry interval in micro seconds. */
49  const SOCKET_SELECT_TIMEOUT = 1000000; /**< @type integer Default socket select timeout in micro seconds. */
50 
51  protected $_aServiceURLs = array(); /**< @type array Container for service URLs environments. */
52 
53  protected $_nEnvironment; /**< @type integer Active environment. */
54 
55  protected $_nConnectTimeout; /**< @type integer Connect timeout in seconds. */
56  protected $_nConnectRetryTimes = 3; /**< @type integer Connect retry times. */
57 
58  protected $_sProviderCertificateFile; /**< @type string Provider certificate file with key (Bundled PEM). */
59  protected $_sProviderCertificatePassphrase; /**< @type string Provider certificate passphrase. */
60  protected $_sRootCertificationAuthorityFile; /**< @type string Root certification authority file. */
61 
62  protected $_nWriteInterval; /**< @type integer Write interval in micro seconds. */
63  protected $_nConnectRetryInterval; /**< @type integer Connect retry interval in micro seconds. */
64  protected $_nSocketSelectTimeout; /**< @type integer Socket select timeout in micro seconds. */
65 
66  protected $_logger; /**< @type ApnsPHP_Log_Interface Logger. */
67 
68  protected $_hSocket; /**< @type resource SSL Socket. */
69 
70  /**
71  * Constructor.
72  *
73  * @param $nEnvironment @type integer Environment.
74  * @param $sProviderCertificateFile @type string Provider certificate file
75  * with key (Bundled PEM).
76  * @throws ApnsPHP_Exception if the environment is not
77  * sandbox or production or the provider certificate file is not readable.
78  */
79  public function __construct($nEnvironment, $sProviderCertificateFile)
80  {
81  if ($nEnvironment != self::ENVIRONMENT_PRODUCTION && $nEnvironment != self::ENVIRONMENT_SANDBOX) {
82  throw new ApnsPHP_Exception(
83  "Invalid environment '{$nEnvironment}'"
84  );
85  }
86  $this->_nEnvironment = $nEnvironment;
87 
88  if (!is_readable($sProviderCertificateFile)) {
89  throw new ApnsPHP_Exception(
90  "Unable to read certificate file '{$sProviderCertificateFile}'"
91  );
92  }
93  $this->_sProviderCertificateFile = $sProviderCertificateFile;
94 
95  $this->_nConnectTimeout = ini_get("default_socket_timeout");
96  $this->_nWriteInterval = self::WRITE_INTERVAL;
97  $this->_nConnectRetryInterval = self::CONNECT_RETRY_INTERVAL;
98  $this->_nSocketSelectTimeout = self::SOCKET_SELECT_TIMEOUT;
99  }
100 
101  /**
102  * Set the Logger instance to use for logging purpose.
103  *
104  * The default logger is ApnsPHP_Log_Embedded, an instance
105  * of ApnsPHP_Log_Interface that simply print to standard
106  * output log messages.
107  *
108  * To set a custom logger you have to implement ApnsPHP_Log_Interface
109  * and use setLogger, otherwise standard logger will be used.
110  *
111  * @see ApnsPHP_Log_Interface
112  * @see ApnsPHP_Log_Embedded
113  *
114  * @param $logger @type ApnsPHP_Log_Interface Logger instance.
115  * @throws ApnsPHP_Exception if Logger is not an instance
116  * of ApnsPHP_Log_Interface.
117  */
118  public function setLogger(ApnsPHP_Log_Interface $logger)
119  {
120  if (!is_object($logger)) {
121  throw new ApnsPHP_Exception(
122  "The logger should be an instance of 'ApnsPHP_Log_Interface'"
123  );
124  }
125  if (!($logger instanceof ApnsPHP_Log_Interface)) {
126  throw new ApnsPHP_Exception(
127  "Unable to use an instance of '" . get_class($logger) . "' as logger: " .
128  "a logger must implements ApnsPHP_Log_Interface."
129  );
130  }
131  $this->_logger = $logger;
132  }
133 
134  /**
135  * Get the Logger instance.
136  *
137  * @return @type ApnsPHP_Log_Interface Current Logger instance.
138  */
139  public function getLogger()
140  {
141  return $this->_logger;
142  }
143 
144  /**
145  * Set the Provider Certificate passphrase.
146  *
147  * @param $sProviderCertificatePassphrase @type string Provider Certificate
148  * passphrase.
149  */
150  public function setProviderCertificatePassphrase($sProviderCertificatePassphrase)
151  {
152  $this->_sProviderCertificatePassphrase = $sProviderCertificatePassphrase;
153  }
154 
155  /**
156  * Set the Root Certification Authority file.
157  *
158  * Setting the Root Certification Authority file automatically set peer verification
159  * on connect.
160  *
161  * @see http://tinyurl.com/GeneralProviderRequirements
162  * @see http://www.entrust.net/
163  * @see https://www.entrust.net/downloads/root_index.cfm
164  *
165  * @param $sRootCertificationAuthorityFile @type string Root Certification
166  * Authority file.
167  * @throws ApnsPHP_Exception if Root Certification Authority
168  * file is not readable.
169  */
170  public function setRootCertificationAuthority($sRootCertificationAuthorityFile)
171  {
172  if (!is_readable($sRootCertificationAuthorityFile)) {
173  throw new ApnsPHP_Exception(
174  "Unable to read Certificate Authority file '{$sRootCertificationAuthorityFile}'"
175  );
176  }
177  $this->_sRootCertificationAuthorityFile = $sRootCertificationAuthorityFile;
178  }
179 
180  /**
181  * Get the Root Certification Authority file path.
182  *
183  * @return @type string Current Root Certification Authority file path.
184  */
185  public function getCertificateAuthority()
186  {
188  }
189 
190  /**
191  * Set the write interval.
192  *
193  * After each socket write operation we are sleeping for this
194  * time interval. To speed up the sending operations, use Zero
195  * as parameter but some messages may be lost.
196  *
197  * @param $nWriteInterval @type integer Write interval in micro seconds.
198  */
199  public function setWriteInterval($nWriteInterval)
200  {
201  $this->_nWriteInterval = (int)$nWriteInterval;
202  }
203 
204  /**
205  * Get the write interval.
206  *
207  * @return @type integer Write interval in micro seconds.
208  */
209  public function getWriteInterval()
210  {
211  return $this->_nWriteInterval;
212  }
213 
214  /**
215  * Set the connection timeout.
216  *
217  * The default connection timeout is the PHP internal value "default_socket_timeout".
218  * @see http://php.net/manual/en/filesystem.configuration.php
219  *
220  * @param $nTimeout @type integer Connection timeout in seconds.
221  */
222  public function setConnectTimeout($nTimeout)
223  {
224  $this->_nConnectTimeout = (int)$nTimeout;
225  }
226 
227  /**
228  * Get the connection timeout.
229  *
230  * @return @type integer Connection timeout in seconds.
231  */
232  public function getConnectTimeout()
233  {
235  }
236 
237  /**
238  * Set the connect retry times value.
239  *
240  * If the client is unable to connect to the server retries at least for this
241  * value. The default connect retry times is 3.
242  *
243  * @param $nRetryTimes @type integer Connect retry times.
244  */
245  public function setConnectRetryTimes($nRetryTimes)
246  {
247  $this->_nConnectRetryTimes = (int)$nRetryTimes;
248  }
249 
250  /**
251  * Get the connect retry time value.
252  *
253  * @return @type integer Connect retry times.
254  */
255  public function getConnectRetryTimes()
256  {
258  }
259 
260  /**
261  * Set the connect retry interval.
262  *
263  * If the client is unable to connect to the server retries at least for ConnectRetryTimes
264  * and waits for this value between each attempts.
265  *
266  * @see setConnectRetryTimes
267  *
268  * @param $nRetryInterval @type integer Connect retry interval in micro seconds.
269  */
270  public function setConnectRetryInterval($nRetryInterval)
271  {
272  $this->_nConnectRetryInterval = (int)$nRetryInterval;
273  }
274 
275  /**
276  * Get the connect retry interval.
277  *
278  * @return @type integer Connect retry interval in micro seconds.
279  */
280  public function getConnectRetryInterval()
281  {
283  }
284 
285  /**
286  * Set the TCP socket select timeout.
287  *
288  * After writing to socket waits for at least this value for read stream to
289  * change status.
290  *
291  * In Apple Push Notification protocol there isn't a real-time
292  * feedback about the correctness of notifications pushed to the server; so after
293  * each write to server waits at least SocketSelectTimeout. If, during this
294  * time, the read stream change its status and socket received an end-of-file
295  * from the server the notification pushed to server was broken, the server
296  * has closed the connection and the client needs to reconnect.
297  *
298  * @see http://php.net/stream_select
299  *
300  * @param $nSelectTimeout @type integer Socket select timeout in micro seconds.
301  */
302  public function setSocketSelectTimeout($nSelectTimeout)
303  {
304  $this->_nSocketSelectTimeout = (int)$nSelectTimeout;
305  }
306 
307  /**
308  * Get the TCP socket select timeout.
309  *
310  * @return @type integer Socket select timeout in micro seconds.
311  */
312  public function getSocketSelectTimeout()
313  {
315  }
316 
317  /**
318  * Connects to Apple Push Notification service server.
319  *
320  * Retries ConnectRetryTimes if unable to connect and waits setConnectRetryInterval
321  * between each attempts.
322  *
323  * @see setConnectRetryTimes
324  * @see setConnectRetryInterval
325  * @throws ApnsPHP_Exception if is unable to connect after
326  * ConnectRetryTimes.
327  */
328  public function connect()
329  {
330  $bConnected = false;
331  $nRetry = 0;
332  while (!$bConnected) {
333  try {
334  $bConnected = $this->_connect();
335  } catch (ApnsPHP_Exception $e) {
336  $this->_log('ERROR: ' . $e->getMessage());
337  if ($nRetry >= $this->_nConnectRetryTimes) {
338  throw $e;
339  } else {
340  $this->_log(
341  "INFO: Retry to connect (" . ($nRetry+1) .
342  "/{$this->_nConnectRetryTimes})..."
343  );
344  usleep($this->_nConnectRetryInterval);
345  }
346  }
347  $nRetry++;
348  }
349  }
350 
351  /**
352  * Disconnects from Apple Push Notifications service server.
353  *
354  * @return @type boolean True if successful disconnected.
355  */
356  public function disconnect()
357  {
358  if (is_resource($this->_hSocket)) {
359  $this->_log('INFO: Disconnected.');
360  return fclose($this->_hSocket);
361  }
362  return false;
363  }
364 
365  /**
366  * Connects to Apple Push Notification service server.
367  *
368  * @throws ApnsPHP_Exception if is unable to connect.
369  * @return @type boolean True if successful connected.
370  */
371  protected function _connect()
372  {
373  $sURL = $this->_aServiceURLs[$this->_nEnvironment];
374  unset($aURLs);
375 
376  $this->_log("INFO: Trying {$sURL}...");
377 
378  /**
379  * @see http://php.net/manual/en/context.ssl.php
380  */
381  $streamContext = stream_context_create(array('ssl' => array(
382  'verify_peer' => isset($this->_sRootCertificationAuthorityFile),
383  'cafile' => $this->_sRootCertificationAuthorityFile,
384  'local_cert' => $this->_sProviderCertificateFile
385  )));
386 
387  if (!empty($this->_sProviderCertificatePassphrase)) {
388  stream_context_set_option($streamContext, 'ssl',
389  'passphrase', $this->_sProviderCertificatePassphrase);
390  }
391 
392  $this->_hSocket = @stream_socket_client($sURL, $nError, $sError,
393  $this->_nConnectTimeout, STREAM_CLIENT_CONNECT, $streamContext);
394 
395  if (!$this->_hSocket) {
396  throw new ApnsPHP_Exception(
397  "Unable to connect to '{$sURL}': {$sError} ({$nError})"
398  );
399  }
400 
401  stream_set_blocking($this->_hSocket, 0);
402  stream_set_write_buffer($this->_hSocket, 0);
403 
404  $this->_log("INFO: Connected to {$sURL}.");
405 
406  return true;
407  }
408 
409  /**
410  * Logs a message through the Logger.
411  *
412  * @param $sMessage @type string The message.
413  */
414  protected function _log($sMessage)
415  {
416  if (!isset($this->_logger)) {
417  $this->_logger = new ApnsPHP_Log_Embedded();
418  }
419  $this->_logger->log($sMessage);
420  }
421 }
integer $_nConnectRetryTimes
Connect retry times.
Definition: Abstract.php:56
void setLogger(ApnsPHP_Log_Interface $logger)
Set the Logger instance to use for logging purpose.
Definition: Abstract.php:118
void setSocketSelectTimeout(integer $nSelectTimeout)
Set the TCP socket select timeout.
Definition: Abstract.php:302
string $_sProviderCertificateFile
Provider certificate file with key (Bundled PEM).
Definition: Abstract.php:58
void setWriteInterval(integer $nWriteInterval)
Set the write interval.
Definition: Abstract.php:199
boolean _connect()
Connects to Apple Push Notification service server.
Definition: Abstract.php:371
void setRootCertificationAuthority(string $sRootCertificationAuthorityFile)
Set the Root Certification Authority file.
Definition: Abstract.php:170
integer $_nConnectRetryInterval
Connect retry interval in micro seconds.
Definition: Abstract.php:63
Exception class.
Definition: Exception.php:25
void setProviderCertificatePassphrase(string $sProviderCertificatePassphrase)
Set the Provider Certificate passphrase.
Definition: Abstract.php:150
const ENVIRONMENT_SANDBOX
integer Sandbox environment.
Definition: Abstract.php:43
void setConnectRetryInterval(integer $nRetryInterval)
Set the connect retry interval.
Definition: Abstract.php:270
void connect()
Connects to Apple Push Notification service server.
Definition: Abstract.php:328
ApnsPHP_Log_Interface getLogger()
Get the Logger instance.
Definition: Abstract.php:139
const WRITE_INTERVAL
integer Default write interval in micro seconds.
Definition: Abstract.php:47
resource $_hSocket
SSL Socket.
Definition: Abstract.php:68
Abstract class: this is the superclass for all Apple Push Notification Service classes.
Definition: Abstract.php:40
integer $_nSocketSelectTimeout
Socket select timeout in micro seconds.
Definition: Abstract.php:64
array $_aServiceURLs
Container for service URLs environments.
Definition: Abstract.php:51
string $_sRootCertificationAuthorityFile
Root certification authority file.
Definition: Abstract.php:60
integer getConnectTimeout()
Get the connection timeout.
Definition: Abstract.php:232
A simple logger.
Definition: Embedded.php:31
boolean disconnect()
Disconnects from Apple Push Notifications service server.
Definition: Abstract.php:356
string $_sProviderCertificatePassphrase
Provider certificate passphrase.
Definition: Abstract.php:59
integer $_nWriteInterval
Write interval in micro seconds.
Definition: Abstract.php:62
void _log(string $sMessage)
Logs a message through the Logger.
Definition: Abstract.php:414
integer getWriteInterval()
Get the write interval.
Definition: Abstract.php:209
The Log Interface.
Definition: Interface.php:33
ApnsPHP_Log_Interface $_logger
Logger.
Definition: Abstract.php:66
void __construct(integer $nEnvironment, string $sProviderCertificateFile)
Constructor.
Definition: Abstract.php:79
integer getConnectRetryTimes()
Get the connect retry time value.
Definition: Abstract.php:255
const SOCKET_SELECT_TIMEOUT
integer Default socket select timeout in micro seconds.
Definition: Abstract.php:49
void setConnectRetryTimes(integer $nRetryTimes)
Set the connect retry times value.
Definition: Abstract.php:245
string getCertificateAuthority()
Get the Root Certification Authority file path.
Definition: Abstract.php:185
const DEVICE_BINARY_SIZE
integer Device token length.
Definition: Abstract.php:45
const CONNECT_RETRY_INTERVAL
integer Default connect retry interval in micro seconds.
Definition: Abstract.php:48
const ENVIRONMENT_PRODUCTION
integer Production environment.
Definition: Abstract.php:42
integer getConnectRetryInterval()
Get the connect retry interval.
Definition: Abstract.php:280
integer $_nEnvironment
Active environment.
Definition: Abstract.php:53
void setConnectTimeout(integer $nTimeout)
Set the connection timeout.
Definition: Abstract.php:222
integer getSocketSelectTimeout()
Get the TCP socket select timeout.
Definition: Abstract.php:312
integer $_nConnectTimeout
Connect timeout in seconds.
Definition: Abstract.php:55