Communicate with APNS from PHP - php

I would like to communicate with the Apple Push Notification Service from a PHP script.
But I keep getting following error:
Warning: stream_socket_client(): Unable to set private key file
I have a .pem-file which looks like this:
-----BEGIN CERTIFICATE-----
Encrypted String
-----END CERTIFICATE-----
Bag Attributes
friendlyName: ...
localKeyID: ...
Key Attributes: ...
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: ...
DEK-Info: ...
Encrypted String
-----END RSA PRIVATE KEY-----
I am running the PHP script from sudo. It can find my .pem file, because if I remove it, I get a "handshake failure" error instead.
What could be wrong here?

I recently made a script to send remote pushnotifications.
This is how I did it:
$message = "A cool message!";
$deviceid = "";
$count = 0;
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'apns-dev.pem');
$fp = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
echo 'Failed to connect ' . $err . $errstr;
} else {
$payloads['aps'] = array('alert' => $message, 'badge' => 1, 'sound' => 'default');
$payload = json_encode($payloads);
$msg = chr(0) . pack('n',32) . pack('H*', $deviceid) . pack('n',strlen($payload)) . $payload;
fwrite($fp, $msg);
$count += 1;
fclose($fp);
}
echo 'Sended: ' . $count;

I got it working. It turns out I exported my private key which I generated for the push notifications instead of the corresponding certificate.

Related

SSL error when adding ios push notification code

