14

Apple has updated their push notification service and the certificate file received is now a .p8 file. There are many examples online of how to send a push notification with the .pem file but I can't find anything for a .p8 file. Does anyone have any code that works with the .p8 file?

Cam Connor
  • 1,231
  • 2
  • 25
  • 40

3 Answers3

18

With the script below I'm able to send token-based push notifications with the .p8 file.

The minimum version of curl supporting this is 7.38.0, and it must be compiled with the flag --with-nghttp2 and openssl >= 1.0.2

<?php

  $keyfile = 'AuthKey_AABBCC1234.p8';               # <- Your AuthKey file
  $keyid = 'AABBCC1234';                            # <- Your Key ID
  $teamid = 'AB12CD34EF';                           # <- Your Team ID (see Developer Portal)
  $bundleid = 'com.company.YourApp';                # <- Your Bundle ID
  $url = 'https://api.development.push.apple.com';  # <- development url, or use http://api.push.apple.com for production environment
  $token = 'e2c48ed32ef9b018........';              # <- Device Token

  $message = '{"aps":{"alert":"Hi there!","sound":"default"}}';

  $key = openssl_pkey_get_private('file://'.$keyfile);

  $header = ['alg'=>'ES256','kid'=>$keyid];
  $claims = ['iss'=>$teamid,'iat'=>time()];

  $header_encoded = base64($header);
  $claims_encoded = base64($claims);

  $signature = '';
  openssl_sign($header_encoded . '.' . $claims_encoded, $signature, $key, 'sha256');
  $jwt = $header_encoded . '.' . $claims_encoded . '.' . base64_encode($signature);

  // only needed for PHP prior to 5.5.24
  if (!defined('CURL_HTTP_VERSION_2_0')) {
      define('CURL_HTTP_VERSION_2_0', 3);
  }

  $http2ch = curl_init();
  curl_setopt_array($http2ch, array(
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
    CURLOPT_URL => "$url/3/device/$token",
    CURLOPT_PORT => 443,
    CURLOPT_HTTPHEADER => array(
      "apns-topic: {$bundleid}",
      "authorization: bearer $jwt"
    ),
    CURLOPT_POST => TRUE,
    CURLOPT_POSTFIELDS => $message,
    CURLOPT_RETURNTRANSFER => TRUE,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HEADER => 1
  ));

  $result = curl_exec($http2ch);
  if ($result === FALSE) {
    throw new Exception("Curl failed: ".curl_error($http2ch));
  }

  $status = curl_getinfo($http2ch, CURLINFO_HTTP_CODE);
  echo $status;

  function base64($data) {
    return rtrim(strtr(base64_encode(json_encode($data)), '+/', '-_'), '=');
  }

?>
Roel Koops
  • 840
  • 2
  • 16
  • 28
  • 2
    I'm getting an error as 'Unexpected HTTP/1.x request: POST /3/device/5cba9501b6b6b3d6xxxxxxxxxxxxx'. Can you suggest a solution? – Hareesh Jan 04 '18 at 09:23
  • Can you try to restart the webserver as suggested in this answer: https://stackoverflow.com/a/48007808/1833495 ? – Roel Koops Jan 04 '18 at 11:19
  • 1
    I was getting this error when i tried to run the above code ' Curl failed: No URL set!' even though am passing the url. so i just replaced the `curl_setopt_array` to `curl_setopt` and it worked for me. – Sawood Jan 19 '19 at 09:52
  • @Hareesh I managed to solve this issue, see here: https://stackoverflow.com/a/55147621/3210941 – AndyW Mar 13 '19 at 17:10
  • @RoelKoops Could you tell me how we can generate apple developer token for musickit apis – Ashish Chaturvedi Jun 18 '19 at 12:36
  • @RoelKoops what should we pass in $signature parameter? – Jay Sojitra Dec 18 '19 at 13:03
  • 1
    @JaySojitra: You don't have to fill $signature yourself. This will be done by openssl_sign when the call is succesfull, see https://www.php.net/manual/en/function.openssl-sign.php – Roel Koops Dec 18 '19 at 14:44
  • I only have access to curl version 7.29.0. Is there any way to run this with this version? – Chris Jul 12 '20 at 18:18
  • @Chris: I don't think so, curl 7.29.0 is missing HTTP/2 support – Roel Koops Aug 03 '20 at 08:50
2

I also struggled to find a simple library to send APNS notifications with a .p8 file in PHP. I found the edamov/pushok library to be the most straightforward and object-oriented. Just install the package with composer require edamov/pushok and follow the instructions in Getting Started.

craastad
  • 6,222
  • 5
  • 32
  • 46
1

I have been trying to send push notification with new JWT based push notification service using PHP. Its was definitely not a easy task.

I have uploaded project on GitHub. You can download from there and make sure you replace your .p8 file with existing .p8 file.

Then in push.php file you need to replace your kid, iss(Team ID), token and app_bundle_id.

Go to the directory and from terminal run the command php push.php. If everything goes well then you should receive push notification.

This solution works well for me. Just make sure that you don't get any errors in terminal.

I hope this helps.

Jay
  • 106
  • 6