iOS推送服务端实现

2017-12-02  本文已影响116人  修_远

推送服务端代码PHP,如果使用中出现问题,建议找PHP的同学一起阅读
使用终端命令$ php 路径/push.php就可以执行下面的代码了。
还需要一个ROOT证书entrust_2048_ca.cer,这个是在网上下的,具体链接找不到了,可以自己在网上搜下

<?php  
    class APNS  
    {  
        const ENVIRONMENT_PRODUCTION = 0;  
        const ENVIRONMENT_SANDBOX = 1;  
        const DEVICE_BINARY_SIZE = 32;  
        const CONNECT_RETRY_INTERVAL = 1000000;  
        const SOCKET_SELECT_TIMEOUT = 1000000;  
        const COMMAND_PUSH = 1;  
        const STATUS_CODE_INTERNAL_ERROR = 999;  
        const ERROR_RESPONSE_SIZE = 6;  
        const ERROR_RESPONSE_COMMAND = 8;  
        const PAYLOAD_MAXIMUM_SIZE = 256;  
        const APPLE_RESERVED_NAMESPACE = 'aps';  
        protected $_environment;  
        protected $_providerCertificateFile;
        protected $_passphrase;  
        protected $_rootCertificationAuthorityFile;  
        protected $_connectTimeout;  
        protected $_connectRetryTimes = 3;  
        protected $_connectRetryInterval;  
        protected $_socketSelectTimeout;  
        protected $_hSocket;  
        protected $_deviceTokens = array();  
        protected $_text;  
        protected $_badge;  
        protected $_sound;  
        protected $_customProperties;  
        protected $_expiryValue = 604800;  
        protected $_customIdentifier;  
        protected $_autoAdjustLongPayload = true;  
        protected $asurls = array('ssl://gateway.push.apple.com:2195','ssl://gateway.sandbox.push.apple.com:2195');  
        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'  
                            );  
          
        function __construct($environment,$providerCertificateFile)  
        {  
            if($environment != self::ENVIRONMENT_PRODUCTION && $environment != self::ENVIRONMENT_SANDBOX)   
            {  
                throw new Exception(  
                    "Invalid environment '{$environment}'"  
                );  
            }  
            $this->_environment = $environment;  
  
            if(!is_readable($providerCertificateFile))   
            {  
                throw new Exception(  
                    "Unable to read certificate file '{$providerCertificateFile}'"  
                );  
            }  
            $this->_providerCertificateFile = $providerCertificateFile;  
  
            $this->_connectTimeout = @ini_get("default_socket_timeout");  
            $this->_connectRetryInterval = self::CONNECT_RETRY_INTERVAL;  
            $this->_socketSelectTimeout = self::SOCKET_SELECT_TIMEOUT;  
        }  
  
        public function setRCA($rootCertificationAuthorityFile)  
        {  
            if(!is_readable($rootCertificationAuthorityFile))   
            {  
                throw new Exception(  
                    "Unable to read Certificate Authority file '{$rootCertificationAuthorityFile}'"  
                );  
            }  
            $this->_rootCertificationAuthorityFile = $rootCertificationAuthorityFile;  
        }  
  
        public function setPassphrase($passphrase)
        {
            $this->_passphrase = $passphrase;
        }

        public function getRCA()  
        {  
            return $this->_rootCertificationAuthorityFile;  
        }  
  
        protected function _connect()  
        {  
            $sURL = $this->asurls[$this->_environment];  
            $streamContext = stream_context_create(  
                array  
                    (  
                        'ssl' => array  
                        (  
                            'verify_peer' => isset($this->_rootCertificationAuthorityFile),  
                            'cafile' => $this->_rootCertificationAuthorityFile,  
                            'local_cert' => $this->_providerCertificateFile,
                            'passphrase' => $this->_passphrase
                        )  
                    )  
                );  
  
            $this->_hSocket = @stream_socket_client($sURL,$nError,$sError,$this->_connectTimeout,STREAM_CLIENT_CONNECT, $streamContext);  
  
            if (!$this->_hSocket)   
            {  
                throw new Exception  
                (  
                    "Unable to connect to '{$sURL}': {$sError} ({$nError})"  
                );  
            }  
            stream_set_blocking($this->_hSocket, 0);  
            stream_set_write_buffer($this->_hSocket, 0);  
            return true;  
        }  
  
        public function connect()  
        {  
            $bConnected = false;  
            $retry = 0;  
            while(!$bConnected)   
            {  
                try   
                {  
                    $bConnected = $this->_connect();  
                }catch (Exception $e)   
                {  
                    if ($nRetry >= $this->_connectRetryTimes)   
                    {  
                        throw $e;  
                    }else   
                    {  
                        usleep($this->_nConnectRetryInterval);  
                    }  
                }  
                $retry++;  
            }  
        }  
  
        public function disconnect()  
        {  
            if (is_resource($this->_hSocket))   
            {  
                return fclose($this->_hSocket);  
            }  
            return false;  
        }  
  
        protected function getBinaryNotification($deviceToken, $payload, $messageID = 0, $Expire = 604800)  
        {  
            $tokenLength = strlen($deviceToken);  
            $payloadLength = strlen($payload);  
  
            $ret  = pack('CNNnH*', self::COMMAND_PUSH, $messageID, $Expire > 0 ? time() + $Expire : 0, self::DEVICE_BINARY_SIZE, $deviceToken);  
            $ret .= pack('n', $payloadLength);  
            $ret .= $payload;  
            return $ret;  
        }  
  
        protected function readErrorMessage()  
        {  
            $errorResponse = @fread($this->_hSocket, self::ERROR_RESPONSE_SIZE);  
            if ($errorResponse === false || strlen($errorResponse) != self::ERROR_RESPONSE_SIZE)   
            {  
                return;  
            }  
            $errorResponse = $this->parseErrorMessage($errorResponse);  
            if (!is_array($errorResponse) || empty($errorResponse))   
            {  
                return;  
            }  
            if (!isset($errorResponse['command'], $errorResponse['statusCode'], $errorResponse['identifier']))   
            {  
                return;  
            }  
            if ($errorResponse['command'] != self::ERROR_RESPONSE_COMMAND)   
            {  
                return;  
            }  
            $errorResponse['timeline'] = time();  
            $errorResponse['statusMessage'] = 'None (unknown)';  
            if (isset($this->_aErrorResponseMessages[$errorResponse['statusCode']]))   
            {  
                $errorResponse['statusMessage'] = $this->_errorResponseMessages[$errorResponse['statusCode']];  
            }  
            return $errorResponse;  
        }  
  
        protected function parseErrorMessage($errorMessage)  
        {  
            return unpack('Ccommand/CstatusCode/Nidentifier', $errorMessage);  
        }  
  
        public function send()  
        {  
            if (!$this->_hSocket)   
            {  
                throw new Exception  
                (  
                    'Not connected to Push Notification Service'  
                );  
            }  
            $sendCount = $this->getDTNumber();  
            $messagePayload = $this->getPayload();  
            foreach($this->_deviceTokens AS $key => $value)  
            {  
                $apnsMessage = $this->getBinaryNotification($value, $messagePayload, $messageID = 0, $Expire = 604800);  
                $nLen = strlen($apnsMessage);  
                $aErrorMessage = null;  
                if ($nLen !== ($nWritten = (int)@fwrite($this->_hSocket, $apnsMessage)))   
                {  
                    $aErrorMessage = array  
                    (  
                        'identifier' => $key,  
                        'statusCode' => self::STATUS_CODE_INTERNAL_ERROR,  
                        'statusMessage' => sprintf('%s (%d bytes written instead of %d bytes)',$this->_errorResponseMessages[self::STATUS_CODE_INTERNAL_ERROR], $nWritten, $nLen)  
                    );  
                }  
            }  
        }  
  
  
        public function addDT($deviceToken)  
        {  
            if (!preg_match('~^[a-f0-9]{64}$~i', $deviceToken))   
            {  
                throw new Exception  
                (  
                    "Invalid device token '{$deviceToken}'"  
                );  
            }  
            $this->_deviceTokens[] = $deviceToken;  
        }         
          
        public function getDTNumber()  
        {  
            return count($this->_deviceTokens);  
        }  
  
        public function setText($text)  
        {  
            $this->_text = $text;  
        }  
  
        public function getText()  
        {  
            return $this->_text;  
        }  
  
        public function setBadge($badge)  
        {  
            if (!is_int($badge))   
            {  
                throw new Exception  
                (  
                    "Invalid badge number '{$badge}'"  
                );  
            }  
            $this->_badge = $badge;  
        }  
  
        public function getBadge()  
        {  
            return $this->_badge;  
        }  
  
        public function setSound($sound = 'default')  
        {  
            $this->_sound = $sound;  
        }  
  
        public function getSound()  
        {  
            return $this->_sound;  
        }  
  
        public function setCP($name, $value)  
        {  
            if ($name == self::APPLE_RESERVED_NAMESPACE)   
            {  
                throw new Exception  
                (  
                    "Property name '" . self::APPLE_RESERVED_NAMESPACE . "' can not be used for custom property."  
                );  
            }  
            $this->_customProperties[trim($name)] = $value;  
        }  
  
        protected function _getPayload()  
        {  
            $aPayload[self::APPLE_RESERVED_NAMESPACE] = array();  
  
            if (isset($this->_text))   
            {  
                $aPayload[self::APPLE_RESERVED_NAMESPACE]['alert'] = (string)$this->_text;  
            }  
            if (isset($this->_badge) && $this->_badge > 0)   
            {  
                $aPayload[self::APPLE_RESERVED_NAMESPACE]['badge'] = (int)$this->_badge;  
            }  
            if (isset($this->_sound))   
            {  
                $aPayload[self::APPLE_RESERVED_NAMESPACE]['sound'] = (string)$this->_sound;  
            }  
  
            if (is_array($this->_customProperties))   
            {  
                foreach($this->_customProperties as $propertyName => $propertyValue)   
                {  
                    $aPayload[$propertyName] = $propertyValue;  
                }  
            }  
            return $aPayload;  
        }  
  
        public function setExpiry($expiryValue)  
        {  
            if (!is_int($expiryValue))   
            {  
                throw new Exception  
                (  
                    "Invalid seconds number '{$expiryValue}'"  
                );  
            }  
            $this->_expiryValue = $expiryValue;  
        }  
  
        public function getExpiry()  
        {  
            return $this->_expiryValue;  
        }  
  
        public function setCustomIdentifier($customIdentifier)  
        {  
            $this->_customIdentifier = $customIdentifier;  
        }  
  
        public function getCustomIdentifier()  
        {  
            return $this->_customIdentifier;  
        }         
  
        public function getPayload()  
        {  
            $sJSONPayload = str_replace  
            (  
                '"' . self::APPLE_RESERVED_NAMESPACE . '":[]',  
                '"' . self::APPLE_RESERVED_NAMESPACE . '":{}',  
                json_encode($this->_getPayload())  
            );  
            $nJSONPayloadLen = strlen($sJSONPayload);  
  
            if ($nJSONPayloadLen > self::PAYLOAD_MAXIMUM_SIZE)  
            {  
                if ($this->_autoAdjustLongPayload)   
                {  
                    $maxTextLen = $textLen = strlen($this->_text) - ($nJSONPayloadLen - self::PAYLOAD_MAXIMUM_SIZE);  
                    if ($nMaxTextLen > 0)  
                    {  
                        while (strlen($this->_text = mb_substr($this->_text, 0, --$textLen, 'UTF-8')) > $maxTextLen);  
                        return $this->getPayload();  
                    }else  
                    {  
                        throw new Exception  
                        (  
                            "JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is " .  
                            self::PAYLOAD_MAXIMUM_SIZE . " bytes. The message text can not be auto-adjusted."  
                        );  
                    }  
                }else  
                {  
                    throw new Exception  
                    (  
                        "JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is " .  
                        self::PAYLOAD_MAXIMUM_SIZE . " bytes"  
                    );  
                }  
            }  
            return $sJSONPayload;  
        }     
    }  
  