I have a code which is supposed to send IOS push messages but it is giving me an error.
My code:
$streamContextCreate = stream_context_create();
stream_context_set_option($streamContextCreate, 'ssl', 'local_cert', '/home/devmzad/public_html/public/ios/MzadDevCertificates.pem');
$fp = stream_socket_client(
'ssl://gateway.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $streamContextCreate);
echo "<pre>";
print_r($fp); //gives error here.
die;
the error I receive is below:
stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages:
error:14094438:SSL routines:SSL3_READ_BYTES:tlsv1 alert internal error
I would appreciate if someone could help me with it. Thanks.
Please try the below code :
<?php
/* We are using the sandbox version of the APNS for development. For production
environments, change this to ssl://gateway.push.apple.com:2195 */
$apnsServer = 'ssl://gateway.sandbox.push.apple.com:2195';
/* Make sure this is set to the password that you set for your private key
when you exported it to the .pem file using openssl on your OS X */
$privateKeyPassword = '1234';
/* Put your own message here if you want to */
$message = 'Welcome to iOS 7 Push Notifications';
/* Pur your device token here */
$deviceToken =
'05924634A8EB6B84437A1E8CE02E6BE6683DEC83FB38680A7DFD6A04C6CC586E';
/* Replace this with the name of the file that you have placed by your PHP
script file, containing your private key and certificate that you generated
earlier */
$pushCertAndKeyPemFile = 'PushCertificateAndKey.pem';
$stream = stream_context_create();
stream_context_set_option($stream,
'ssl',
'passphrase',
$privateKeyPassword);
stream_context_set_option($stream,
'ssl',
'local_cert',
$pushCertAndKeyPemFile);
$connectionTimeout = 20;
$connectionType = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT;
$connection = stream_socket_client($apnsServer,
$errorNumber,
$errorString,
$connectionTimeout,
$connectionType,
$stream);
if (!$connection){
echo "Failed to connect to the APNS server. Error no = $errorNumber<br/>";
exit;
} else {
echo "Successfully connected to the APNS. Processing...</br>";
}
$messageBody['aps'] = array('alert' => $message,
'sound' => 'default',
'badge' => 2,
);
$payload = json_encode($messageBody);
$notification = chr(0) .
pack('n', 32) .
pack('H*', $deviceToken) .
pack('n', strlen($payload)) .
$payload;
$wroteSuccessfully = fwrite($connection, $notification, strlen($notification));
if (!$wroteSuccessfully){
echo "Could not send the message<br/>";
}
else {
echo "Successfully sent the message<br/>";
}
fclose($connection);
?>

Forbidden access when connecting to Apple Push Notification service

I have some troubleshooting when trying to push a notification to my iPhone using the APNs. I use a PHP code that I keep seeing over and over on the Internet so I don't think the problem is about it:
<?php
// Put your device token here (without spaces):
$deviceToken = 'mytoken'; // Of course this is my correct token here
// Put your private key's passphrase here:
$passphrase = 'mypassphrase'; // Same here
$message = $argv[1];
$url = $argv[2];
if (!$message || !$url)
exit('Example Usage: $php newspush.php \'Breaking News!\' \'https://raywenderlich.com\'' . "\n");
////////////////////////////////////////////////////////////////////////////////
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', __DIR__.'/cert.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
'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',
'link_url' => $url,
);
// 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;
stream_set_blocking($fp, 0);
// 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 have the output "Message successfully delivered", so the connection has been successfully established, idem for the sent message. However, the device does not receive anything.
I used the feedback feature to try to know what's wrong, but the result is empty (the array is literally empty):
<?php
function send_feedback_request() {
//connect to the APNS feedback servers
//make sure you're using the right dev/production server & cert combo!
$stream_context = stream_context_create();
stream_context_set_option($stream_context, 'ssl', 'local_cert', __DIR__.'/cert3.pem');
stream_context_set_option($stream_context, 'ssl', 'passphrase', 'meteor0405');
$apns = stream_socket_client('ssl://feedback.sandbox.push.apple.com:2196', $errcode, $errstr, 60, STREAM_CLIENT_CONNECT, $stream_context);
if(!$apns) {
echo "ERROR $errcode: $errstr\n";
return;
}
$feedback_tokens = array();
//and read the data on the connection:
while(!feof($apns)) {
$data = fread($apns, 38);
if(strlen($data)) {
$feedback_tokens[] = unpack("N1timestamp/n1length/H*devtoken", $data);
}
}
fclose($apns);
return $feedback_tokens;
}
var_dump(send_feedback_request());
Would you have any idea on what I can do to figure out what's wrong? Can it be due to the certificate? A .cer file has been generated from the Apple website and been imported into Keychain Access to make a .p12 file. Then, I converted it to .pem format thanks to an openssl command, and this is the one I use in files below.
Thank you!
If you are getting the successful message then it means your PHP code is correct but something is missing from the pem file.Checkout the pem file creation steps here https://www.digicert.com/ssl-support/pem-ssl-creation.htm and try it again.Hope it will help.
The problem was indeed coming from my PEM file. To anyone having the same issue, here is what I did.
After having downloaded the certificate and private key from the iPhone Developper Connection Portal in the .p12 format, I had to convert them into .pem format. After that, I had to merge the two files (put the content of the certificate first, then the private key). This merge has to be put in a new .pem file, and this is the file to use in the PHP script.
Here is the full tutorial I followed: https://blog.serverdensity.com/how-to-build-an-apple-push-notification-provider-server-tutorial/
Moreover, the PHP code is not exactly the same. The one I used in the first post was not correct, use the tutorial's one instead.

APNS push notifications not being sent

Actually I am new to APNS and I have been using some help from the online forums and blogs. I am using PHP to implement the server side. The following is my PHP code
<?php
// Put your device token here (without spaces):
$deviceToken = '0f744707bebcf74f9b7c25d48e3358945f6aa01da5ddb387462c7eaf61bbad78';
// Put your private key's passphrase here:
$passphrase = 'pushchat';
// Put your alert message here:
$message = 'My first push notification!';
////////////////////////////////////////////////////////////////////////////////
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
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 '
' . PHP_EOL;
// Close the connection to the server
fclose($fp);
I have converted the .p12 file to a PEM file and named it as ck.pem and has hosted it on the same location as the php file resides. When I execute the PHP file, the following gets printed. Is there something I am missing. I am doubtful about the certificate part.
Connected to APNS
Message successfully delivered
I had the exact same problem, using the exact same example code - works perfect for android but fails for IOS with no returning error.
To fix my problem I had to create the SSL cert again against the app and then run
openssl x509 -in aps_development.cer -inform der -out aps_development.pem
openssl pkcs12 -nocerts -out aps_developmentKey.pem -in ios_development.p12
cat aps_development.pem aps_developmentKey.pem > ck.pem
Finially tested against:
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert aps_development.pem -key aps_developmentKey.pem -CAfile entrust_2048_ca.cer
After this everything worked perfect, that was on the 29th Sept - Its now stopped working so I think its the Certs again but at least it may help you with your solution.
I actually replaced the UDID of the device with the Device Token and it works like a charm. You cannot use UDID anymore.

