APNS バイナリインターフェイスを試す

新しいバイナリインターフェイスが推奨だということで試す。
こんな感じで送信する。

<?php
$o = new APNSUtility();
$o->set_certfile( "dev.pem" );
$o->apns_server_url( "ssl://gateway.sandbox.push.apple.com:2195" );
$o->set_priority( 10 );
$o->set_expire( time() );
$o->set_message( "message" );
$o->newsend( "__device_token__", "__user_identifer__" );
$o->newsend( "__device_token__", "__user_identifer__" );

$o->set_message( "change message" );
$o->newsend( "__device_token__", "__user_identifer__" );
$o->newsend( "__device_token__", "__user_identifer__" );

$o->disconnect();

適当にペタっと

<?php
class APNSUtility
{

    private $_certfile;
    private $_message;
    private $_priority;
    private $_apns_server;
    private $_debug = false;

    static private $_apns;

    public function set_certfile( $certfile )
    {
        $this->_certfile = $certfile;
    }

    public function apns_server_url( $apns_server ){
        $this->_apns_server = $apns_server;
    }

    public function set_debug(){
        $this->_debug = true;
    }

    public function set_message( $message )
    {
        $payload = json_encode(
            array(
                "aps" => array( "alert" => array( "body" => $message, "action-loc-key" => "start" ) )
            )
        );
        $this->_message = pack("C",2).pack("n", strlen($payload)).$payload;
    }


    public function set_expire( $value ){
        $timeout = pack('N', $value );
        $this->_expire = pack("C", 4).pack("n", 4).$timeout;
    }

    public function set_priority( $value ){
        $this->_priority = pack("C", 5).pack("n", 1).pack("C", $value);
    }

    public function newsend( $device_token, $identifer = null ){

        $frame_data  = pack("C", 1).pack("n", 32).pack("H*", $device_token );
        $frame_data .= $this->_message;;
        $frame_data .= $this->_priority;;
        if( $identifer !== null )
        {
            $frame_data .= pack("C", 3).pack("n", 4 ).pack("N", $identifer);
        }
        $send_data = pack("C",2).pack( "N", strlen( $frame_data )).$frame_data;
        $this->write_payload( $send_data );

        $this->print_error();
    }

    public function disconnect(){
        fclose( self::$_apns );
    }

    private function get_connection(){
        if( self::$_apns ){
            return self::$_apns;
        }
        $ctx = stream_context_create();  
        stream_context_set_option($ctx, 'ssl', 'local_cert',  $this->_certfile );
        $fp = stream_socket_client($this->_apns_server, $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);  
        if (!$fp) {
            return false;  
        }
        self::$_apns = $fp;
    }

    private function print_error( $delay = false )
    {
        if( $this->_debug ){
            sleep(2);
        }
        stream_set_blocking( self::$_apns, 0 );
        $error_byte = @fread( self::$_apns, 6 );
        if( strlen( $error_byte ) == 6 )
        {
            print var_export( unpack( "C", substr( $error_byte, 1, 1 ) ), 1);
            print var_export( unpack( "N", substr( $error_byte, 2    ) ), 1);
            self::$_apns = false;
        }
    }

    private function write_payload( $payload )
    {
        self::get_connection();

        for($written = 0; $written < strlen($payload); $written += $fwrite) {
            $fwrite = fwrite(self::$_apns, substr($payload, $written));
            if (!$fwrite) {
                return false;
            }
        }
        return true;
    }
}