再次深入研究苹果消息推送服务(APNS) 完善PHP版服务器端公共类

前段时间开发的一套APNS推送平台效率很差,通过再次深入研究苹果的消息推送服务,总结了不少经验。同时也参考了网上一些技术blog的博文,重新完善了此前写过的一个PHP类,代码如下:

<?php
/**
 * ApplePush 苹果消息推送公共类
 * @author www.sunbloger.com
 */
class ApplePush
{
    
    const STATUS_CODE_INTERNAL_ERROR = 999;
    const ERROR_RESPONSE_SIZE = 6;
    const ERROR_RESPONSE_COMMAND = 8;
    
    protected $_errorResponseMessages = array(
        0 => 'No errors encountered',
        1 => 'Processing error',
        2 => 'Missing device token',
        3 => 'Missing topic',
        4 => 'Missing payload',
        5 => 'Invalid token size',
        6 => 'Invalid topic size',
        7 => 'Invalid payload size',
        8 => 'Invalid token',
        self::STATUS_CODE_INTERNAL_ERROR => 'Internal error'
    );
    
    /**
     * APNS server url
     * 
     * @var string
     */
    protected $apns_url = 'ssl://gateway.push.apple.com:2195'; //沙盒地址:ssl://gateway.sandbox.push.apple.com:2195
    
    /**
     * 推送数据
     * 
     * @var string
     */
    private $payload_json;
    
    /**
     * 数据流对象
     * 
     * @var mixed
     */
    private $fp;
    
    /**
     * 设置APNS地址
     * 
     * @param string $url
     */
     
    public function setApnsUrl($url)
    {
        if (empty($url)) {
            return false;
        } else {
            $this->apns_url = $url;
        }
        return true;
    }
    
    /**
     * 设置推送的消息
     * 
     * @param string $body
     */
    public function setBody($body)
    {
        if (empty($body)) {
            return false;
        } else {
            $this->payload_json = json_encode($body);
        }
        return true;
    }
    
    /**
     * Open 打开APNS服务器连接
     * 
     * @param string $pem 证书
     * @param string $passphrase 证书密钥
     */
    public function open($pem, $passphrase)
    {
        if (empty($pem)) {
            return false;
        }
        if (empty($passphrase)) {
            return false;
        }
        $ctx = stream_context_create();
        stream_context_set_option($ctx, 'ssl', 'local_cert', $pem);
        stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
        $fp = stream_socket_client($this->apns_url, $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
        if (!$fp) {
            return false;
        }
        $this->fp = $fp;
        return true;
    }
    
    /**
     * Send 推送
     * 
     * @param string $token
     */
    public function send($token, $id)
    {
        $msg = pack('CNNnH*', 1, $id, 864000, 32, $token) . pack('n', strlen($this->payload_json)) . $this->payload_json;
        // Send it to the server
        $result = fwrite($this->fp, $msg, strlen($msg));
        return $result;
    }
    
    public function readErrMsg()
    {
        $errInfo = @fread($this->fp, self::ERROR_RESPONSE_SIZE);
        if ($errInfo === false || strlen($errInfo) != self::ERROR_RESPONSE_SIZE) {
            return true;
        }
        $errInfo = $this->parseErrMsg($errInfo);
        if (!is_array($errInfo) || empty($errInfo)) {
            return true;
        }
        if (!isset($errInfo['command'], $errInfo['statusCode'], $errInfo['identifier'])) {
            return true;
        }
        if ($errInfo['command'] != self::ERROR_RESPONSE_COMMAND) {
            return true;
        }
        $errInfo['timeline'] = time();
        $errInfo['statusMessage'] = 'None (unknown)';
        $errInfo['errorIdentifier'] = $errInfo['identifier'];
        if (isset($this->_aErrorResponseMessages[$errInfo['statusCode']])) {
            $errInfo['statusMessage'] = $this->_errorResponseMessages[$errInfo['statusCode']];
        }
        return $errInfo;
    }

    protected function parseErrMsg($errorMessage)
    {
        return unpack('Ccommand/CstatusCode/Nidentifier', $errorMessage);
    }
    
    /**
     * Close APNS server 关闭APNS服务器连接
     * 
     */
    public function close()
    {
        // Close the connection to the server
        fclose($this->fp);
        return true;
    }
}
?>

阳光部落原创,更多内容请访问http://www.sunbloger.com/

相关内容:

发表评论