Push Notification Crypto error

I use Push Notifs in my PHP Laravel app. I created a pem file and tested it. When using it on my dev machine, it correctly pushes to the mobile device. When I now push the whole project to my production server, and start the pushnotif call, I get the error: Failed to enable crypto
Do I need to create a special pem file while being on production server? And I am not talking about "production certificates" I still want to use the sandbox for testing
<?php
namespace App\Helpers;
use Carbon\Carbon;
use Illuminate\Support\Facades\Config;
class PushNotificationHelper {
public function pushToResponder($deviceToken) {
// Set device token of mobile device and the passphrase for certification
$pushToken = $deviceToken;
$passphrase = Config::get('MFConfig.PushNotificationTest.passPhrase');
$APNS = Config::get('MFConfig.PushNotificationTest.APNS');
// Open new context for streaming and set certificate as well as passphrase
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', '../App/Certificates/ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
stream_context_set_option($ctx, 'ssl', 'cafile', '../App/Certificates/entrust_2048_ca.cer');
// Open connection to APNS
$fp = stream_socket_client($APNS, $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
// If no connection could be made then fail with error, otherwise connect
if (!$fp) {
exit("Failed to connect: $err, $errstr" . PHP_EOL);
}
echo 'Connected to APNS' . PHP_EOL;
// Create the payload body
$body['aps'] = array(
'alert' => "MEDIFAKTOR Einsatz",
'sound' => 'default'
);
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $pushToken) . pack('n', strlen($payload)) . $payload;
// Send to server
$result = fwrite($fp, $msg, strlen($msg));
// If no result is available, the message was not delivered.
if(!$result) {
echo 'Message not delivered.' . PHP_EOL;
} else {
echo 'Message successfully delivered.' . PHP_EOL;
}
// Close connection
fclose($fp);
}
}
I tested the connection with:
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert ck.pem -debug -showcerts -CAfile entrust_2048_ca.cer
and it returns status 0 (ok) which is fine I think?
but when I call the function I get: failed loading cafile stream
Not sure about this, but it might be your php settings in the dev enviroment.
try to locate the cacert.pem file.
If you are using a linux system you can try locate cacert.pem using the terminal.
When you find the location find the php.ini file and find this line:
;openssl.cafile =
and change this to
openssl.cafile= path from locate cacert.pem command or the location the .pem is actually located.
Report back on how it went.

Apple Push Notification SSL Error

I got the following error message, when trying to send a push notif via PHP:
stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages:
error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
I guess it could be the issue with the SSL3 problems in the past? But does this mean the script is not usable that way anymore? What do I need to change, as i have no clue. I checked all certificates and they are working. I can connect to the sandbox at apple via terminal with the certificates and the handshake seems to work via terminal.
This is my PHP Script
class PushNotification {
public function sendTestMessageToDevice($message){
$devicetoken = Config::get('mfsconfig.PushNotificationTest.deviceToken');
$passphrase = Config::get('mfsconfig.PushNotificationTest.passPhrase');
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open connection to APNS
$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 a binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $devicetoken) . pack('n', strlen($payload)) . $payload;
// Send to server
$result = fwrite($fp, $msg, strlen($msg));
if(!result) {
echo 'Message not delivered' . PHP_EOL;
} else {
echo 'Message successfully delivered' . PHP_EOL;
}
fclose($fp);
}
I think I got the solution:
Click the disclosure arrow next to your certificate in Keychain Access and select the certificate and the key.
Right click and choose Export 2 items
Choose the p12 format from the drop down and name it cert.p12.
Now covert the p12 file to a pem file:
$ openssl pkcs12 -in cert.p12 -out apple_push_notification_production.pem -nodes -clcerts
After uploading the newly created pem file, everything works smoothly!

Categories