The push works just fine, the problem is that the feedback is empty. I need to delete the tokens that have expired or have an invalid status.This is what I write test code,this a problem?]
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
$fp = stream_socket_client('ssl://feedback.sandbox.push.apple.com:2196', $error, $errorString, 60, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
return;
}
while ($devcon = fread($fp,38)) {
$arr = unpack("H*", $devcon);
$rawhex = trim(implode("", $arr));
$feedbackTime = hexdec(substr($rawhex, 0, 8));
$feedbackDate = date('Y-m-d H:i', $feedbackTime);
$feedbackLen = hexdec(substr($rawhex, 8, 4));
$feedbackDeviceToken = substr($rawhex, 12, 64);
}
fclose($fp);
Feedback services don't always return data. You will get data only if there is need to report failed deliveries.
See the documentation here.
Not sure if this is true but I have noticed feedback services don't work with the sandbox environment (at least I haven't received a response any time I checked with sandbox)
Related
I ddevelop in mac.
stream_socket_server(): unable to connect to udp://192.168.50.191:1234 (Can't assign requested address)
What's the matter? Thanks for your help.
$socket = stream_socket_server("udp://192.168.50.191:1234", $errno, $errstr, ST$
if (!$socket) {
die("$errstr ($errno)");
}
do {
$pkt = stream_socket_recvfrom($socket, 1, 0, $peer);
echo "$peer\n";
stream_socket_sendto($socket, date("D M j H:i:s Y\r\n"), 0, $peer);
} while ($pkt !== false);
May be you need run as root user.
On Windows working without admin privileges.
My iOS app should support push notifications through APN and I have uninstalled and re-installed my app into my iPhone 6S three times which means that I have three different couples <device-id, device-token> in an apposite MySQL table of which only the last (the maximum id) is the most recent and thus the valid one. Then, I wrote this PHP script which I found here in StackOverflow which should return the invalid tokens to be deleted from the database:
<?php
$cert_file = './superbar-development.pem';
$stream_context = stream_context_create();
stream_context_set_option($stream_context, 'ssl', 'local_cert', $cert_file);
$apns_connection = stream_socket_client('feedback.sandbox.push.apple.com:2196', $error_code, $error_message, 60, STREAM_CLIENT_CONNECT, $stream_context);
if($apns_connection === false) {
apns_close_connection($apns_connection);
error_log ("APNS Feedback Request Error: $error_code - $error_message", 0);
}
$feedback_tokens = array();
while(!feof($apns_connection)) {
$data = fread($apns_connection, 38);
if(strlen($data)) {
$feedback_tokens[] = unpack("N1timestamp/n1length/H*devtoken", $data);
}
}
fclose($apns_connection);
print_r($feedback_tokens);
?>
But I always get and empty array which means that the first two couples <device-id, device-token> have not been detected as invalid yet. How much time does it take to do that? I am asking this because I have seen that connecting to and reading from feedback.sandbox.push.apple.com:2196 is very very slow so I wouldn't like to cron to do it every time it has to send push notifications. Do you know anything about this? Thank you.
I have an ssl server (test) in c - and a client written in php. the server works fine when a client written in c connects, but when the php client (virtually identical to the c client) sends, the message appears on the server only after buffer overflow or disconnect.
why a c program and not a php program would work is a mystery to me.
I've tried buffer control, unblocking, adding nulls to the send string.
php 5.4 centos linux 2.6
i can add code if appropriate - it's quite vanilla. but i thought there might be a difference between the way php handles stream traffic and c. my confidence in my code.
thanks for any thoughts.
#!/usr/local/bin/php
<?php
date_default_timezone_set('America/New_York');
$host = 'localhost';
$port = 9255;
$timeout = 5.0;
function gen_cert($pem_file,$pem_passphrase)
{
// Certificate data:
$dn = array(
"countryName" => "US",
"stateOrProvinceName" => "Texas",
"localityName" => "Houston",
"organizationName" => "<org name>",
"organizationalUnitName" => "Tech",
"commonName" => "kensie2",
"emailAddress" => "<email>"
);
// Generate certificate
$privkey = openssl_pkey_new();
$cert = openssl_csr_new($dn, $privkey);
$cert = openssl_csr_sign($cert, null, $privkey, 365);
// Generate PEM file
$pem = array();
openssl_x509_export($cert, $pem[0]);
openssl_pkey_export($privkey, $pem[1], $pem_passphrase);
openssl_pkey_export($privkey, $pem[1], $pem_passphrase);
$pem = implode($pem);
// Save PEM file
// $pemfile = $filename;
file_put_contents($pem_file, $pem);
chmod($pem_file,0400);
}
$pem_passphrase = 'foozot';
$pem_file = 'test3_client.pem';
if(!file_exists($pem_file))
gen_cert($pem_file,$pem_passphrase);
$context = stream_context_create();
// local_cert must be in PEM format
stream_context_set_option($context, 'tls', 'local_cert', $pem_file);
// Pass Phrase (password) of private key
stream_context_set_option($context, 'tls', 'passphrase', $pem_passphrase);
stream_context_set_option($context, 'tls', 'allow_self_signed', true);
stream_context_set_option($context, 'tls', 'verify_peer', true);
$fp = stream_socket_client('tls://'.$host.':'.$port, $errno, $errstr, $timeout,
STREAM_CLIENT_CONNECT, $context);
if($fp)
{
$buf = fread($fp,8192);
fwrite(STDOUT,"from server: $buf");
// tried this - no difference
// stream_set_write_buffer($fp,0);
// tried this - no difference
// stream_set_blocking($fp,0);
$ary = stream_get_meta_data($fp);
fwrite(STDERR,"meta=" . print_r($ary,true) . "\n");
while(1)
{
$buf = fgets(STDIN);
fwrite(STDOUT,"buf=$buf\n");
if(strstr($buf,"\n") === null)
$buf .= "\n\0";
$er = fwrite($fp, $buf,strlen($buf) + 1);
fwrite(STDERR,posix_strerror(posix_get_last_error()) . "\n");
}
}
else
{
echo "ERROR: $errno - $errstr<br />\n";
}
?>
I'musing code from Professional Linux Network Programming - Chapter 8 - server.c
By Nathan Yocom, plnp#yocom.org modified to prefork. it uses BIO for io.
as a model for the c code. i don't think i can post it without some copyright violation.
it does work. far more tested than my code.
I'm sending push notifications and when the message contains foreign characters (Turkish in my case) like İ, ş, ç, ğ... The message does not arrive to devices.
Here's my code:
$message = 'THİS is push';
$passphrase = 'mypass';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'MyPemFile.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.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 Apple service. ' . PHP_EOL;
// Encode the payload as JSON
$body['aps'] = array(
'alert' => $message,
'sound' => 'default'
);
$payload = json_encode($body);
$result = 'Start'.PHP_EOL;
$tokenArray = array('mytoken');
foreach ($tokenArray as $item)
{
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $item) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Failed message'.PHP_EOL;
else
echo 'Successful message'.PHP_EOL;
}
// Close the connection to the server
fclose($fp);
I have tried encoding $message variable with utf8_encode() but the message received as "THÝS is push". And other ways like iconv() didn't work for me, some of them cropped Turkish characters, some didn't receive at all.
I also have
header('content-type: text/html; charset: utf-8');
and
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
in my page. I don't think the problem appears while I set the value but maybe with pack() function.
Any ideas to solve this without replacing characters with English?
All I had to do was replacing the Turkish characters with following script:
function tr_to_utf($text) {
$text = trim($text);
$search = array('Ü','Ş','Ğ','Ç','İ','Ö','ü','ş','ğ','ç','ı','ö');
$replace = array('Ãœ','Å','Ğ','Ç','Ä°','Ö','ü','ÅŸ','ÄŸ','ç','ı','ö');
$new_text = str_replace($search,$replace,$text);
return $new_text;
}
Now it is working with no problems.
This is the source.
The "n" parameter means, that you pack as unsigned short (always 16 bit, big endian byte order). I`m not sure how Apple CPU hardware handle the instructions and how convert them, but is different from the PC for sure. Try to switch the byte order, use "v" unsigned short (always 16 bit, little endian byte order).
Can someone clarify what the APNs (Apple Push Notification) wants as far as how you query it?
The docs say it starts sending as soon as the connection is made. Does this mean that I don't do an fread() on it?
Here's my current code to try and read it. I did NOT put the fread() in a loop as I do not know what response indicates "no more records to read" and I didn't want an infinite loop on my server.
<?php
$apnsCert = 'HOHRO-prod.pem';
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
stream_context_set_option($streamContext, 'ssl', 'verify_peer', false);
$apns = stream_socket_client('ssl://feedback.push.apple.com:2196', $error, $errorString, 60, STREAM_CLIENT_CONNECT, $streamContext);
echo 'error=' . $error;
echo 'errorString=' . $errorString;
$result = fread($apns, 38);
echo 'result=' . $result;
fclose($apns);
?>
So far all I am getting is a null reply. There are no errors so it is connecting.
I don't know if the null reply means no data is there, or my fread() is the wrong way to do it.
Thanks
Here's a big gotcha which confused me when I first tried connecting: the APNS feedback servers only return the device tokens that have "expired" since your last feedback request. Which means most of the time you'll get a NULL response unless you're already dealing with a high volume of users of your app.
So make sure you store the expired device tokens to disk or db, because after your feedback query they're gone for good. This makes testing a pain to say the least!
Here's a complete function to fetch the device tokens from the APNS feedback servers (many thanks to the answers above for helping me put it all together):
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', '/path/to/my/cert.pem');
$apns = stream_socket_client('ssl://feedback.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;
}
If all is well, the return values from this function will look something like this (via print_r()):
Array
(
Array
(
[timestamp] => 1266604759
[length] => 32
[devtoken] => abc1234..............etcetc
),
Array
(
[timestamp] => 1266604922
[length] => 32
[devtoken] => def56789..............etcetc
),
)
That code looks right however you need to loop and check for end of stream in order to read all the device codes.
while (!feof($apns)) {
$devcon = fread($apns, 38);
}
However my problem is the actual unpacking of the data. Does anyone know how to unpack the binary data which you've just read to get the actual device ID (as string) along with the timestamp etc?
I got the solution from apple forum and it is for development. Try this for production also.
"Well, as dumb as it sounds, I found a solution:
Create a dummy app id in the program portal, enable development push notifications on it
Create and download the associated provisioning profile
Create a new xcode project, and invoke the registerForRemoteNotificationTypes method on start.
Install the dummy app on your device. At this point, you should have two DEVELOPMENT apps running on your device: the original app and the dummy app. Both should be registered to receive push notifications.
Uninstall the original app, and try to send a push notification to that app.
Invoke the feedback service, and you should receive data back."
This finally worked for me.
$arr = unpack("H*", $devconts);
$rawhex = trim(implode("", $arr));
$feedbackTime = hexdec(substr($rawhex, 0, 8));
$feedbackDate = date('Y-m-d H:i', $feedbackTime);
$feedbackLen = hexdec(substr($rawhex, 8, 4));
$feedbackDeviceToken = substr($rawhex, 12, 64);
And then you simply check for the device token against the timestamp!
Just started using this library - works great for me!
https://github.com/mac-cain13/notificato