hgzhang 2020-02-18
前一段时间做项目涉及到这方面的内容,看了技术文档,小程序页面没有详细介绍,要前往微信公众号开发文档,卡券功能是先为微信公众号开发的功能,后来也提供个小程序,文档在小程序中没有过多的介绍,微信文档我就不想过多的吐槽了,大家都懂。
一、会员卡
1、在小程序会员卡,其实也是用到微信公众号的,开始在摸索,在微信公众号管理后台创建会员卡,在小程序中能调用,但会员卡号不能自定义编号,因为管理后创建的,默认是不能自定义编码(use_custom _code=false),一键开卡(wx_activate=true)、自动激活(auto_activate=true),所以不是我们需要的,应该另辟一条道路,自己通过接口创建会员卡,代码例子如下:
public function addCard(){ exit; $url = ‘https://api.weixin.qq.com/card/create?access_token=‘.$this->getAccessToken(); $post[‘card‘][‘card_type‘] = ‘MEMBER_CARD‘; $post[‘card‘][‘member_card‘][‘prerogative‘] = ‘111‘; $post[‘card‘][‘member_card‘][‘auto_activate‘] = true; //自动激活 $post[‘card‘][‘member_card‘][‘wx_activate‘] = true; //一键开卡 $post[‘card‘][‘member_card‘][‘supply_bonus‘] = false; $post[‘card‘][‘member_card‘][‘supply_balance‘] = false; $post[‘card‘][‘member_card‘][‘base_info‘][‘logo_url‘] = "http://mmbiz.qpic.cn/mmbiz_png/q2O5rxE2PYlF9XricN8EmwX0o5aPWayBVc8wVbOuqv64v7iaVJvURbWSj5r2qOib8WhXw1aHsibhs05AELEylgrjMQ/0?wx_fmt=png"; $post[‘card‘][‘member_card‘][‘base_info‘][‘code_type‘] = "CODE_TYPE_TEXT"; $post[‘card‘][‘member_card‘][‘base_info‘][‘brand_name‘] = ‘brand_name_1‘; $post[‘card‘][‘member_card‘][‘base_info‘][‘title‘] = ‘title_1‘; $post[‘card‘][‘member_card‘][‘base_info‘][‘color‘] = ‘Color010‘; $post[‘card‘][‘member_card‘][‘base_info‘][‘notice‘] = ‘notice‘; $post[‘card‘][‘member_card‘][‘base_info‘][‘description‘] = ‘description‘; $post[‘card‘][‘member_card‘][‘base_info‘][‘sku‘][‘quantity‘] = 1000000000; $post[‘card‘][‘member_card‘][‘base_info‘][‘date_info‘][‘type‘] = ‘DATE_TYPE_PERMANENT‘; $post[‘card‘][‘member_card‘][‘base_info‘][‘get_limit‘] = 1; //限领一张 $post[‘card‘][‘member_card‘][‘base_info‘][‘can_share‘] = false; $post[‘card‘][‘member_card‘][‘base_info‘][‘can_give_friend‘] = false; $post[‘card‘][‘member_card‘][‘base_info‘][‘use_custom_code‘] = true; //开启自定义编码 $data = http_curl_post_json($url,$post); $data = json_decode($data,true); return $data; }
2、创建好会员卡后,在小程序中写入用户领取会员卡的前端代码,jssdk的wx.addCard方法,其中加密不同于jssdk的加密方式,加密方式看微信公众号jssdk说明文档附录4,addCard方法的cardExt
里的参数很重要
code:需要给用户自定义编码时,才需填入你后台开发生成编码(会员卡卡号),否则不填为空字符串
openid:需要给自定的用户发放会员卡是,才需填入用户的openid(微信公众号的epenid而不是小程序的openid),否则为空字符串
...........等参数
注意:以上参数需要用到的时候才加入一起加密,如:code的值为空字符串则不需加了加密,否则领取会员卡时会出签名错误
加密方法
<?php class Jssdk { private $appId = ‘‘; private $appSecret = ‘‘; public function __construct($appId,$appSecret){ $this->appId = $appId; $this->appSecret = $appSecret; } /* *实现微信jssdk加密 */ public function getSignPackage($url) { $jsapiTicket = $this->getJsApiTicket(); // 注意 URL 一定要动态获取,不能 hardcode. //ajax页面url则必须要前端传输url地址 // $protocol = (!empty($_SERVER[‘HTTPS‘]) && $_SERVER[‘HTTPS‘] !== ‘off‘ || $_SERVER[‘SERVER_PORT‘] == 443) ? "https://" : "http://"; // $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; $timestamp = time(); $nonceStr = $this->createNonceStr(); // 这里参数的顺序要按照 key 值 ASCII 码升序排序 $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url"; $signature = sha1($string); $signPackage = array( "appId" => $this->appId, "nonceStr" => $nonceStr, "timestamp" => $timestamp, "url" => $url, "signature" => $signature, "rawString" => $string ); return $signPackage; } //获取access_token public function getAccessTokenInfo(){ return $this->getAccessToken(); } private function createNonceStr($length = 16) { $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; $str = ""; for ($i = 0; $i < $length; $i++) { $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); } return $str; } private function getJsApiTicket() { // jsapi_ticket 应该全局存储与更新,以下代码以写入到文件中做示例 $data = json_decode(file_get_contents("jssdk/jsapi_ticket.json")); if ($data->expire_time < time()) { $accessToken = $this->getAccessToken(); $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken"; $res = json_decode($this->curl($url)); $ticket = $res->ticket; if ($ticket) { $data->expire_time = time() + 7000; $data->jsapi_ticket = $ticket; $fp = fopen("jssdk/jsapi_ticket.json", "w"); fwrite($fp, json_encode($data)); fclose($fp); } } else { $ticket = $data->jsapi_ticket; } return $ticket; } private function getAccessToken() { // access_token 应该全局存储与更新,以下代码以写入到文件中做示例 $data = json_decode(file_get_contents("jssdk/access_token.json")); if ($data->expire_time < time()) { $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$this->appId&secret=$this->appSecret"; $res = json_decode($this->curl($url)); $access_token = $res->access_token; if ($access_token) { $data->expire_time = time() + 7000; $data->access_token = $access_token; $fp = fopen("jssdk/access_token.json", "w"); fwrite($fp, json_encode($data)); fclose($fp); } } else { $access_token = $data->access_token; } return $access_token; } private function curl( $url , $postFields = NULL ) { $ch = curl_init(); curl_setopt( $ch , CURLOPT_TIMEOUT , 3 ); curl_setopt( $ch , CURLOPT_URL , $url ); curl_setopt( $ch , CURLOPT_FAILONERROR , FALSE ); curl_setopt( $ch , CURLOPT_RETURNTRANSFER , TRUE ); //https 请求 if ( strlen( $url ) > 5 && strtolower( substr( $url , 0 , 5 ) ) == ‘https‘ ){ curl_setopt( $ch , CURLOPT_SSL_VERIFYPEER , FALSE ); curl_setopt( $ch , CURLOPT_SSL_VERIFYHOST , FALSE ); } if ( is_array( $postFields ) && 0 < count( $postFields ) ){ $postBodyString = ‘‘; $postMultipart = FALSE; foreach ( $postFields as $k => $v ) { if ( ‘@‘ != substr( $v , 0 , 1 ) ) //判断是不是文件上传 { $postBodyString .= "$k=" . urlencode( $v ) . "&"; } else { //文件上传用multipart/form-data,否则用www-form-urlencoded $postMultipart = TRUE; } } $postFields = trim( $postBodyString , ‘&‘ ); unset( $k , $v ); curl_setopt( $ch , CURLOPT_POST , TRUE ); if ( $postMultipart ){ curl_setopt( $ch , CURLOPT_POSTFIELDS , $postFields ); } else { curl_setopt( $ch , CURLOPT_POSTFIELDS , $postFields ); } } $reponse = curl_exec( $ch ); curl_close( $ch ); return $reponse; } //卡券等签名, private function apiTicket() { // api_ticket 应该全局存储与更新,以下代码以写入到文件中做示例 $data = json_decode(file_get_contents("jssdk/api_ticket.json")); if ($data->expires_in < time()) { $accessToken = $this->getAccessToken(); $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$accessToken&type=wx_card"; $res = json_decode($this->curl($url)); $ticket = $res->ticket; if ($ticket) { $data->expires_in = time() + 7000; $data->ticket = $ticket; $fp = fopen("jssdk/api_ticket.json", "w"); fwrite($fp, json_encode($data)); fclose($fp); } } else { $ticket = $data->ticket; } return $ticket; } //由于历史原因,卡券的JS接口先于JSSDK出现,当时的JSAPI并没有鉴权体系,所以在卡券的签名里也加上了appsecret/api_ticket这些身份信息 public function getApiTicket($cardId=‘‘,$code=‘‘) { $apiTicket = $this->apiTicket(); $timestamp = time(); $nonceStr = $this->createNonceStr(); // 这里参数的顺序要按照 key 值 ASCII 码升序排序 $tmpArr = array($nonceStr,$apiTicket,$cardId,$timestamp); if($code){ array_push($tmpArr, $code); } sort($tmpArr,SORT_STRING); $tmpStr = implode($tmpArr); $signature = sha1($tmpStr); $signPackage = array( "cardId" => $cardId, "nonceStr" => $nonceStr, "timestamp" => $timestamp, "signature" => $signature, ); return $signPackage; } } ?>
3、领取会员卡,回调给后台领取信息,在addCard方法领取成功会返回用户领取的相关信息,success中把领取的信息提交后台保存,从而确认领取成功。
4、很多jssdk功能最先在微信公众号的,之后小程序在这基础之上引用,所以在小程序引用jssdk的方法涉及到的appid和appid密码都是微信公众号的而不是小程序的,卡券也如此,千万不要搞错,否则会造成签名错误等问题,这点微信官网没有说明。
5、熟悉会员卡,其它卡券类型也差不多。
以下会运用到的方法: 1 //post方式提交json格式的数据 function http_curl_post_json($url,$post){ $data_string = json_encode($post); $ch = curl_init($url); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POSTFIELDS,$data_string); curl_setopt($ch, CURLOPT_RETURNTRANSFER,true); curl_setopt($ch, CURLOPT_HTTPHEADER, array( ‘Content-Type: application/json‘, ‘Content-Length: ‘ . strlen($data_string)) ); $result = curl_exec($ch); return $result; }