?>  
<?php  
date_default_timezone_set('PRC');  
echo "we are young,test apns.  -".date('Y-m-d h:i:s',time());  
  
$rootpath = 'entrust_2048_ca.cer';  //ROOT证书地址  
$cp = 'voip_ck.pem';  //provider证书地址  
// $cp = 'push_key_dis.pem';  //provider证书地址  
$apns = new APNS(0,$cp);  //设置推送环境
try  
{  
    $apns->setPassphrase('123456');//设置证书密码
    $apns->setRCA($rootpath);  //设置ROOT证书  
    $apns->connect(); //连接  
    $apns->addDT('1234562ec1fa73e3db8825258ea8ee6570da43eda86b31fbf7a4eb396b95c7a3');  //区分APNS 和 VoIP加入deviceToken  
    $apns->setText('这是一条测试信息');  //发送内容  
    $apns->setBadge(1);  //设置图标数  
    $apns->setSound();  //设置声音  
    $apns->setExpiry(3600);  //过期时间  
    // $apns->setCP('custom operation',array('type' => '1','url' => 'http://www.google.com.hk'));  //自定义操作  
    $apns->send();  //发送  
    echo ' sent ok';  
}catch(Exception $e)  
{  
    echo $e;  
}  
?>  
上一篇下一篇

猜你喜欢

热点阅读