百度云推送,地址:http://push.baidu.com/,优点挺多,大平台,稳定灵活,安全,免费,应用广。
最近的公司项目需要后端给移动端发送通知,第一次接触这种需求,同事推荐我了解下个推,后来又推荐了百度云,比较起来选择了百度云。
于是在官方SDK中心下载了 php服务端SDK,地址:http://push.baidu.com/sdk/push_server_sdk_for_php。
起初看着SDK一头雾水,结构比较复杂,后来发现最终程序使用了通用的curl请求方式,想想推送模块可以单独一块,也可以封装。
因为项目使用的thinkphp框架,在基本熟悉SDK后,有了把几个类型接口封装到框架一个模型里的想法。
模型代码如下:
1 class BdPushModel extends Model { 2 const TAG_TYPE_LBS_LABEL = 2; // LBS 推送 3 const TAG_TYPE_INTEREST_LABEL = 3; // 兴趣组 4 const TAG_TYPE_AGE_LABEL = 4; // 年龄组 5 const TAG_TYPE_SEX_LABEL = 5; // 性别组 6 const TAG_TYPE_OP_LABEL = 6; // 组合运算 7 8 9 public $apikey = "Vek7uG4nhplvh3cpg2H5Ut50";//测试用 10 public $secret_key = "NdxoxNykVrH6qA3CV33kzK7lsSTTvZA9";//测试用 11 public $restHostUrl = 'http://api.tuisong.baidu.com/rest/3.0/'; 12 /*$timestamp : 用户发起请求时的unix时间戳。本次请求签名的有效时间为该时间戳+10分钟。*/ 13 public $timestamp = ''; 14 public function _initialize(){ 15 $this->timestamp = NOW_TIME + 600;//初始化用户发起请求时的unix时间戳 16 } 17 /** 18 * 单播, 推送一条消息到指定设备 19 * $channel_id 目标客户端设备所属的唯一id; 20 * $msg 消息内容.可参见<u>消息体格式说明</u> 当消息体类型为一个array时,将自动调用json_encode方法来将array转换为一个string; 21 * $opts 可选参数列表, 包含 msg_type, msg_expires, deploy_status, msg_topic几项可选内容; 22 * 23 */ 24 public function pushMsgToSingleDevice($channel_id,$device_type,$messages){ 25 if(empty($channel_id)) 26 return array('error_code'=>C('RES_PARAM_ERR'),'error_msg'=>''); 27 $api = 'push/single_device';//API的资源操作方法名 28 $msg_type = 1;//取值如下:0:消息;1:通知。默认为0 29 $url = $this->restHostUrl.$api; 30 $arrContent = array( 31 'apikey' => $this->apikey, 32 'timestamp' => NOW_TIME, 33 'device_type' => $device_type,//3:android;4:ios 34 'channel_id' => $channel_id, 35 'msg' => $messages, 36 'msg_type' => $msg_type 37 ); 38 $sign = $this->getSign('POST',$url,$arrContent); 39 $arrContent['sign'] = $sign; 40 $return = $this->curlPost($arrContent,$url); 41 $rs = $this->object_array(json_decode($return)); 42 if($rs['error_code']>0){ 43 return false; 44 } 45 return true; 46 } 47 48 /** 49 * 批量单播, 向指定的一组channel_id发送一条消息. 50 * $channel_ids; 一个数组, 每项为一个channel_id 51 * $msg 消息内容.可参见<u>消息体格式说明</u> 当消息体类型为一个array时,将自动调用json_encode方法来将array转换为一个string; 52 * $opts 可选参数, 包含 53 */ 54 public function pushBatchUniMsg($channel_ids,$messages,$device_type){ 55 if(empty($channel_ids)) 56 return array('error_code'=>C('RES_PARAM_ERR'),'error_msg'=>''); 57 $api = 'push/batch_device';//API的资源操作方法名 58 $msg_type = 1;//取值如下:0:消息;1:通知。默认为0 59 $url = $this->restHostUrl.$api; 60 $arrContent = array( 61 'apikey' => $this->apikey, 62 'timestamp' => NOW_TIME, 63 'device_type' => $device_type,//3:android;4:ios 64 'channel_ids' => $channel_ids, 65 'msg' => $messages, 66 'msg_type' => $msg_type 67 ); 68 $sign = $this->getSign('POST',$url,$arrContent); 69 $arrContent['sign'] = $sign; 70 $return = $this->curlPost($arrContent,$url); 71 if($return['error_code']>0){ 72 return false; 73 } 74 return true; 75 } 76 /** 77 *@var curl模拟post提交数据 78 *@param $data 提交的所有参数 79 *@param $url 请求的地址 80 *@return json 百度页面返回的结果 81 */ 82 function curlPost($data,$url){ 83 $data = $this->encodePostBody($data); 84 $port = parse_url($url, PHP_URL_PORT); 85 $header = array( 86 'Content-Type: application/x-www-form-urlencoded;charset=utf-8', 87 'User-Agent: '. $this->makeUA() 88 ); 89 $ch = curl_init (); 90 curl_setopt ( $ch, CURLOPT_URL, $url ); 91 curl_setopt ( $ch, CURLOPT_PORT, empty($port)?80:$port ); 92 curl_setopt ($ch, CURLOPT_HTTPHEADER, $header); 93 curl_setopt ( $ch, CURLOPT_POST, 1 ); 94 // curl_setopt ( $ch, CURLOPT_HEADER, 0 ); 95 // curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, false ); 96 curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 ); 97 curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data ); 98 $return = curl_exec ( $ch ); 99 curl_close ( $ch ); 100 return $return; 101 } 102 103 function encodePostBody($body) { 104 if ($body === null) { 105 return ''; 106 } 107 108 if (! is_array($body)) { 109 return urlencode(strval($body)); 110 } 111 112 $result = array (); 113 foreach ( $body as $k => $v ) { 114 $result [ ] = urlencode($k) . '=' . urlencode($v); 115 } 116 117 return join('&', $result); 118 } 119 120 121 function makeUA(){ 122 $sdkVersion = '3.0.0';//百度推送版本 123 $sysName = php_uname('s'); 124 $sysVersion = php_uname('v'); 125 $machineName = php_uname('m'); 126 127 $systemInfo = "$sysName; $sysVersion; $machineName"; 128 129 $langName = 'PHP'; 130 $langVersion = phpversion(); 131 132 $serverName = php_sapi_name(); 133 $serverVersion = "Unknown"; 134 135 $sendInfo = 'ZEND/' . zend_version(); 136 137 $serverInfo = "$serverName/$serverVersion"; 138 139 if(isset($_SERVER['SERVER_SOFTWARE'])){ 140 $serverInfo .= '(' . $_SERVER['SERVER_SOFTWARE'] . ')'; 141 } 142 143 144 $tpl = "BCCS_SDK/3.0 ($systemInfo) $langName/$langVersion (Baidu Push SDK for PHP v$sdkVersion) $serverInfo $sendInfo"; 145 146 return $tpl; 147 } 148 //object转数组 149 function object_array($array){ 150 if(is_object($array)){ 151 $array = (array)$array; 152 } 153 if(is_array($array)){ 154 foreach($array as $key=>$value){ 155 $array[$key] = object_array($value); 156 } 157 } 158 return $array; 159 } 160 /** 161 * 计算请求迁名 162 * 163 * @param string $method 164 * GET|POST 165 * @param string $url 166 * 请求的完整url, 不含query部份 167 * @param array $arrContent 168 * 提交的数据项,包含get及post,但不包含签名项 169 * @return string 170 */ 171 function getSign($method, $url, $arrContent) { 172 $secret_key = $this->secret_key; 173 $baseStr = strtoupper($method) . $url; 174 ksort($arrContent); 175 foreach ( $arrContent as $key => $value ) { 176 $baseStr .= $key . '=' . $value; 177 } 178 $sign = md5(urlencode($baseStr . $secret_key)); 179 180 return $sign; 181 } 182 183 }
限于篇幅,这里只写单播和批量单播这个例子
控制器调用代码:
class IndexController extends Controller { public function index(){ $channelId = '3785562685113372034';//测试用 $title = 'Hi!'; $description = 'hello, this message from baidu push service.'; $push = new BdPushModel('user_member'); $messages = json_encode(array('title'=>$title,'description'=>$description)); $device_type = 3;//3:android,4:ios $rs = $push->pushMsgToSingleDevice($channelId,$device_type,$messages); // 判断返回值,当发送失败时, , 可以通过getError来获得错误信息. if(!$rs){ $this->ajaxReturn(false, "JSON"); exit(); } $this->ajaxReturn(true, "JSON"); exit(); } }