小程序的消息推送很简单,主要把几个步骤理清就好了。
- 在小程序的微信开发平台上配置服务器
- 前端传递必要参数
- 后端实现推送功能
一、配置
官方文档点这里
进入到微信平台,点开发=》开发设置=》消息推送的启用。
配置地址写可线上访问的,且必须要http或者https开头的,访问的位置是配置回调的php文件。内容如下:
<?php
/**
* wechat php test
*/
//define your token
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
$wechatObj->valid();
class wechatCallbackapiTest
{
public function valid()
{
$echoStr = $_GET["echostr"];
//valid signature , option
if($this->checkSignature()){
echo $echoStr;
exit;
}
}
private function checkSignature()
{
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );
if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
}
token是自己随便填的,AESkey最好直接使用后面的随机生成。
在提交后你可能会遇到“无效TOKEN”,那么可从以下几个地方检查:
- 所填的域名是否可访问,最好另起一个窗口直接访问一下你所填的地址
- 所填的Token和验证php文件中定义的token是否一致
- 判断
$tmpStr
和$signature
是否一致后需要echo出结果
提交配置成功后再去模板消息那里添加自己需要做的需求推送模板,注意模板参数的顺序,在后端提交代码中顺序需要保证是一样的。
二、代码的实现
推送这里可以分成普通的消息推送和订单支付的消息推送,当然,这里是我自己分的,原因是他们所需的formid的区别,看了文档会知道,普通的消息推送所需的formid是必须在前端的form标签中提交后获取到的,这也是必须参数。而支付订单的消息推送中的formid就可以不用前端那一步,因为它的formid是支付过程中生成的预支付id(prepay_id),所以下面只介绍普通的消息推送,知道了推送过程,支付的消息推送只需将其formid换成pripay_id就可以了。
前端
<form bindsubmit="formSubmit" report-submit="true">
<button formType="submit">允许通知我</button>
</form>
formSubmit: function (e) {
var that = this
wx.request({
url: "https://xxx/mobiletplus/index.php?act=login&op=send_wx",
data: {
"form_id": e.detail.formId,
"customer_id": that.data.customer_id
},
method: 'POST',
header: {
'content-type': 'application/x-www-form-urlencoded'
},
success: function (res) {
util.showSuccess("设置成功")
//console.log(res.data)
},
fail: function (e) {
util.showError("设置失败".e)
}
})
},
拿到form_id后传到后端方法send_wx中实现功能
后端
所需参数:
- touser=>open_id
- templateId
- formId
- data
1.获取open_id(可参考我上一篇文章小程序授权登陆)
open_id在小程序授权登陆的时候产生,并存到数据库中
$json=$this->_getUserInfo();
$data['openid']=empty($json->openid)?$json->openId:$json->openid;
private function _getUserInfo(){
require_once(dirname(dirname(__FILE__)).DS."resource".DS.'wxBizDataCrypt.php');
$code = $_REQUEST['code'];
$appId = $_REQUEST['appID'];
$appSecret = $_REQUEST['appSecret'];
$grant_type="authorization_code";
$url_get = 'https://api.weixin.qq.com/sns/jscode2session?appid='.$appId.'&secret='.$appSecret.'&js_code='.$code.'&grant_type='.$grant_type;
try{
$json=json_decode($this->curlGet($url_get));
if (!$json->errmsg){
$sessionKey = $json->session_key;
$encryptedData=$_REQUEST['encrypted'];
$iv=$_REQUEST['iv'];
$appID=$_REQUEST['appID'];
$pc = new WXBizDataCrypt($appID, $sessionKey);
$errCode = $pc->decryptData($encryptedData, $iv, $data );
if ($errCode == 0) {
return json_decode($data);
} else {
throw new Exception($errCode);
}
}else {
throw new Exception('获取session_key发生错误:错误代码'.$json->errcode.',微信返回错误信息:'.$json->errmsg);
}
}
catch(Exception $e){
output_error($e->getMessage());
}
}
private function curlGet($url,$method='get',$data=''){
$ch = curl_init();
$header=array();
$header[] = "Accept-Charset: utf-8";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$temp = curl_exec($ch);
curl_close($ch);
return $temp;
}
2.获取access_token
$access_token = $this->get_wxmini_access_token()->access_token;
public function get_wxmini_access_token(){
$grant_type="client_credential";
$url_get="https://api.weixin.qq.com/cgi-bin/token?grant_type=".$grant_type."&appid=".$this->appid."&secret=".$this->appSecret;
try{
$data = json_decode($this->curlGet($url_get));
return $data;
}
catch(Exception $e){
output_error($e->getMessage());
}
}
private function curlGet($url,$method='get',$data=''){
$ch = curl_init();
$header=array();
$header[] = "Accept-Charset: utf-8";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$temp = curl_exec($ch);
curl_close($ch);
return $temp;
}
3.获取$url
$url = 'https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token='.$access_token; //此处变量插入字符串不能使用{}!!!
4.$data的结构
$data = array(
"touser"=>$openid,
"template_id"=>$template_id,
"page"=>$page,
"form_id"=>$form_id,
//"page"=>$page,
"data"=>array(
"keyword1"=>array(
"value"=>$key1,
"color"=>"#173177"
),
"keyword2"=>array(
"value"=>$key2,
"color"=>"#173177"
),
"keyword3"=>array(
"value"=>$key3,
"color"=>"#173177"
),
),
);
5.send_wx
public function send_wx($form_id,$template_id,$page,$openid,$send_data){
$access_token = $this->get_wxmini_access_token()->access_token;
if(!empty($access_token)) {
$url = 'https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token='.$access_token; //此处变量插入字符串不能使用{}!!!
/*
* $send_data格式严格按照下面的形式
* array(
* "keyword1"=>array(
* "value"=>$key1,
* "color"=>"#173177"
* ),
* "keyword2"=>array(
* "value"=>$key2,
* "color"=>"#173177"
* ),
* "keyword3"=>array(
* "value"=>$key3,
* "color"=>"#173177"
* ),
* ),
* */
$data = array(
"touser"=>$openid,
"template_id"=>$template_id,
"page"=>$page,
"form_id"=>$form_id,
//"page"=>$page,
"data"=>$send_data,
);
$result = $this->curlPost($url,$data,'json');
$arr = array('ret'=>1,
'msg'=>'success',
'data'=>array('result'=>$result),
);
} else {
$arr = array('ret'=>0,'msg'=>'ACCESS TOKEN为空!');
}
echo json_encode($arr);
}
三、微信小程序的支付功能
对于app中的微信支付功能可以看我前面写的微信支付爬坑
那在这里的微信小程序的支付功能简单说一下就可以了,参考代码即可。主要说的是注意事项。
-
首先,我们需要在小程序对于账号的微信公共平台找到微信支付这个tab
如图可见,2是我们小程序的appid,3是我们需要关联的商户号。所以我们得需要一个开通了的商户号。
- 关联商户号,如果关联失败的原因可能是因为:此小程序之前关联过别的商户号,如果关联过别的商户号,则再关联新的商户号的时候,新的商户号中费率必须和之前关联过的那个商户号的费率相同,否则会关联失败。这里我也是被坑了挺长时间。一开始反驳回来说的是一个费率为广告流量的,一个是销售的。我本来以为是说的是我的小程序是广告流量的,我在想我的类目明明是海淘啊,怎么会审核说我的是广告流量业务的。后来才发现,原来他指的是这个小程序之前关联过的商户号的业务是广告流量的。如果碰到这样的情况,是无法在线修改和删除之前关联过的商户号的(目前是,不代表以后会不能)。那我打客服电话咨询,他说只能迁移小程序。所以我这边用的是新申请的小程序。
- prepay_id为空。待关联成功后,点支付的功能时发现prepay_id预支付id为空。可能的原因是:商户号不对;没有openid;缺少JSAPI支付功能;我碰到的原因就是这个JSAPI没有开通。需要到对应的商户号下面开通,开通需要管理员的短信验证码。
- 支付相关后台代码
wxmini表示的是小程序
public function payOp(){
$app_id=empty($_REQUEST['appID'])?"wx3ee49988xxxx4":$_REQUEST['appID'];
$mch_id='xxxx';
$app_key='xxx';
$openid=$_REQUEST['openid'];
// order_info
$orderIds=$_REQUEST['orderIds'];
if(empty($orderIds)){
output_error("网络繁忙");
}
$orderIds=getRandChar(5)."_".$orderIds;
$order_amount=(float)$_REQUEST['order_amount'];
// $order_info=Model("order")->getOrderInfo(array("order_id"=>$order_id));
// if(empty($order_info)){
// output_error("网络繁忙");
// }
// get prepay id
$prepay_id = $this->generatePrepayId($app_id, $mch_id, $app_key,$orderIds,$order_amount,$openid);
// re-sign it
if($_REQUEST['platform'] == "wxmini"){
$response = array(
'appId' => $app_id,
'timeStamp' => ''.time(),
'nonceStr' => $this->generateNonce(),
'package' => 'prepay_id='.$prepay_id,
'signType' => 'MD5'
);
$response['paySign'] = $this->calculateSign($response, $app_key);
}
else{
$response = array(
'appid' => $app_id,
'partnerid' => $mch_id,
'prepayid' => $prepay_id,
'package' => 'Sign=WXPay',
'noncestr' => $this->generateNonce(),
'timestamp' => time(),
);
$response['sign'] = $this->calculateSign($response, $app_key);
}
output_data(array('response'=>$response,'prepay_id'=>$prepay_id));
}
/**
* Generate a nonce string
*
* @link https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=4_3
*/
function generateNonce(){
return md5(uniqid('', true));
}
/**
* Get a sign string from array using app key
*
* @link https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=4_3
*/
function calculateSign($arr, $key){
ksort($arr);
$buff = "";
foreach ($arr as $k => $v) {
if ($k != "sign" && $k != "key" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return strtoupper(md5($buff . "&key=" . $key));
}
/**
* Get xml from array
*/
function getXMLFromArray($arr){
$xml = "<xml>";
foreach ($arr as $key => $val) {
if (is_numeric($val)) {
$xml .= sprintf("<%s>%s</%s>", $key, $val, $key);
} else {
$xml .= sprintf("<%s><![CDATA[%s]]></%s>", $key, $val, $key);
}
}
$xml .= "</xml>";
return $xml;
}
好了,对于小程序的消息推送功能就总结完了。