immobiliare / ApnsPHP

ApnsPHP: Apple Push Notification & Feedback Provider
BSD 3-Clause "New" or "Revised" License
1.43k stars 449 forks source link

Support for HTTP/2 #113

Closed Playcorp closed 8 years ago

Playcorp commented 8 years ago

Hi,

Can you update ApnsPHP with HTTP/2 connexion ? https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html

Thanks !

gpdawson commented 8 years ago

+1 ! Would be very nice to have the newer, simpler system. Of course its a big task - perhaps requires a new repo altogether.

longxibendi commented 8 years ago

+1 ! thanks

javiermarinros commented 8 years ago

I hope this helps, I haven't be able to test it yet (there is no support for HTTP/2 in Google App Engine yet)

<?php

/**
 * Apple Push Notification Service implementation
 *
 * @see https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/APNsProviderAPI.html#//apple_ref/doc/uid/TP40008194-CH101-SW1
 */
class PushNotification_Service_APNS2 extends PushNotification_Service_Base
{
    const PAYLOAD_MAXIMUM_SIZE = 2048;
    const NOTIFICATION_TTL_MS = 5000;

    private static $_urls = [
        'https://api.development.push.apple.com:443',
        'https://api.push.apple.com:443',
    ];

    /**
     * @var GuzzleHttp\Client
     */
    private $_client;
    private $_notification;

    public function __construct($certificate, $passphrase = null, $guzzle_settings = [])
    {
        $this->id = 'apns';

        defined('CURL_HTTP_VERSION_2_0') || define('CURL_HTTP_VERSION_2_0', 3);

        $this->_client = new GuzzleHttp\Client(
            $guzzle_settings + [
                GuzzleHttp\RequestOptions::SYNCHRONOUS => true,
                GuzzleHttp\RequestOptions::CERT        => [$certificate, $passphrase],
                'curl'                                 => [
                    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
                ],
            ]
        );
    }

    /**
     * @inheritdoc
     */
    public function prepare($notification)
    {
        $this->_notification = $notification;
    }

    /**
     * @inheritdoc
     */
    public function prepare_message($message, $data = [])
    {
        $this->prepare(
            array_merge_recursive(
                [
                    'aps' => [
                        'alert' => $message,
                        'sound' => 'default'
                    ]
                ],
                $data
            )
        );
    }

    /**
     * @inheritdoc
     */
    public function send($to, $extra = [])
    {
        $body = $this->_notification;

        if (!empty($extra)) {
            $body = $extra + $body;
        }

        if (is_array($to) || $to instanceof Traversable) {
            foreach ($to as $t) {
                $this->_send($t, $body);
            }
        } else {
            $this->_send($to, $body);
        }
    }

    private function _send($token, $body)
    {
        $url = self::$_urls[$this->sandbox ? 0 : 1];

        $response = $this->_client->post(
            $url . '/3/device/' . $token,
            [

                GuzzleHttp\RequestOptions::JSON => $body,
            ]
        );

        $code = $response->getStatusCode();

        if ($code == 200) {
            return true;
        } elseif ($code == 410) {//The device token is no longer active for the topic.
            $this->_on(self::ERROR_INVALID_TOKEN, $token);
            return false;
        }

        //Generar error
        $statuses = [
            200 => 'Success',
            400 => 'Bad request',
            403 => 'There was an error with the certificate.',
            405 => 'The request used a bad :method value. Only POST requests are supported.',
            410 => 'The device token is no longer active for the topic.',
            413 => 'The notification payload was too large.',
            429 => 'The server received too many requests for the same device token.',
            500 => 'Internal server error',
            503 => 'The server is shutting down and unavailable.'
        ];

        if (isset($statuses[$code])) {
            $message = "APNS Error: " . $statuses[$code];
        } else {
            $message = 'Unknown APNS error';
        }

        throw new PushNotification_Exception(
            $message, [
                'to'       => $token,
                'body'     => $body,
                'response' => $response->getBody()->getContents(),
            ]
        );
    }
}
duccio commented 8 years ago

Please, checkout branch 'http2' for the first implementation of the HTTP/2 Protocol.