I am very excited about this library. Thank you so much for all the
work you put into this!
At first it seemed very capable of handling multiple notifications as
it can handle many applications. However, on further inspection I
found that it does not batch notifications as Apple encourages you to
do on their apns guide (
https://developer.apple.com/library/mac/
#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/
CommunicatingWIthAPS/CommunicatingWIthAPS.html). For each message it
opens a stream, sends a notification and closes the stream, which can
be optimised. Here are the code that opens a stream, sends all the
queued messages (in a batch) and closes the stream:
////////////// BEGIN NEW ADDITION ////////////////
/**
* True if running in sandbox
*
* @var bool
* @access private
*/
private $isSandbox = true;
/**
* The limit of how many messages to send
* @var int
* @access private
*/
private $limit = 100;
private function _checkMessage($pid, $message, $token, $development) {
return strlen($pid)!=0 && strlen($message)!=0 && strlen($token)!=0 &&
strlen($development)!=0;
}
////////////// END NEW ADDITION ////////////////
////////////// BEGIN REPLACE EXISTING ////////////////
private function _fetchMessages(){
// only send one message per user... oldest message first
$sql = "SELECT
`apns_messages`.`pid`,
`apns_messages`.`message`,
`apns_devices`.`devicetoken`
FROM `apns_messages`
LEFT JOIN `apns_devices` ON (`apns_devices`.`pid` =
`apns_messages`.`fk_device` AND `apns_devices`.`clientid` =
`apns_messages`.`clientid`)
WHERE `apns_messages`.`status`='queued'
AND `apns_messages`.`delivery` <= NOW()
AND `apns_devices`.`status`='active'
AND `apns_devices`.`development`=".($this->isSandbox ?
"'sandbox'":"'production'").
" GROUP BY `apns_messages`.`fk_device`
ORDER BY `apns_messages`.`created` ASC
LIMIT ".$this->limit.";";
$development = $this->isSandbox ? 'sandbox': 'production';
if($result = $this->db->query($sql)){
if($result->num_rows){
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', $this-
>apnsData[$development]['certificate']);
$fp = stream_socket_client($this->apnsData[$development]['ssl'],
$error, $errorString, 100, (STREAM_CLIENT_CONNECT|
STREAM_CLIENT_PERSISTENT), $ctx);
while($row = $result->fetch_array(MYSQLI_ASSOC)){
$pid = $this->db->prepare($row['pid']);
$message = stripslashes($this->db->prepare($row['message']));
$token = $this->db->prepare($row['devicetoken']);
if(!$fp){
$this->_pushFailed($pid);
$this->_triggerError("Failed to connect to APNS: {$error}
{$errorString}.");
}
else if(!$this->_checkMessage($pid, $message, $token,
$development)) {
$this->_pushFailed($pid);
$this->_triggerError("Invalid message for device pid: ".
$pid.".");
}
else {
$this->_pushMessage($fp, $pid, $message, $token, $development);
}
}
fclose($fp);
$this->_checkFeedback($development);
}
}
}
private function _flushMessages(){
// send all the messages for each device
$sql = "SELECT
`apns_messages`.`pid`,
`apns_messages`.`message`,
`apns_devices`.`devicetoken`
FROM `apns_messages`
LEFT JOIN `apns_devices` ON (`apns_devices`.`pid` =
`apns_messages`.`fk_device` AND `apns_devices`.`clientid` =
`apns_messages`.`clientid`)
WHERE `apns_messages`.`status`='queued'
AND `apns_messages`.`delivery` <= NOW()
AND `apns_devices`.`status`='active'
AND `apns_devices`.`development`=".($this->isSandbox ?
"'sandbox'":"'production'").
" ORDER BY `apns_messages`.`created` ASC
LIMIT ".$this->limit.";";
$development = $this->isSandbox ? 'sandbox': 'production';
if($result = $this->db->query($sql)){
//var_dump ($result);
if($result->num_rows){
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', $this-
>apnsData[$development]['certificate']);
$fp = stream_socket_client($this->apnsData[$development]['ssl'],
$error, $errorString, 100, (STREAM_CLIENT_CONNECT|
STREAM_CLIENT_PERSISTENT), $ctx);
while($row = $result->fetch_array(MYSQLI_ASSOC)){
$pid = $this->db->prepare($row['pid']);
$message = stripslashes($this->db->prepare($row['message']));
$token = $this->db->prepare($row['devicetoken']);
if(!$fp){
$this->_pushFailed($pid);
$this->_triggerError("Failed to connect to APNS: {$error}
{$errorString}.");
}
else if(!$this->_checkMessage($pid, $message, $token,
$development)) {
$this->_pushFailed($pid);
$this->_triggerError("Invalid message for device pid: ".
$pid.".");
}
else {
$this->_pushMessage($fp, $pid, $message, $token, $development);
}
}
fclose($fp);
$this->_checkFeedback($development);
}
}
}
private function _pushMessage($fp, $pid, $message, $token,
$development){
$msg = chr(0).pack("n",32).pack('H*',
$token).pack("n",strlen($message)).$message;
$fwrite = fwrite($fp, $msg);
if(!$fwrite) {
$this->_pushFailed($pid);
$this->_triggerError("Failed writing to stream.", E_USER_ERROR);
}
else {
$this->_pushSuccess($pid);
}
}
////////////// END REPLACE EXISTING ////////////////
Hope you can use this for your own projects!
Regards Michael