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.
Something that worked for me was updating the permissions on the ck.pem file so that the PHP script could read it correctly. Once done I could connect to APNS without any problems.
[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
Note: Disable the verification also works.