最近公司push推送升級,用蘋果http2進行推送,http2的好處就不說了,這些網上均可以查到,可是真正在項目中用的,用php寫的仍是特別少,所以,寫出來跟你們分享,廢話不說了,直接上代碼:php
pushMessage.phpjson
<?phpapi
class PushMessage {
//發送apns server時發送消息的鍵
const APPLE_RESERVED_NAMESPACE = 'aps';數組
/*
* 鏈接apns地址
* 'https://api.push.apple.com:443/3/device/', // 生產環境
* 'https://api.development.push.apple.com:443/3/device/' // 沙盒環境
*
**/
private $_appleServiceUrl;
//證書
private $_sProviderCertificateFile;
//要發送到的device token
private $_deviceTokens = array();
//額外要發送的內容
private $_customProperties;
//私鑰密碼
private $_passPhrase;
//要推送的文字消息
private $_pushMessage;
//要推送的語音消息
private $_pushSoundMessage;
//設置角標
private $_nBadge;
//發送的頭部信息
private $_headers = array();
private $_errors;
//推送的超時時間,若是超過了這個時間,就自動不推送了,單位爲秒
private $_expiration;
//apple 惟一標識
private $_apns_topic;
//10:當即接收,5:屏幕關閉,在省電時纔會接收到的。若是是屏幕亮着,是不會接收到消息的。並且這種消息是沒有聲音提示的
private $_priority;
//cURL容許執行的最長秒數
private $_timeout;
//curl單鏈接
private $_hSocket;
//curl多鏈接
private $_multi_hSocket;
/**< @type integer Status code for internal error (not Apple). */
const STATUS_CODE_INTERNAL_ERROR = 999;app
const ERROR_WRITE_TOKEN = 1000;
//apple server 返回的錯誤信息
protected $_aErrorResponseMessages = array(
200 => 'Sussess',
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',
self::STATUS_CODE_INTERNAL_ERROR => 'Internal error',
self::ERROR_WRITE_TOKEN => 'Writing token error',
);curl
public function __construct() {}socket
/*
* 鏈接apple server
* @params certificate_file 證書
* @params pass_phrase 私鑰密碼
* @params apple_service_url 要發送的apple apns service
* @params expiration 推送的超時時間,若是超過了這個時間,就自動不推送了,單位爲秒
* @params apns-topic apple標識
**/
public function connServer($params) {
if (empty($params['certificate_file'])) {
return false;
}
$this->_sProviderCertificateFile = $params['certificate_file'];
$this->_appleServiceUrl = $params['apple_service_url'];
$this->_passPhrase = $params['pass_phrase'];
$this->_apns_topic = $params['apns-topic'];
$this->_expiration = $params['expiration'];
$this->_priority = $params['priority'];
$this->_timeout = $params['timeout'];ide
$this->_headers = array(
'apns-topic:'. $params['apns-topic'],
'apns-priority'. $params['priority'],
'apns-expiration'. $params['expiration']
);
$this->_multi_hSocket = curl_multi_init();
if (!$this->_multi_hSocket) {
$this->_errors['connServer']['cert'] = $this->_sProviderCertificateFile;
$this->_errors['connServer']['desc'] = "Unable to connect to '{$this->_appleServiceUrl}': $this->_multi_hSocket";
$this->_errors['connServer']['nums'] = isset($this->_errors['connServer']['nums']) ? intval($this->_errors['connServer']['nums']) : 0;
$this->_errors['connServer']['nums'] += 1;this
return false;
}url
return $this->_multi_hSocket;
}
/*
* 斷連
*
**/
public function disconnect() {
if (is_resource($this->_multi_hSocket)) {
curl_multi_close($this->_multi_hSocket);
}
if (!empty($this->_hSocket)) {
foreach ($this->_hSocket as $val) {
if (is_resource($val)) {
curl_close($val);
}
}
$this->_hSocket = array();
return true;
}
return false;
}
//設置發送文字消息
public function setMessage($message) {
$this->_pushMessage = $message;
}
//設置發送語音消息
public function setSound($sound_message = 'default') {
$this->_pushSoundMessage = $sound_message;
}
//獲取要發送的文字消息
public function getMessage() {
if (!empty($this->_pushMessage)) {
return $this->_pushMessage;
}
return '';
}
//獲取語音消息
public function getSoundMessage() {
if (!empty($this->_pushSoundMessage)) {
return $this->_pushSoundMessage;
}
return '';
}
/*
* 接收device token 能夠是數組,也能夠是單個字符串
*
**/
public function addDeviceToken($device_token) {
if (is_array($device_token) && !empty($device_token)) {
$this->_deviceTokens = $device_token;
} else {
$this->_deviceTokens[] = $device_token;
}
}
//返回要獲取的device token
public function getDeviceToken($key = '') {
if ($key !== '') {
return isset($this->_deviceTokens[$key]) ? $this->_deviceTokens[$key] : array();
}
return $this->_deviceTokens;
}
//設置角標
public function setBadge($nBadge) {
$this->_nBadge = intval($nBadge);
}
//獲取角標
public function getBadge() {
return $this->_nBadge;
}
/*
* 用來設置額外的消息
* @params custom_params array $name 不能和 self::APPLE_RESERVED_NAMESPACE('aps')樣,
*
**/
public function setCustomProperty($custom_params) {
foreach ($custom_params as $name=>$value) {
if (trim($name) == self::APPLE_RESERVED_NAMESPACE) {
$this->_errors['setCustomProperty'][] = $name.'設置不成功,'.$name.'不能夠設置成 aps.';
}
$this->_customProperties[trim($name)] = $value;
}
}
/*
* 用來獲取額外設置的值
* @params string $name
*
**/
public function getCustomProperty($name = '') {
if ($name !== '') {
return isset($this->_customProperties[trim($name)]) ? $this->_customProperties[trim($name)] : '';
}
return $this->_customProperties;
}
/**
* 組織發送的消息
*
*/
protected function getPayload() {
$aPayload[self::APPLE_RESERVED_NAMESPACE] = array();
if (isset($this->_pushMessage)) {
$aPayload[self::APPLE_RESERVED_NAMESPACE]['alert'] = $this->_pushMessage;
}
if (isset($this->_pushSoundMessage)) {
$aPayload[self::APPLE_RESERVED_NAMESPACE]['sound'] = (string)$this->_pushSoundMessage;
}
if (isset($this->_nBadge)) {
$aPayload[self::APPLE_RESERVED_NAMESPACE]['badge'] = (int)$this->_nBadge;
}
if (is_array($this->_customProperties) && !empty($this->_customProperties)) {
foreach($this->_customProperties as $sPropertyName => $mPropertyValue) {
$aPayload[$sPropertyName] = $mPropertyValue;
}
}
return json_encode($aPayload);
}
/*
* 推送消息
*
**/
public function send() {
if (empty($this->_multi_hSocket)) {
return false;
}
if (isset($this->_errors['connServer'])) {
unset($this->_errors['connServer']);
}
if (empty($this->_deviceTokens)) {
$this->_errors['send']['not_deviceTokens']['desc'] = 'No device tokens';
$this->_errors['send']['not_deviceTokens']['time'] = date("Y-m-d H:i:s",time());
return false;
}
if (empty($this->getPayload())) {
$this->_errors['send']['not_message']['desc'] = 'No message to push';
$this->_errors['send']['not_message']['time'] = date("Y-m-d H:i:s",time());
return false;
}
$hArr = array();
foreach ($this->_deviceTokens as $key=>$token) {
$sendMessage = $this->getPayload();
$this->_hSocket[$key] = curl_init();
if (!defined(CURL_HTTP_VERSION_2_0)) {
define(CURL_HTTP_VERSION_2_0, 3);
}
curl_setopt($this->_hSocket[$key], CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
curl_setopt($this->_hSocket[$key], CURLOPT_SSLCERT, $this->_sProviderCertificateFile);
curl_setopt($this->_hSocket[$key], CURLOPT_SSLCERTPASSWD, $this->_passPhrase);
curl_setopt($this->_hSocket[$key], CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($this->_hSocket[$key], CURLOPT_TIMEOUT, $this->_timeout);
curl_setopt($this->_hSocket[$key], CURLOPT_URL, $this->_appleServiceUrl . $token);
curl_setopt($this->_hSocket[$key], CURLOPT_POSTFIELDS, $sendMessage);
curl_setopt($this->_hSocket[$key], CURLOPT_HTTPHEADER, $this->_headers);
curl_setopt($this->_hSocket[$key], CURLOPT_RETURNTRANSFER, 1);
if (!$this->_hSocket[$key]) {
$this->_errors['send']['cert'] = $this->_sProviderCertificateFile;
$this->_errors['send']['desc'][$key] = "Unable to connect to '{$this->_appleServiceUrl}': $this->_hSocket[$key]";
} else {
array_push($hArr, $this->_hSocket[$key]);
curl_multi_add_handle($this->_multi_hSocket,$this->_hSocket[$key]);
}
}
if (empty($hArr)) {
$this->_errors['send']['hSocket'] = "all socket link faild";
$this->_errors['send']['time'] = date("Y-m-d H:i:s", time());
return false;
}
$running = null;
do {
curl_multi_exec($this->_multi_hSocket, $running);
} while ($running > 0);
foreach ($hArr as $h) {
$info = curl_getinfo($h);
$response_errors = curl_multi_getcontent($h);
if ($info['http_code'] !== 200) {
$device_token = explode('/',$info['url']);
$this->_writeErrorMessage(json_decode($response_errors, true), $info['http_code'], array_pop($device_token));
}
curl_multi_remove_handle($this->_multi_hSocket, $h);
}
$this->_deviceTokens = array();
return true;
}
//獲取發送過程當中的錯誤
public function getError() {
return $this->_errors;
}
/*
* 讀取錯誤信息
*@params res_errors 發送失敗的具體信息
*@params res_code 響應頭返回的錯誤code
*@params token 發送失敗的device token
**/
protected function _writeErrorMessage($res_errors, $res_code, $token) {
$errors = array(
'reason' => $res_errors,
'response_code' => $res_code,
'token' => $token,
'time' => date("Y-m-d H:i:s",time())
);
if (isset($this->_aErrorResponseMessages[$res_code])) {
$errors['msg'] = $this->_aErrorResponseMessages[$res_code];
}
$this->_errors['send']['response'][] = $errors;
$this->disconnect();
sleep(0.5);
$this->_resConnect();
}
//從新鏈接
protected function _resConnect() {
$conn_res = $this->connServer(array(
'certificate_file' => $this->_sProviderCertificateFile,
'apple_service_url' => $this->_appleServiceUrl,
'pass_phrase' => $this->_passPhrase,
'priority' => $this->_priority,
'apns-topic' => $this->_apns_topic,
'expiration' => $this->_expiration,
'timeout' => $this->_timeout
));
if (!$conn_res) {
$this->_errors['connServer']['res_conn_nums'] = isset($this->_errors['connServer']['res_conn_nums']) ? intval($this->_errors['connServer']['res_conn_nums']) : 0;
$this->_errors['connServer']['res_conn_nums'] += 1;
if ($this->_errors['connServer']['res_conn_nums'] >=5) {
return false;
}
return $this->_resConnect();
}
if (isset($this->_errors['connServer'])) {
unset($this->_errors['connServer']);
}
return true;
}
}
使用:
include "pushMessage.php";
$obj = new PushMessage();
$params = array(
'certificate_file' =>證書路徑 ,// .pem 文件
'apple_service_url' => // 生產環境: 'https://api.push.apple.com:443/3/device/' 沙盒環境 'https://api.development.push.apple.com:443/3/device/'
'pass_phrase' => //這個是證書的私鑰密碼
'apns-topic' => //apple惟一標識,這個不是隨便的字符串,應該是申請蘋果推送的時候有的吧,具體不清楚,這個要問負責人
'expiration' =>0, //推送的超時時間,若是超過了這個時間,就自動不推送了,單位爲秒, 通常默認爲0
'priority' => 10,//10:當即接收,5:屏幕關閉,在省電時纔會接收到的。若是是屏幕亮着,是不會接收到消息的。並且這種消息是沒有聲音提示的,通常爲10
'timeout' => 30,//curl超時時間,單位爲秒
);
//設置發送的文字仍是聲音或者角標什麼的按本身的需求調用
$obj->connServer($params);
$obj->setMessage = "要發送的文字";
$obj->setSound = "要發送的聲音";
$obj->addDeviceToken= array();//或者單個的device token, 要發送到的apple token
$obj->setBadge = 1;//設置角標
$obj->setCustomProperty = array('a'=>'b');//其餘額外發送的參數
$obj->getPayload(); //組織發送
$obj->send();//發送
$obj->getError();//獲取發送過程當中的錯誤
$obj->disconnect();//斷連
注意:轉載請註明出處,謝謝!