随着微信小程序、手机APP项目的愈发普遍。单一的轮子会造成项目愈发臃肿。很多时候我们为了图方便都是直接引入别人的类库,很少关心自己是否实现一个类库。
今天波波分享的半个轮子属于一个半成品。其想法是将微信模板消息推送、阿里云移动推送、个推(集成这个主要原因是uni-app中移动端有此插件,集成后可以让前端技术更方便)、邮件、短信这几个功能放到一个PHP文件中。使用时只需要一句话进行调用。
调用代码片段:
- /**
- * 工单提醒
- */
- public function reminder(){
- $msg = ["touser"=>1,"method"=>"wechat","scene"=>"remind","msg_type"=>"text",
- "content"=>["first"=>["value"=>"您有一条工单即将到期","color"=>"#173177"],
- "keyword1"=>["value"=>"GD2018080133420","color"=>"#173177"],"keyword2"=>["value"=>"保养任务","color"=>"#173177"],
- "keyword3"=>["value"=>"2021-03-30 12:30:00","color"=>"#173177"],"remark"=>['value'=>"这是一条测试提醒"]],'title'=>"工单提醒",'openid'=>"oytM-6Y_oTomRkXPjxHJsIdMhVP0"];
- $res = NotifyService::send($msg);
- $code = $res['code'] || 200;
- $this->result([],$code,$res['msg'],'json');
- }
关键在于使用时仅需要在调用的PHP文件上方引入NotifyService,直接使用send()方法即可。
NotifyService源码(半成品):
- <?php
- namespace service;
- /**
- * 消息推送服务
- * Class NotifyService.php
- * @package app\admin\controller
- * @author 繁华如梦 <[email protected]>
- * @desc:基于阿里移动推送、邮件、个推、微信公众号做消息推送
- * @date 2021/3/8 9:33
- */
- class NotifyService{
- private static $content = [];
- /** 发送消息对象 */
- private static $_send = [];
- /**NotifyService Constructor
- * @param array $msg 初始化消息数据
- * $msg eg.["touser":uid,"method":all,"scene":register,"msg_type":text,"content":XXX ...];
- * method:all表示全部推送,wechat表示微信推送,alipush表示阿里推送,mail表示邮件,getui表示个推
- */
- public static function send($msg){
- $v = self::verify($msg);
- if($v['code'] !== 200){
- return ['code'=>$v['code'],'msg'=>$v['msg']];
- }
- emptyempty($msg['msg_type']) && $msg['msg_type'] = "text"; //默认文本消息,后期根据通道可以丰富推送消息类型,但微信仅支持文本!!!
- self::$content = $msg;
- self::buildMsg();
- switch (self::$content['method']){
- case "wechat":
- self::wechat_push(self::$_send);
- break;
- case "alipush":
- self::mpush(self::$_send);
- break;
- case "all":
- self::wechat_push(self::$_send['wechat']);
- self::mpush(self::$_send['alipush']);
- break;
- default:
- break;
- }
- return ['code'=>"200",'msg'=>"消息发送成功"];
- }
- /**
- * 发送微信模板消息
- * @param array $msg buildMsg
- */
- private static function wechat_push($msg){
- $wechat = &load_wechat('Receive');
- $res = $wechat->sendTemplateMessage($msg);
- return $res;
- }
- /**发送阿里移动推送
- * @param array $msg buildMsg
- */
- private function mpush($msg){
- $api = "cloudpush.aliyuncs.com";
- date_default_timezone_set("GMT");
- $dateTimeFormat = 'Y-m-d\TH:i:s\Z'; // ISO8601规范
- $accessKeyId = sysconf('sms_aliyun_appid');
- $accessKeySecret = sysconf('sms_aliyun_appsecret');
- $msg['AccessKeyId'] = $accessKeyId;
- $msg['SignatureMethod'] = "HMAC-SHA1";
- $msg['Timestamp'] = date($dateTimeFormat);
- $msg['SignatureVersion'] = "1.0";
- $msg['SignatureNonce'] = uniqid();
- $msg['Signature'] = self::getSignature($msg,$accessKeySecret);
- //推送消息
- $res = simplexml_load_string(HttpService::get($api,$msg));
- $res = json_decode(json_encode($res),true);
- //返回数据仅有RequestId,MessageId
- if(!emptyempty($res['MessageId'])){
- return ['code'=>200,'msg'=>"移动推送消息成功",'content'=>$res];
- }else{
- return ['code'=>500,'msg'=>$res['Message']];
- }
- }
- /**
- * 根据类型构建消息
- */
- private static function buildMsg(){
- if(emptyempty(self::$content['method']) || !in_array(self::$content['method'],['wechat','alipush','mail','getui'])) {
- return false;
- }
- switch (self::$content['method']){
- case "wechat":
- self::$_send = ['touser'=>self::$content['openid'],'template_id'=>self::getTemplateId("wechat",self::$content['scene']),'url'=>"",'data'=>self::$content['content']];
- break;
- case "alipush":
- self::$_send = [
- 'Action'=>"Push",
- 'RegionId' => "cn-hangzhou",
- 'Version'=>"2016-08-01",
- 'AppKey' => self::$content['app_key'],//创建的应用
- 'PushType' => "NOTICE",
- 'DeviceType' => "ALL",
- 'Target' => "DEVICE",
- 'TargetValue' => self::$content['device_id'],
- 'Body' => self::$content['content'],
- 'Title' => self::$content['title'],
- 'JobKey' => self::$content['job_key'], //如果需要后台记录推送消息状态
- 'StoreOffline' => "true",
- ];
- break;
- case "all":
- self::$_send['wechat'] = ['touser'=>self::$content['openid'],'template_id'=>self::getTemplateId("wechat",self::$content['scene']),'url'=>"",'data'=>self::$content['content']];
- self::$_send['alipush'] = [
- 'Action'=>"Push",
- 'RegionId' => "cn-hangzhou",
- 'Version'=>"2016-08-01",
- 'AppKey' => self::$content['app_key'],//创建的应用
- 'PushType' => "NOTICE",
- 'DeviceType' => "ALL",
- 'Target' => "DEVICE",
- 'TargetValue' => self::$content['device_id'],
- 'Body' => self::$content['content'],
- 'Title' => self::$content['title'],
- 'JobKey' => self::$content['job_key'], //如果需要后台记录推送消息状态
- 'StoreOffline' => "true",
- ];
- break;
- default:
- self::$_send = [];
- break;
- }
- return true;
- //return self::$_send;
- }
- /**获取消息模板ID
- * @param $chanel string 推送通道
- * @param $scene string 消息场景
- */
- private static function getTemplateId($chanel,$scene){
- //alarm:设备报警;remind:任务提醒;
- $temp_wechat = ['register'=>"kFuKXjJlSWWeLj1MQelT7E0BRIf3H1gDBfm-5yF9Q30",'auth'=>"3jCOuTcVyfyb7bOJSm6HCO8kZaRdA8lnS0MQ_54QpEE","repass"=>"VOgt3a1SEKAeB8yN8f-hIFSRwMRM6W-TqvLPPTRLoMk","alarm"=>"hH7MhPQn5Bg3Kkc1DT4bMiqU38PrBryYTKUKyDjtlYU","remind"=>"Wm9TlfstyPMfqqmXiw0bOR-Mrw4qk8IKD6zlCBGKbhU"];
- $temp_alipush = ['register'=>"",'auth'=>"","repass"=>"","alarm"=>"","remind"=>""];
- $temp_getui = ['register'=>"",'auth'=>"","repass"=>"","alarm"=>"","remind"=>""];
- return ${"temp_".$chanel}[$scene];
- }
- /** 阿里云签名
- * @param array $parameters 请求参数
- * @param string $accessKeySecret 接入密钥
- * @return string
- */
- private static function getSignature($parameters, $accessKeySecret){
- ksort($parameters);
- $canonicalizedQueryString = '';
- foreach($parameters as $key => $value) {
- $canonicalizedQueryString .= '&' . self::percentEncode($key)
- . '=' . self::percentEncode($value);
- }
- // 生成用于计算签名的字符串 stringToSign
- $stringToSign = 'GET&%2F&' . self::percentencode(substr($canonicalizedQueryString, 1));
- // 计算签名,注意accessKeySecret后面要加上字符'&'
- $signature = base64_encode(hash_hmac('sha1', $stringToSign, $accessKeySecret . '&', true));
- return $signature;
- }
- /** percent加密
- * @param $str
- * @return string|null
- */
- private static function percentEncode($str){
- // 使用urlencode编码后,将"+","*","%7E"做替换即满足ECS API规定的编码规范
- $res = urlencode($str);
- $res = preg_replace('/\+/', '%20', $res);
- $res = preg_replace('/\*/', '%2A', $res);
- $res = preg_replace('/%7E/', '~', $res);
- return $res;
- }
- /** 数据验证
- * @param array $arr 待验证数据
- */
- private static function verify($arr){
- //验证的规则--备忘用
- $rule = ['touser'=>"integer",'method'=>"in.all|alipush|wechat|mail|getui",'msg_type'=>"alpha",
- 'content'=>"require",'title'=>"require",'openid'=>"wechat.require",'device_id'=>"alipush.require",'app_key'=>"alipush.require",
- 'push_type'=>"alipush.MESSAGE|NOTICE"];
- if(emptyempty($arr['touser']) || !is_numeric($arr['touser'])){return ['code'=>400197,'msg'=>"touser参数错误"];}
- if(emptyempty($arr['method']) || !in_array($arr['method'],['all','alipush','wechat','mail','getui'])){return ['code'=>400201,'msg'=>"method参数错误"];}
- if(emptyempty($arr['scene']) || !in_array($arr['scene'],["register","auth","repass","alarm","remind"])){return ['code'=>400202,'msg'=>"scene参数错误"];}
- if(emptyempty($arr['content']) || !is_array($arr['content'])){return ['code'=>400203,'msg'=>"content参数错误"];}
- if(emptyempty($arr['title']) || !is_string($arr['title'])){return ['code'=>400204,'msg'=>"title参数错误"];}
- //String类型没有判断,开发时注意传入正确参数
- if(in_array($arr['method'],['all','wechat']) && emptyempty($arr['openid'])){return ['code'=>400206,'msg'=>"openid参数错误"];}
- if(in_array($arr['method'],['all','alipush']) && emptyempty($arr['device_id'])){return ['code'=>400207,'msg'=>"device_id参数错误"];}
- if(in_array($arr['method'],['all','alipush']) && emptyempty($arr['app_key'])){return ['code'=>400208,'msg'=>"app_key参数错误"];}
- if(in_array($arr['method'],['all','alipush']) && emptyempty($arr['push_type'])){return ['code'=>400209,'msg'=>"push_type为空"];}
- if(in_array($arr['method'],['all','alipush']) && !in_array($arr['push_type'],['MESSAGE','NOTICE'])){return ['code'=>400210,'msg'=>"push_type参数错误"];}
- return ['code'=>200,'msg'=>"参数校验成功"];
- }
- }
上述源码仅测试了微信模板消息。阿里移动推送虽然集成了,但是并未进行测试。个推、邮件、短信是尚未开发的部分。
上述源码支持在波波thinkPHP开发的后端框架TP-admin中直接使用,也支持zoujingli的项目ThinkAdmin。