4
votes

I tested push notification on my local machine, it is working perfectly. I then uploaded my files to the real server with the same certificate (".pem" file), and I ensure that the ports 2195 and 2196 are open.

I tested:

telnet gateway.sandbox.push.apple.com 2195

It is working...

root@server ~ # telnet gateway.sandbox.push.apple.com 2195

Trying 17.149.34.54...

Connected to gateway.sandbox.push.apple.com.

Escape character is '^]'.

But when I test from my php script, it returns:

Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Connection timed out)

Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://feedback.sandbox.push.apple.com:2196

Any suggestions?


This is the php code:

$ctx = stream_context_create(); 

stream_context_set_option($ctx, 'ssl', 'local_cert',
   "path/to/certificate"); 

$fp = stream_socket_client("ssl://gateway.push.apple.com:2195",
   $error, $errorString, 100,
   (STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT), $ctx);
4
Please show your entire PHP code...powtac
$ctx = stream_context_create(); stream_context_set_option($ctx, 'ssl', 'local_cert', "path/to/certificate"); $fp = stream_socket_client("path/to/certificate", $error, $errorString, 100, (STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT), $ctx);yasserislam
It is better to add this to your question, just edit it.Paul Hiemstra
i added the correct php code in the questionyasserislam

4 Answers

5
votes

This code will work fine:

 $device = 'sdfsdfsfsdffsd';
$payload['aps'] = array('alert' => 'Hello I am testing the server code ....', 'badge' => 1, 'sound' => 'default');
$payload = json_encode($payload);

$options = array('ssl' => array(
  'local_cert' =>'ck.pem',
  'passphrase' => 'abc123'
));



$streamContext = stream_context_create();
stream_context_set_option($streamContext, $options);
$apns = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $error, $errorString, 60, STREAM_CLIENT_CONNECT, $streamContext);

$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $device)) . chr(0) . chr(strlen($payload)) . $payload;
fwrite($apns, $apnsMessage);
fclose($apns);

Only check the pem file path, and the port is on.

2
votes

I had the same problem of receiving 'unable to connect to ... (Connection timed out)'. I can connect from my home machine, but I can't from the hosting server.

In my case, port 2195 and 2196 weren't simply open from the hosted server. I had to contact technical support to open those ports. Ping may work, because it uses different port number. So please contact to your hosting service company to ensure those ports are open.

Good luck,

Kaz

0
votes

In the stream_socket_client function, you should not pass the certificate path, but the APNS url.

This method opens a connection and returns it:

public function connect(){

        $streamContext = stream_context_create();
        stream_context_set_option($streamContext, 'ssl', 'local_cert', '/your/cert/path');
        $apns = stream_socket_client('use.apns.url.here', $error, $errorString, 9, STREAM_CLIENT_CONNECT, $streamContext);

        if (!$apns){
            $this->logger->error("Failed to connect to APNS: {$error} {$errorString}.");
        }

        return $apns;
    }

Once you built your apns message, you can push it using the following

fwrite($apns, $apnsMessage);

You can follow this tutorial http://goo.gl/9Q0u if your goal is to implement your own push notification API.

There are also existing php libraries:

And a very good Java library (I currently use it for massive pushes):

0
votes

You have to set your firewall to allow all the 17.0.0.0/8 block (it all belongs to Apple!). Check THIS ANSWER

And according to Apple:

The APNs servers use load balancing, so your devices won't always connect to the same public IP address for notifications. It's best to allow access to these ports on the entire 17.0.0.0/8 address block, which is assigned to Apple.

If you are using CSF firewall (like me), I'd recommend to add this line to csf.allow file:

tcp|out|d=2195|d=17.0.0.0/8

Using this instead of just "17.0.0.0/8" will allow only outbond connections to Apple and specifically to port 2195. NSA won't like it but this is much more precise and safe! ;)