Am trying to send Apple Push Notifications to my app. Am following this tutorial for the APNS process. URL: http://www.raywenderlich.com/3525/apple-push-notification-services-tutorial-part-2.
I have done almost work in MAMP, PHP and i have mentioned my .pem file in pus_config.php file for APNS connection. I have tested my .pem file with simplepush.php file and i sent notifications to my device. Now am trying with push.php file which was taken from the above tutorial.
This is my push_config.php file,
<?php
// Configuration file for push.php
$config = array(
// These are the settings for development mode
'development' => array(
// The APNS server that we will use
'server' => 'gateway.sandbox.push.apple.com:2195',
// The SSL certificate that allows us to connect to the APNS servers
'certificate' => 'GopiAPNSCert.pem',
'passphrase' => 'gopi',
// Configuration of the MySQL database
'db' => array(
'host' => 'localhost',
'dbname' => 'gopipush',
'username' => 'gopipush',
'password' => 'uH4q9xQGNAuFW',
),
// Name and path of our log file
'logfile' => '/Users/gopi/Desktop/PushChatServer/log/push_development.log',
),
// These are the settings for production mode
'production' => array(
// The APNS server that we will use
'server' => 'gateway.push.apple.com:2195',
// The SSL certificate that allows us to connect to the APNS servers
'certificate' => 'ck.pem',
'passphrase' => 'secret',
// Configuration of the MySQL database
'db' => array(
'host' => 'localhost',
'dbname' => 'pushchat',
'username' => 'pushchat',
'password' => '1233}jfdoie',
),
// Name and path of our log file
'logfile' => '/Users/gopi/Desktop/PushChatServer/log/push_development.log',
),
);
The above certificate name and passphrase are verified and correct tested with simplepush.php file.
Here is my push.php file,
<?php
try
{
require_once('push_config.php');
ini_set('display_errors', 'off');
if ($argc != 2 || ($argv[1] != 'development' && $argv[1] != 'production'))
exit("Usage: php push.php development|production". PHP_EOL);
$mode = $argv[1];
$config = $config[$mode];
writeToLog("Push script started ($mode mode)");
$obj = new APNS_Push($config);
$obj->start();
}
catch (Exception $e)
{
fatalError($e);
}
////////////////////////////////////////////////////////////////////////////////
function writeToLog($message)
{
global $config;
if ($fp = fopen($config['logfile'], 'at'))
{
fwrite($fp, date('c') . ' ' . $message . PHP_EOL);
fclose($fp);
}
}
function fatalError($message)
{
writeToLog('Exiting with fatal error: ' . $message);
exit;
}
////////////////////////////////////////////////////////////////////////////////
class APNS_Push
{
private $fp = NULL;
private $server;
private $certificate;
private $passphrase;
function __construct($config)
{
$this->server = $config['server'];
$this->certificate = $config['certificate'];
$this->passphrase = $config['passphrase'];
// Create a connection to the database.
$this->pdo = new PDO(
'mysql:host=' . $config['db']['host'] . ';dbname=' . $config['db']['dbname'],
$config['db']['username'],
$config['db']['password'],
array());
// If there is an error executing database queries, we want PDO to
// throw an exception.
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// We want the database to handle all strings as UTF-8.
$this->pdo->query('SET NAMES utf8');
}
// This is the main loop for this script. It polls the database for new
// messages, sends them to APNS, sleeps for a few seconds, and repeats this
// forever (or until a fatal error occurs and the script exits).
function start()
{
writeToLog('Connecting to ' . $this->server);
if (!$this->connectToAPNS())
{
exit;
}
while (true)
{
writeToLog('Getting PushQueue');
$stmt = $this->pdo->prepare('SELECT * FROM push_queue WHERE time_sent IS NULL LIMIT 20');
$stmt->execute();
$messages = $stmt->fetchAll(PDO::FETCH_OBJ);
foreach ($messages as $message)
{
if ($this->sendNotification($message->message_id, $message->device_token, $message->payload))
{
$stmt = $this->pdo->prepare('UPDATE push_queue SET time_sent = NOW() WHERE message_id = ?');
$stmt->execute(array($message->message_id));
}
else // failed to deliver
{
$this->reconnectToAPNS();
}
}
unset($messages);
sleep(5);
}
}
// Opens an SSL/TLS connection to Apple's Push Notification Service (APNS).
// Returns TRUE on success, FALSE on failure.
function connectToAPNS()
{
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', $this->certificate);
stream_context_set_option($ctx, 'ssl', 'passphrase', $this->passphrase);
$this->fp = stream_socket_client(
'ssl://' . $this->server, $err, $errstr, 60,
STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$this->fp)
{
writeToLog('Failed APNS Connection');
writeToLog("Failed to connect: $err $errstr");
return FALSE;
}
writeToLog('Connection OK');
return TRUE;
}
// Drops the connection to the APNS server.
function disconnectFromAPNS()
{
fclose($this->fp);
$this->fp = NULL;
}
// Attempts to reconnect to Apple's Push Notification Service. Exits with
// an error if the connection cannot be re-established after 3 attempts.
function reconnectToAPNS()
{
writeToLog('ReconnectToAPNS');
$this->disconnectFromAPNS();
$attempt = 1;
while (true)
{
writeToLog('Reconnecting to ' . $this->server . ", attempt $attempt");
if ($this->connectToAPNS())
return;
if ($attempt++ > 3)
fatalError('Could not reconnect after 3 attempts');
sleep(60);
}
}
// Sends a notification to the APNS server. Returns FALSE if the connection
// appears to be broken, TRUE otherwise.
function sendNotification($messageId, $deviceToken, $payload)
{
if (strlen($deviceToken) != 64)
{
writeToLog("Message $messageId has invalid device token");
return TRUE;
}
if (strlen($payload) < 10)
{
writeToLog("Message $messageId has invalid payload");
return TRUE;
}
writeToLog("Sending message $messageId to '$deviceToken', payload: '$payload'");
if (!$this->fp)
{
writeToLog('No connection to APNS');
return FALSE;
}
// The simple format
$msg = chr(0) // command (1 byte)
. pack('n', 32) // token length (2 bytes)
. pack('H*', $deviceToken) // device token (32 bytes)
. pack('n', strlen($payload)) // payload length (2 bytes)
. $payload; // the JSON payload
/*
// The enhanced notification format
$msg = chr(1) // command (1 byte)
. pack('N', $messageId) // identifier (4 bytes)
. pack('N', time() + 86400) // expire after 1 day (4 bytes)
. pack('n', 32) // token length (2 bytes)
. pack('H*', $deviceToken) // device token (32 bytes)
. pack('n', strlen($payload)) // payload length (2 bytes)
. $payload; // the JSON payload
*/
$result = @fwrite($this->fp, $msg, strlen($msg));
if (!$result)
{
writeToLog('Message not delivered');
return FALSE;
}
writeToLog('Message successfully delivered');
return TRUE;
}
}
Am getting this error in my push_development.log file.
2012-05-14T18:04:28+05:30 Push script started (development mode)
2012-05-14T18:04:28+05:30 Connecting to gateway.sandbox.push.apple.com:2195
2012-05-14T18:04:29+05:30 Failed to connect: 0
I can't find what i did wrong? And what i should change in my push.php file. I have tested my network connection and .pem files. Can you please help me to solve this error and get notifications in my device? Thanks in advance.
EDIT
unknownc42c032e8297:~ name$ cd /Users/name/Desktop/PushChatServer
unknownc42c032e8297: PushChatServer name$ telnet gateway.sandbox.push.apple.com 2195
Trying 17.149.34.66...
Connected to gateway.sandbox.push-apple.com.akadns.net.
Escape character is '^]'.
^C
Connection closed by foreign host.
unknownc42c032e8297: PushChatServer name$ openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert NameAPNCert.pem -key GopiAPNSCert
.pem
Enter pass phrase for NameAPNKey.pem:
CONNECTED(00000003)
depth=1 /C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
0 s:/C=US/ST=California/L=Cupertino/O=Apple Inc/OU=Internet Services/CN=gateway.sandbox.push.apple.com
i:/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
1 s:/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
i:/O=Entrust.net/OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Certification Authority (2048)
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIEZTCCA02gAwIBAgIESyDhfjANBgkqhkiG9w0BAQUFADCBsTELMAkGA1UEBhMC
VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
Lm5ldC9ycGEgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
KGMpIDIwMDkgRW50cnVzdCwgSW5jLjEuMCwGA1UEAxMlRW50cnVzdCBDZXJ0aWZp
Y2F0aW9uIEF1dGhvcml0eSAtIEwxQzAeFw0xMDA0MTMyMzM0MzNaFw0xMjA1MzEw
MDA0MjdaMIGPMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTESMBAG
A1UEBxMJQ3VwZXJ0aW5vMRIwEAYDVQQKEwlBcHBsZSBJbmMxGjAYBgNVBAsTEUlu
dGVybmV0IFNlcnZpY2VzMScwJQYDVQQDEx5nYXRld2F5LnNhbmRib3gucHVzaC5h
cHBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM5NngiDMFpGBMmb
8tG2MRhLEdsx553Xjq+5C/c0mtildwhnC1X0LWKUexWdQsMchniac+WnHFSs3YMJ
JJ55kQSB6wqK/WNcxsUn8pMkMsvk3YZFM7TsaKQvFOeieiXCSJVlR3grm3+dilv1
Br+SUqv8JrgU3ijmoQO63vkb8B/hAgMBAAGjggEnMIIBIzALBgNVHQ8EBAMCBaAw
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDMGA1UdHwQsMCowKKAmoCSG
Imh0dHA6Ly9jcmwuZW50cnVzdC5uZXQvbGV2ZWwxYy5jcmwwMwYIKwYBBQUHAQEE
JzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDBABgNVHSAE
OTA3MDUGCSqGSIb2fQdLAjAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LmVudHJ1
c3QubmV0L3JwYTAfBgNVHSMEGDAWgBQe8auJBvhJDwEzd+4Ueu4ZfJMoTTAdBgNV
HQ4EFgQUNyg/64Sjw/+b4YOwC8E/c+jemRgwCQYDVR0TBAIwADANBgkqhkiG9w0B
AQUFAAOCAQEAk9Ij+NCp+323+4vBqbA0fT9ZCROptPqNIshY5uEvaWUaW5hsoLUm
fsMJMueqzDaoj4yPD8iCCZq1Mp8tM8WB2mG1zIxTLshlhRgDDUF11IbUUBHv/ZhU
RzXewQD6pazQmsBPuR0vP3mmWbKqmZOiv2yWSGlQmWGW4m6RQwjYYj8UqqFEdinV
g1+qY6/muTpaCiygDjJZBlv9P6bwwP9FB8OJf5tGECvvxXad3PK/oiI77aLTYSVr
SA0oisXCiqcgTKQq5BV5M3fQQ4ZS73aBKLI0wPYc0AASD5WdtPTGTvmEbhO4KeaU
0SL85Prf8uSsDOLvn3656awLz/H/yzrf/g==
-----END CERTIFICATE-----
subject=/C=US/ST=California/L=Cupertino/O=Apple Inc/OU=Internet Services/CN=gateway.sandbox.push.apple.com
issuer=/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
---
No client certificate CA names sent
---
SSL handshake has read 2549 bytes and written 2017 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 1024 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : AES256-SHA
Session-ID:
Session-ID-ctx:
Master-Key: 729CC0899B36143DAC78D40B2C31ECB71C81A3BD8DC5CFD6D71AC7885DD2E63DCD47096E97A1B3AF032A8D7D48BF73DA
Key-Arg : None
Start Time: 1336636910
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
name
closed
unknownc42c032e8297: PushChatServer name$ php simplepush.php
Connected to APNS
Message successfully delivered
Here i able to connect with apns and send notifications. So think no problems with .pem files.
[EDIT] Could you try setting the obsolute path to certificate file in config?
You can check this to solve peer verification issue.
Install the certificate http://code.google.com/p/apns-php/wiki/CertificateCreation#Verify_peer_using_Entrust_Root_Certification_Authority
Use here
stream_context_set_option($ctx, 'ssl', 'cafile', 'entrust_2048_ca.cer');
Note: Disable the verification also works.