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);
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.
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
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:
http://code.google.com/p/apns-php/
http://www.easyapns.com/
And a very good Java library (I currently use it for massive pushes):
https://github.com/notnoop/java-apns
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! ;)
Related
I have hosted my PHP code on google cloud.
I want to send push notifications to ios app. I have enabled port 2195 and 2196.
While sending the push notification I got the following error :
Warning: stream_socket_client(): SSL: Connection reset by peer
Warning: stream_socket_client(): Failed to enable crypto
Warning: stream_socket_client(): unable to connect to
ssl://gateway.push.apple.com:2195 (Unknown error)
I am not much familiar with Google Cloud. What should I do to make it working?
Here is code:
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', PEM_FILE_PATH . 'apns-dev.pem');
$fp = stream_socket_client("ssl://gateway.push.apple.com:2195", $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
$data['msgs'] = "Failed to connect $err $errstr \n";
} else {
$payload = json_encode($body);
$msg = chr(0) . pack("n", 32) . pack("H*", str_replace(" ", "", $deviceToken)) . pack("n", strlen($payload)) . $payload;
$result = fwrite($fp, $msg);
if (!$result) {
$data['msgs'] = 'Message not delivered'; //. PHP_EOL;
} else {
$data['msgs'] = 'Success'; //. PHP_EOL;
}
fclose($fp);
}
return $data;
The main problem when we are trying to send data to the APNS (Apple Push Notification Service) servers is the SSL certificates.
APNS uses this technology in order to serve more secure connection to its users.
As it is said at APNS documentation: "Each certificate is limited to a single app and is also limited to one of two development environments, each with its own assigned hostname". So you can use two environments
Development (testing environment): ssl://gateway.sandbox.push.apple.com:2195
Production (once the app is launched): ssl://gateway.push.apple.com:2195
If you want to test if you can connect to APNS server, just try the following command:
$ telnet gateway.sandbox.push.apple.com 2195
Trying 17.172.232.226...
Connected to gateway.sandbox.push-apple.com.akadns.net.
Escape character is '^]'.
If you get an error then make sure your firewall allows outgoing connections on port 2195.
Then you can test if your SSL certificate and private key are working and it can be set up a secure connection:
$ openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert YourDevCert.pem -key YourPrivateKey.pem
Enter pass phrase for YourPrivateKey.pem: ******
If this works it means that your certificates are correctly set up (you should see a whole bunch of output, which is openssl letting you know what is going on under the hood).
Once knowing all of this information, I see that you have one mistake in your code and also you should check something else:
Check if you have a good connection with APNS server.
Check that your $payload variable is a json string.
Check that you have a correct $deviceToken.
Check that you are using the right certificate with the right environtment. In this case, you are setting a apns-dev.pem certificate and you are sending it to the production environment (I interpret that your production certificate is apns-prod.pem so check it).
Check that your PHP file can find your certificate.
One of your problems, you haven't set any password for your private key. You should add the following line once you have added your certificate:
stream_context_set_option($ctx, "ssl", "passphrase", "your_private_key");
If you have some troubles or doubts, I followed this tutorial to send my first APNS Push Notifications.
I got a error like failed to connect 111 connection refused php push notification using APNS.
It's working fine on local server but not working on GoDaddy shared server.Please find my Php code.
$path_pem_file="http://dummy.com/uploads/app/1.pem";
// this is the pass phrase you defined when creating the key
$passphrase = '';
// this is where you can customize your notification
$payload = '{"aps":{"alert":"message","sound":"default"}}';
// start to create connection
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', $path_pem_file);
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
$fp = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', 'Device token here..') . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if ($fp) { fclose($fp);}
You need to have following PORTs open on your server to use Apple APNs
2195
2196
As far as I know GoDaddy will not open this ports for you on shared hosting and you will have to go for Dedicated server or VPS.
If you are using GoDaddy Web Hosting, they will not open the ports to send push. If you are using GoDaddy Virtual Private Servers, then you can call them and get the ports unlocked.
You need to go for Dedicated Hosting.
Please have a look on the following url, this may help you :
http://www.buzztouch.com/forum/thread.php?tid=b580c417cbbc86eb9575ea0¤tpage=1
I have a problem, I'd like to send out push notifications using php, however I keep getting this error:
Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Connection refused) in /home/colupon/public_html/iPhone/push/index.php on line 21
Failed to connect: 111 Connection refused
My code is as follows:
$deviceToken = '0f************************************************************78';
$passphrase = '************';
$message = 'My first push notification!';
////////////////////////////////////////////////////////////////////////////////
$ctx = stream_context_create();
$filename = 'ckdev.pem';
stream_context_set_option($ctx, 'ssl', 'local_cert', $filename);
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
echo 'Connected to APNS' . PHP_EOL;
// Create the payload body
$body['aps'] = array(
'alert' => $message,
'sound' => 'default'
);
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) .
$payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered'.PHP_EOL;
// Close the connection to the server
fclose($fp);
?>
I believe the problem is with the server I'm using because I posted the same code and the same .pem file on a different server and it sent the notification without any problem. I attempted to open up ports on the firewall for my server because I read that might cause this problem, but the same error message still showed up. Is there anything else I can do? Any help would be greatly appreciated, thanks!
This issue is common problem in Apple Push notification, to resolve this error you have to go through as follows:
Test your pem files locally and remotely in server if the problem is server go to 2 else build pem correct file.
Set up the permission wrong on the folder that had the certificate file. This worked for me:
chmod 755 your_folder_that_has_certificate_files
3.Check connectivity of apns port 2195 from your hosting server as follows:
run
telnet gateway.push.apple.com 2195
if this is the problem
Trying 17.172.233.36...
telnet: connect to address 17.172.233.36: Connection refused
you can solve this issue by opening the port 2195 on the production server. You can verify by following command $telnet gateway.push.apple.com 2195
-bash-3.2# telnet gateway.push.apple.com 2195
Trying 17.149.38.141...
Connected to gateway.push.apple.com (17.149.38.141).
Escape character is '^]'.
Connection closed by foreign host.
In case of MAC,
(built-in server was working fine using terminal but not through browser, for me, so i installed MAMP.)
1.Go to---> /Library/WebServer/Documents/----copy both php and ckdev.pem file here.
2 go to terminal-->$open /private/etc-->go to--->apache2>originals>httpd.config file-->
**"#LoadModule php5_module libexec/apache2/libphp5.so", remove "#"..(perhaps, you would have to change the permission also..!)
then goto browser and check--> localhost/yourPhpFile.php
In Case of Windows system,
1.Install WAMP,
2.goto php.ini file--->search for this ";extension=php_openssl.dll" line and remove semicolon ";".
3.click WAMP icon from right-bottom goto PHP>PHP Extensions>select php_openssl..
That's it..hope this may help further seekers.
In my case the problem was that I forgot to setup my passphrase correctly in php script.
<?php
// Put your device token here (without spaces):
$deviceToken = 'xxx';
// Put your private key's passphrase here:
$passphrase = 'xxx';
To me, it was the SELinux issue.
So in your /etc/selinux/config file, set the SELINUX=enforcing to SELINUX=disabled. And restart. Thats it.
I just had the SAME error and I found the solution for my problem.
‚mypassword‘ instead of 'mypassword'
Seems like notepad changed the quotes. This literally took me 4 hours... Hopefully someone will read this and save some time...
I have to send push notification to iOS devices. My connection has to be enabled through a proxy. I tried everything but without success. I have an error 110 Connection Timed Out. It's working with cURL if I just try to connect to Apple push's address. I don't know where the problem is. Proxy config ? PHP stream_context wrong implementation ?
Here's my code :
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'certificate.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', 'my_passphrase');
stream_context_set_option($ctx, 'ssl', 'verify_peer', false);
stream_context_set_option($ctx, 'http', 'proxy', 'tcp://my-proxy.net:8080');
stream_context_set_option($ctx, 'http', 'request_fulluri', true);
$fp = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err,$errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
var_dump($fp);
var_dump($err);
var_dump($errstr);
exit;
Do you have an idea ?
EDIT:
Can it be directly linked to Squid ? I just figured out the proxy is running with Squid.
I also try with fopen() function instead of stream_socket_client() but it seems it doesn't allow ssl protocol.
Here's my var_dump outputs : bool(false) int(110) string(20) "Connection timed out"
I also have this warning : Warning: stream_socket_client(): unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Connection timed out) in /share/www/website/test.php on line 22
It could simply be your proxy does not allow port 2195 to be opened.
iPhone Push Notification Unable to Connect to the SSL Server
I guess you either:
Need to talk to the people who run the proxy to see if port 2195 is open or not.
or
Setup a test server listening on port 2195 and then try to do a test connection to it through the proxy. That should allow you to test if it is the proxy that is blocking the connection requests.
or
Test whether Curl can open the connection using a proxy.
Which is done by setting the options:
// sets the proxy to go through
curl_setopt($ch, CURLOPT_PROXY, $proxy);
// sets to use a tunnel proxy which most http proxies are
curl_setopt($ch, CURLOPT_HTTPTUNNELPROXY, $proxy);
Full testing code here.
create the SSL context
open a tcp socket to the proxy
send request to the proxy to connect to APNs
once connexion is accepted enable SSL
Have a look at my reply in this post: Send Push Notification to APNS through proxy
I have a PHP file with the following content that works perfectly on development ceritficates, but when I switch to a production certificate the PHP errors and gives the below message, but it only does this about 50% of the time. The other 50% it works. Anyone know why this might be happening?
<?php
// masked for security reason
$deviceToken = 'xxxxxx'; // jq
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', dirname(__FILE__)."/prod.pem");
$number = 5;
$fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
print "Failed to connect $err $errstr\n";
}
else {
print "Connection OK\n";
$msg = $_GET['msg'];
$payload['aps'] = array('alert' => $msg, 'badge' => 1, 'sound' => 'default');
$payload = json_encode($payload);
$msg = chr(0) . pack("n",32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
print "sending message :" . $payload . "\n";
fwrite($fp, $msg);
fclose($fp);
}
?>
The PHP error:
Warning: stream_socket_client() [function.stream-socket-client]: Unable to set local cert chain file `/var/www/vhosts/thissite.com/httpdocs/prod.pem'; Check that your cafile/capath settings include details of your certificate and its issuer in /var/www/vhosts/thissite.com/httpdocs/pushMessageLive.php on line 19
Warning: stream_socket_client() [function.stream-socket-client]: failed to create an SSL handle in /var/www/vhosts/thissite.com/httpdocs/pushMessageLive.php on line 19
Warning: stream_socket_client() [function.stream-socket-client]: Failed to enable crypto in /var/www/vhosts/thissite.com/httpdocs/pushMessageLive.php on line 19
Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Unknown error) in /var/www/vhosts/thissite.com/httpdocs/pushMessageLive.php on line 19
Failed to connect 0
I had the same issue. You have to make a persistent socket connection with Apple's Push Notification Server. I've written up a tutorial for a python daemon called pyapns (http://github.com/samuraisam/pyapns) which worked very well for me:
http://www.how2s.org/index.php/How_to_get_started_with_Apple_Push_Notifications_for_iPhone_or_iPhone_Touch
This works assuming you are running Debian and have root access to install the required packages such as python-twisted, libcurl4-openssl-dev etc.
Sounds like too many connects. Apple's docs state that you need to hold the connection open and send as many as you can at the same time. Re-opening is considered DOS attack. So try making it persistent and see if you get same error.
I don't know if the error you are experiencing are because of too many connects to the push servers... In my experience, those limits are a bit hard to reach.
But PHP on the other hand have been acting strange when I've tried to send batches of push notifications. I'm not sure from your sample code, but I guess you do a stream_socket_client() and fclose() for every message? Using that technique with SSL sockets in PHP, the only thing I've personally have accomplished is failure...
I'm not sure if you have the possibility to run Ruby on your server, but if you can, I recommend switching to ruby-apns-daemon to handle the talk with Apple's servers. It's lightweight and easy to implement in PHP (you practically compose the same payload-JSON, but send it to ruby-apns-daemon instead of through a socket).
I've had the same issue and certificate was in fault. You can see solutions here How can I do an SSL connection with PHP and here Error using ssl cert with PHP.
Hope it'll help you.
And for the record you are not obliged to make a persistent connection with APNS. Though it's best to send all your messages at once, you can connect and disconnect multiple times. I quote Apple's website :
You should also retain connections
with APNs across multiple
notifications. APNs may consider
connections that are rapidly and
repeatedly established and torn down
as a denial-of-service attack. Upon
error, APNs closes the connection on
which the error occurred.
If you don't create hundred of connections at a time you should not get troubles.