programcode
programcode

Reputation: 102

Can this php script still be used to send test push notifications using APNs? [Certificate Based Connection]

This script used to send test push notifications to test devices before Apple made the switch to the new APNs Provider API, which I'm surprised more people aren't talking about.

Now when I run the script from the terminal typing and entering php simplepush.php, the output says

enter image description here

Though no message is received.

//simplepush.php

<?php

// Put your device token here (without spaces):
$deviceToken = 'EXAMPLETOKEN';
// Put your private key's passphrase here:
$passphrase = 'pushchat';
// Put your alert message here:
$message = 'Hello!';
////////////////////////////////////////////////////////////////////////////////
$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://api.sandbox.push.apple.com:443', $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);

Since Apple made the switch last March, I have:

  1. Created a new Certificate Signing Request
  2. Registered a new App ID
  3. Established a Certificate-Based Connection to APNs
  4. Obtained a new Provider Certificate from Apple
  5. Installed the Certificate and Private Key
  6. Established Trust with APNs
  7. Sent Push Notifications Using Command-Line Tools

And I am able to get a test notification when I follow Sending Push Notifications Using Command-Line Tools.

curl -v --header 'apns-topic: com.your.site' --header apns-push-type: alert --cert aps.cer --cert-type DER --key PushChatKey.pem --key-type PEM --data '{"aps":{"alert":"Test"}}' --http2 https://api.sandbox.push.apple.com/3/device/DEVICETOKEN

enter image description here

Is it possible to still use this php script to send test push notifications since apple made the change to the new APNs Provider API? I know that the Apple developer documentation mentions required header request fields but I honestly can't tell if those are to be implemented from the terminal or from directly within the script.

enter image description here

Upvotes: 0

Views: 1707

Answers (2)

Blazej Kita
Blazej Kita

Reputation: 135

I've just written a some code for new version APNS. For comunication we need "The 10-character Key ID you obtained from your developer account", "Team ID" and token refreshing... : "...once every 20 minutes and no less than once every 60 minutes..."

More: Apple Documentation

When I send noticication first time, I save token to cache file to use it again..

class PushNotifications {
    
                
    public function iOS($data, $devicetoken) {

              
                $tokenTMP = 'files/cert/token_apn';  //TOKEN CACHE
                $domain   = 'pl.domain.*****';
           
                
                $def = 'alert';
                
                $url = 'https://api.push.apple.com:443';
                
                if($devicetoken =='e9886c41112d766eb3513ffbcc12ed92cbcb68ecf1e42413319b115d3c3a1ebec') //My test token
                {
                   $url = 'https://api.sandbox.push.apple.com:443'; //sandbox
                   $def = 'alert';
                }
           
                

                //----------------
                //For security, APNs requires you to refresh your token regularly. Refresh your token no more than once every 20 minutes and no less than once every 60 minutes.
                
                $token = '';
                
                if(file_exists($tokenTMP))
                {
                    $fileTime = filemtime($tokenTMP);
                    $maxT     = time() - 1800; //max 30 min.
                    $min     = time() - 3600; //max 30 min.
                    
                    if(  $fileTime > $min && $fileTime < $maxT )
                    {
                        $token = file_get_contents($tokenTMP);
                       // echo 'I get last generated token..';
                    }                                       
                }                
                
                //----------------
                
                if($token == '') //Let's generate new token...
                {
                   // echo 'Generate new token...';
                    
                    //https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_token-based_connection_to_apns
                    $assocToken        = array();
                    $assocToken['alg'] = 'ES256';       //The encryption algorithm you used to encrypt the token. APNs supports only the ES256 algorithm, so set the value of this key to ES256.
                    $assocToken['kid'] = '*******';  //The 10-character Key ID you obtained from your developer account
                    $assocToken['iss'] = '*******';  //The issuer key, the value for which is the 10-character Team ID you use for developing your company’s apps. Obtain this value from your developer account.
                    $assocToken['iat'] = time();  //The “issued at” time, whose value indicates the time at which this JSON token was generated. Specify the value as the number of seconds since Epoch, in UTC. The value must be no more than one hour from the current time.


                    $header = '{'
                            . ' "alg" : "'.$assocToken['alg'].'",'
                            . ' "kid" : "'.$assocToken['kid'].'"'
                            . '}';


                    $payload = '{'
                            . ' "iss" : "'.$assocToken['iss'].'",'
                            . ' "iat" : "'.$assocToken['iat'].'"'
                            . '}';                

                    $headerB64URL  = $this->base64url_encode($header);
                    $payloadB64URL = $this->base64url_encode($payload);               
                    $secret        = file_get_contents('files/cert/AuthKey_********.p8');

                    $signature = '';
                    openssl_sign($headerB64URL.'.'.$payloadB64URL, $signature, $secret, \OPENSSL_ALGO_SHA256);

                    $token = $headerB64URL.'.'.$payloadB64URL.'.'.$this->base64url_encode($signature);
                    
                    //save to use next time..                    
                    $fp = fopen($tokenTMP, 'w');
                    fwrite($fp, $token); 
                    fclose($fp);
                }
                               
        
                
                $apns_id = '8-4-4-5-12';
                
                
                // Create the payload body
                $encode= json_decode( $data['mdesc'],true) ;
                $message = $encode['message'];
                
        $body['aps'] = array(                        
            'sound' => 'default',   
            'alert' => array
                           (
                'title' => $data['mtitle'],
                            'body' => $message,
                            'mdesc' =>  $data['mdesc'] ?? array() 
                ),      
                        'mutable-content' => '1',
        );

        // Encode the payload as JSON
        $payloadData = json_encode($body);
                
                
                $curl = curl_init();
                curl_setopt_array($curl, array(
                CURLOPT_URL => $url . '/3/device/'.$devicetoken,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_ENCODING => "",
                CURLOPT_MAXREDIRS => 1,
                CURLOPT_TIMEOUT => 10,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, 
                CURLOPT_HTTPHEADER => array(
                "authorization: bearer ".$token,
              //  "apns-id: ".$apns_id, //
                "apns-push-type: $def",
                "apns-expiration: ". strtotime('+1 days ' .date('Y-m-d')),//ponawiaj przez 1 dzień..
                "apns-priority: 10",  //wyślij natychmiast..
                "apns-topic: ".$domain,
                  ),
                 CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,   
                 CURLOPT_POST => '1',   
                 CURLOPT_POSTFIELDS => $payloadData   
                 ));
                
        

                $response = curl_exec($curl);
                
                if(curl_errno($curl) == 0)
                {
                    return 'ret: '.$response;
                }else
                {
                    return 'err: '.curl_error($curl);
                }                                                                                                                   
    }
    
      
    
    
}

Upvotes: 1

CJ Ratliff
CJ Ratliff

Reputation: 333

If your curl call works, why not convert it to PHP

Example:

$url = "https://api.sandbox.push.apple.com/3/device/DEVICETOKEN";
$ch = curl_init($url);

$data = json_encode(["aps" => ["alert" => "Test"]]);

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // can be URL encoded string

$headers = array();
$headers[] = 'Apns-Topic: com.your.site';
$headers[] = 'Apns-Push-Type: ';
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($ch);
if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
}
curl_close($ch);

If you need to know how to use cert with CURL in PHP check this answer

Upvotes: 0

Related Questions