[PHP+JS]微信卡券(潦草笔记,全代码,亲测通过)
群发卡券可以通过客服消息推送
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140547
后端代码:
define('APPID', 'xxxxxxxxxxxxxxxx'); define('SECRET', 'xxxxxxxxxxxxxxxx'); $publicToken = null; if($do == 'test') { set_time_limit(0); $openId = 'xxxxxxxxxxxxxxxx'; //$account = account_fetch($_W['acid']); //$account['key'], $account['secret'] echo '<pre>'; $publicToken = WxPublic_AccessToken(APPID, SECRET); echo 'AccessToken' . PHP_EOL; print_r($publicToken); if($publicToken != null && $publicToken['expires_datetime'] >= time()) { // 创建前获取公众号的全部卡券 $result = WxPublic_Card_BatchGet($publicToken['access_token']); echo 'BatchGet' . PHP_EOL; print_r($result); if($result['errcode'] == '0') { $cardIdList = $result['card_id_list']; $codes = array(); for($i = 1; $i <= 5; $i++) { $codes[] = strval(10000 + $i); } foreach($cardIdList as $cardId) { $result = WxPublic_Card_Get($publicToken['access_token'], $cardId); echo 'Get' . PHP_EOL; print_r($result); $result = WxPublic_Card_CheckCode($publicToken['access_token'], $cardId, $codes); echo 'CheckCode' . PHP_EOL; print_r($result); } $result = WxPublic_Card_CardInfo($publicToken['access_token'], date('Y-m-d', strtotime('-62 day')), date('Y-m-d', strtotime('-1 day')), 0); echo 'CardInfo-0' . PHP_EOL; print_r($result); $result = WxPublic_Card_CardInfo($publicToken['access_token'], date('Y-m-d', strtotime('-62 day')), date('Y-m-d', strtotime('-1 day')), 1); echo 'CardInfo-1' . PHP_EOL; print_r($result); } /* // ======================================== $aPath = realpath(dirname(__FILE__) . './test.jpg'); $cardImage = WxPublic_Card_Uploadimg($publicToken['access_token'], $aPath); //if($cardImage !== null && isset($cardImage['url'])) { echo 'Uploadimg' . PHP_EOL; print_r($cardImage); //} // ======================================== // 使用GET_CUSTOM_CODE_MODE_DEPOSIT模式创建卡券 // 用法参考:https://blog.csdn.net/u011738153/article/details/50457167 // 1.quantity初始值设置为0,设置use_custom_code=true,get_custom_code_mode='GET_CUSTOM_CODE_MODE_DEPOSIT' // 2.审核后添加code // 3.修改库存,<= code数量 $card = WxPublic_Card_Create_Groupon( $publicToken['access_token'], 'http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0', '微信餐厅', '132元双人火锅套餐', '020-88888888', '不可与其他优惠同享\r\n如需团购券发票,请在消费时向商户提出\r\n店内均可使用,仅限堂食', date('Y-m-d', strtotime('-1 day')), date('Y-m-d', strtotime('+1 year')), '以下锅底2选1(有菌王锅、麻辣锅、大骨锅、番茄锅、清补 凉锅、酸菜鱼锅可选):\n大锅1份 12元\n小锅2份 16元', 2 ); // $card = WxPublic_Card_Create_Cash( // $publicToken['access_token'], // 'http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0', // '微信餐厅', // '020-88888888', // '不可与其他优惠同享\r\n如需团购券发票,请在消费时向商户提出\r\n店内均可使用,仅限堂食', // date('Y-m-d', strtotime('-1 day')), // date('Y-m-d', strtotime('+1 year')), // 1000, // 10000, // 2 // ); // $card = WxPublic_Card_Create_Discount( // $publicToken['access_token'], // 'http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0', // '微信餐厅', // '132元双人火锅套餐', // '020-88888888', // '不可与其他优惠同享\r\n如需团购券发票,请在消费时向商户提出\r\n店内均可使用,仅限堂食', // date('Y-m-d', strtotime('-1 day')), // date('Y-m-d', strtotime('+1 year')), // 30, // 2 // ); // $card = WxPublic_Card_Create_Gift( // $publicToken['access_token'], // 'http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0', // '微信餐厅', // '132元双人火锅套餐', // '020-88888888', // '不可与其他优惠同享\r\n如需团购券发票,请在消费时向商户提出\r\n店内均可使用,仅限堂食', // date('Y-m-d', strtotime('-1 day')), // date('Y-m-d', strtotime('+1 year')), // '可兑换音乐木盒一个', // 2 // ); // $card = WxPublic_Card_Create_GeneralCoupon( // $publicToken['access_token'], // 'http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0', // '微信餐厅', // '132元双人火锅套餐', // '020-88888888', // '不可与其他优惠同享\r\n如需团购券发票,请在消费时向商户提出\r\n店内均可使用,仅限堂食', // date('Y-m-d', strtotime('-1 day')), // date('Y-m-d', strtotime('+1 year')), // '优惠券专用,填写优惠详情', // 2 // ); echo 'Create' . PHP_EOL; print_r($card); if($card['errcode'] == '0' && isset($card['card_id'])) { $codes = array(); for($i = 1; $i <= 5; $i++) { $codes[] = strval(10000 + $i); } if(count($codes) > 0) { $codeResult = WxPublic_Card_AddCode($publicToken['access_token'], $card['card_id'], $codes); if($codeResult['errcode'] == '0') { $countResult = WxPublic_Card_CodeCount($publicToken['access_token'], $card['card_id']); if($countResult['errcode'] == '0' && intval($countResult['count']) > 0) WxPublic_Card_ModifyStock($publicToken['access_token'], $card['card_id'], intval($countResult['count'])); else throw new Exception('卡券修改库存失败:' . json_encode($countResult)); } else { throw new Exception('卡券添加code失败:' . json_encode($codeResult)); } } // 失败 // $result = WxPublic_Card_CodeUpdate($publicToken['access_token'], $codes[count($codes) - 1], '99999', $cardIdList[count($cardIdList) - 1]); // echo 'CodeUpdate' . PHP_EOL; // print_r($result); $result = WxPublic_Card_CheckCode($publicToken['access_token'], $cardIdList[count($cardIdList) - 1], $codes); echo 'CheckCode' . PHP_EOL; print_r($result); $result = WxPublic_Card_Get($publicToken['access_token'], $card['card_id']); echo 'Get' . PHP_EOL; print_r($result); $result = WxPublic_Card_QrcodeCreate($publicToken['access_token'], $card['card_id']); echo 'QrcodeCreate' . PHP_EOL; print_r($result); } else { throw new Exception('创建卡券失败:' . json_encode($card)); } // ======================================== // 需要客户领取后才能有数据 $result = WxPublic_Card_UserCardList($publicToken['access_token'], $openId, $cardIdList[count($cardIdList) - 1]); echo 'UserCardList' . PHP_EOL; print_r($result); // 需要客户领取后才能查询 $result = WxPublic_Card_CodeGet($publicToken['access_token'], $cardIdList[count($cardIdList) - 1], $codes[0]); echo 'CodeGet' . PHP_EOL; print_r($result); if($result['errcode'] == '0' && $result['can_consume'] == true) { // 需要客户领取后才能核销 $result = WxPublic_Card_CodeConsume($publicToken['access_token'], $cardIdList[count($cardIdList) - 1], $codes[0]); echo 'CodeConsume' . PHP_EOL; print_r($result); } // ======================================== for($i = 0; $i < count($cardIdList);++$i) { for($j = 0; $j < count($codes);++$j) { // 需要客户领取后才能失效,已使用的不能失效 $result = WxPublic_Card_CodeUnavailable($publicToken['access_token'], $cardIdList[$i], $codes[$j], '用户发生退款'); echo 'Unavailable:' . $cardIdList[$i] . '-' . $codes[$j] . PHP_EOL; print_r($result); } $result = WxPublic_Card_Delete($publicToken['access_token'], $cardIdList[$i]); echo 'Delete:' . $cardIdList[$i] . PHP_EOL; print_r($result); } $result = WxPublic_Card_BizuinInfo($publicToken['access_token'], date('Y-m-d', strtotime('-62 day')), date('Y-m-d', strtotime('-1 day')), 0); echo 'BizuinInfo-0' . PHP_EOL; print_r($result); $result = WxPublic_Card_BizuinInfo($publicToken['access_token'], date('Y-m-d', strtotime('-62 day')), date('Y-m-d', strtotime('-1 day')), 1); echo 'BizuinInfo-1' . PHP_EOL; print_r($result); */ } echo '</pre>'; template('pad/test'); exit(); } elseif($do == 'wx_authority_signature') { $publicToken = WxPublic_AccessToken(APPID, SECRET); if($publicToken != null && $publicToken['expires_datetime'] >= time()) { exit(json_encode(Wx_AuthoritySignature($publicToken, $_GPC['url']))); } exit(); } elseif($do == 'wx_getcard') { // https://mp.weixin.qq.com/s/WhYpWmfuhUBw2wseTXdt2A // http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=cardsign $publicToken = WxPublic_AccessToken(APPID, SECRET); if($publicToken != null && $publicToken['expires_datetime'] >= time()) { $result = WxPublic_Card_BatchGet($publicToken['access_token']); if($result['errcode'] == '0') { $codes = array(); for($i = 1; $i <= 5; ++$i) { $codes[] = strval(10000 + $i); } $data = array(); foreach ($result['card_id_list'] as $cardId) { for($i = 0; $i < count($codes); ++$i) { $signature = Wx_CardSignature($publicToken['access_token'], $cardId); $data[] = array( 'api_ticket' => $signature['api_ticket'], 'card_id' => $signature['card_id'], 'card_ext' => array( // 全部字段传出去,别管有没有值 'code' => empty($signature['code']) ? null : $signature['code'], 'openid' => empty($signature['openid']) ? null : $signature['openid'], 'timestamp' => $signature['timestamp'], 'nonce_str' => $signature['nonce_str'], 'signature' => $signature['signature'], 'plaintext' => $signature['plaintext'], ) ); } } exit(json_encode(array_slice($data, 0, 5))); // 官方:只能一次领5张,超出报错 } exit(json_encode($result)); // 输出错误 } exit(json_encode('获取Token失败')); } function curl_get($url) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 跳过验证证书 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); // 跳过验证主机 curl_setopt($curl, CURLOPT_HEADER, false); //curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-type: application/json;charset=\'utf-8\'')); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $data = curl_exec($curl); curl_close($curl); return ($data === FALSE) ? null : json_decode($data, true); } function curl_jsonPost($url, $data) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 跳过验证证书 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); // 跳过验证主机 curl_setopt($curl, CURLOPT_HEADER, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE)); $data = curl_exec($curl); curl_close($curl); return ($data === FALSE) ? null : json_decode($data, true); } function WxPublic_AccessToken($appid, $secret) { static $cache = array(); $name = strtoupper('__ACCESSTOKEN_' . sha1($appid . $secret) . '__'); $data = isset($cache[$name]) ? $cache[$name] : null; if($data == null || $data['expires_datetime'] <= time()) { $data = curl_get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appid . '&secret=' . $secret); $data['expires_datetime'] = time() + intval($data['expires_in'] * 0.9); // 提前过期 $cache[$name] = $data; } return $data; /* $name = strtoupper('__ACCESSTOKEN_' . sha1($appid . $secret) . '__'); $data = isset($_COOKIE[$name]) ? json_decode($_COOKIE[$name], true) : null; if($data == null || $data['expires_datetime'] <= time()) { $data = curl_get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appid . '&secret=' . $secret); $data['expires_datetime'] = time() + intval($data['expires_in'] * 0.9); // 提前过期 setcookie($name, json_encode($data), $data['expires_datetime'], '/', $_SERVER['HTTP_HOST']); } return $data; */ /* static $cache = array(); $key = sha1($appid . $secret); if(!isset($cache[$key]) || $cache[$key]['expires_datetime'] <= time()) { $cache[$key] = curl_get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appid . '&secret=' . $secret); $cache[$key]['expires_datetime'] = time() + intval($cache[$key]['expires_in'] * 0.9); // 提前过期 } return $cache[$key]; */ } function WxPublic_Card_Uploadimg($publicToken, $file_path) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, 'https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=' . $publicToken); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 跳过验证证书 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); // 跳过验证主机 curl_setopt($curl, CURLOPT_HEADER, false); // curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-type: application/json;charset=\'utf-8\'')); // 注意http头,发送失败也是一个原因,这个是个失败案例 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $aPath = realpath($file_path); if (class_exists('\CURLFile')) { curl_setopt($curl, CURLOPT_SAFE_UPLOAD, true); $data = array('buffer' => new \CURLFile($aPath)); // >= 5.5 } else { if (defined('CURLOPT_SAFE_UPLOAD')) curl_setopt($curl, CURLOPT_SAFE_UPLOAD, false); $data = array('buffer' => '@' . $aPath); // <= 5.5 } if(!empty($data)) { curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); } $data = curl_exec($curl); curl_close($curl); return ($data === FALSE) ? null : json_decode($data, true); } function WxPublic_Card_Create_Groupon($publicToken, $logoUrl, $brandName, $title, $servicePhone, $description, $beginDatetime, $endDatetime, $dealDetail = '', $getLimit = 1, $useLimit = 50, $canShare = true, $canGiveFriend = true) { $url = 'https://api.weixin.qq.com/card/create?access_token=' . $publicToken; $data = array( 'card' => array( 'card_type' => 'GROUPON', 'groupon' => array( 'base_info' => array( 'logo_url' => $logoUrl, // 300*300 'brand_name' => $brandName, 'code_type' => 'CODE_TYPE_QRCODE', 'title' => $title, 'color' => 'Color010', 'notice' => '使用时向服务员出示此券', 'service_phone' => $servicePhone, 'description' => str_replace(array('\r\n', '\r', '\n'), chr(13) . chr(10), $description), 'date_info' => array( 'type' => 'DATE_TYPE_FIX_TIME_RANGE', 'begin_timestamp' => strtotime($beginDatetime), 'end_timestamp' => strtotime($endDatetime) ), 'sku' => array( 'quantity' => 0 ), 'get_limit' => $getLimit, 'use_limit' => $useLimit, 'bind_openid' => false, 'can_share' => !!$canShare, 'can_give_friend' => !!$canGiveFriend, // GET_CUSTOM_CODE_MODE_DEPOSIT用法,参考:https://blog.csdn.net/u011738153/article/details/50457167 'use_custom_code' => true, 'get_custom_code_mode' => 'GET_CUSTOM_CODE_MODE_DEPOSIT', ), 'deal_detail' => str_replace(array('\r\n', '\r', '\n'), chr(13) . chr(10), $dealDetail) ) ) ); return curl_jsonPost($url, $data); /* if($card['errcode'] == '0' && isset($card['card_id'])) { if(count($codes) > 0) { $codeResult = WxPublic_Card_AddCode($publicToken, $card['card_id'], $codes); if($codeResult['errcode'] == '0') { $countResult = WxPublic_Card_CodeCount($publicToken, $card['card_id']); if($countResult['errcode'] == '0' && intval($countResult['count']) > 0) WxPublic_Card_ModifyStock($publicToken, $card['card_id'], intval($countResult['count'])); else throw new Exception('卡券修改库存失败:' . json_encode($countResult)); } else { throw new Exception('卡券添加code失败:' . json_encode($codeResult)); } } return $card['card_id']; } throw new Exception('创建卡券失败:' . json_encode($card)); */ } function WxPublic_Card_Create_Cash($publicToken, $logoUrl, $brandName, $servicePhone, $description, $beginDatetime, $endDatetime, $reduceCost, $leastCost = 0, $getLimit = 1, $useLimit = 50, $canShare = true, $canGiveFriend = true) { $url = 'https://api.weixin.qq.com/card/create?access_token=' . $publicToken; $data = array( 'card' => array( 'card_type' => 'CASH', 'cash' => array( 'base_info' => array( 'logo_url' => $logoUrl, 'brand_name' => $brandName, 'code_type' => 'CODE_TYPE_QRCODE', 'color' => 'Color070', 'notice' => '使用时向服务员出示此券', 'service_phone' => $servicePhone, 'description' => str_replace(array('\r\n', '\r', '\n'), chr(13) . chr(10), $description), 'date_info' => array( 'type' => 'DATE_TYPE_FIX_TIME_RANGE', 'begin_timestamp' => strtotime($beginDatetime), 'end_timestamp' => strtotime($endDatetime) ), 'sku' => array( 'quantity' => 0 ), 'get_limit' => $getLimit, 'use_limit' => $useLimit, 'bind_openid' => false, 'can_share' => !!$canShare, 'can_give_friend' => !!$canGiveFriend, // GET_CUSTOM_CODE_MODE_DEPOSIT用法,参考:https://blog.csdn.net/u011738153/article/details/50457167 'use_custom_code' => true, 'get_custom_code_mode' => 'GET_CUSTOM_CODE_MODE_DEPOSIT', ), 'least_cost' => $leastCost, 'reduce_cost' => $reduceCost, ) ) ); return curl_jsonPost($url, $data); } function WxPublic_Card_Create_Discount($publicToken, $logoUrl, $brandName, $title, $servicePhone, $description, $beginDatetime, $endDatetime, $discount, $getLimit = 1, $useLimit = 50, $canShare = true, $canGiveFriend = true) { $url = 'https://api.weixin.qq.com/card/create?access_token=' . $publicToken; $data = array( 'card' => array( 'card_type' => 'DISCOUNT', 'discount' => array( 'base_info' => array( 'logo_url' => $logoUrl, 'brand_name' => $brandName, 'code_type' => 'CODE_TYPE_QRCODE', 'title' => $title, 'color' => 'Color030', 'notice' => '使用时向服务员出示此券', 'service_phone' => $servicePhone, 'description' => str_replace(array('\r\n', '\r', '\n'), chr(13) . chr(10), $description), 'date_info' => array( 'type' => 'DATE_TYPE_FIX_TIME_RANGE', 'begin_timestamp' => strtotime($beginDatetime), 'end_timestamp' => strtotime($endDatetime) ), 'sku' => array( 'quantity' => 0 ), 'get_limit' => $getLimit, 'use_limit' => $useLimit, 'use_custom_code' => false, 'bind_openid' => false, 'can_share' => !!$canShare, 'can_give_friend' => !!$canGiveFriend, // GET_CUSTOM_CODE_MODE_DEPOSIT用法,参考:https://blog.csdn.net/u011738153/article/details/50457167 'use_custom_code' => true, 'get_custom_code_mode' => 'GET_CUSTOM_CODE_MODE_DEPOSIT', ), 'discount' => $discount ) ) ); return curl_jsonPost($url, $data); } function WxPublic_Card_Create_Gift($publicToken, $logoUrl, $brandName, $title, $servicePhone, $description, $beginDatetime, $endDatetime, $gift = '', $getLimit = 1, $useLimit = 50, $canShare = true, $canGiveFriend = true) { $url = 'https://api.weixin.qq.com/card/create?access_token=' . $publicToken; $data = array( 'card' => array( 'card_type' => 'GIFT', 'gift' => array( 'base_info' => array( 'logo_url' => $logoUrl, 'brand_name' => $brandName, 'code_type' => 'CODE_TYPE_QRCODE', 'title' => $title, 'color' => 'Color050', 'notice' => '使用时向服务员出示此券', 'service_phone' => $servicePhone, 'description' => str_replace(array('\r\n', '\r', '\n'), chr(13) . chr(10), $description), 'date_info' => array( 'type' => 'DATE_TYPE_FIX_TIME_RANGE', 'begin_timestamp' => strtotime($beginDatetime), 'end_timestamp' => strtotime($endDatetime) ), 'sku' => array( 'quantity' => 0 ), 'get_limit' => $getLimit, 'use_limit' => $useLimit, 'bind_openid' => false, 'can_share' => !!$canShare, 'can_give_friend' => !!$canGiveFriend, // GET_CUSTOM_CODE_MODE_DEPOSIT用法,参考:https://blog.csdn.net/u011738153/article/details/50457167 'use_custom_code' => true, 'get_custom_code_mode' => 'GET_CUSTOM_CODE_MODE_DEPOSIT', ), 'gift' => str_replace(array('\r\n', '\r', '\n'), chr(13) . chr(10), $gift) ) ) ); return curl_jsonPost($url, $data); } function WxPublic_Card_Create_GeneralCoupon($publicToken, $logoUrl, $brandName, $title, $servicePhone, $description, $beginDatetime, $endDatetime, $defaultDetail = '', $getLimit = 1, $useLimit = 50, $canShare = true, $canGiveFriend = true) { $url = 'https://api.weixin.qq.com/card/create?access_token=' . $publicToken; $data = array( 'card' => array( 'card_type' => 'GENERAL_COUPON', 'general_coupon' => array( 'base_info' => array( 'logo_url' => $logoUrl, 'brand_name' => $brandName, 'code_type' => 'CODE_TYPE_QRCODE', 'title' => $title, 'color' => 'Color090', 'notice' => '使用时向服务员出示此券', 'service_phone' => $servicePhone, 'description' => str_replace(array('\r\n', '\r', '\n'), chr(13) . chr(10), $description), 'date_info' => array( 'type' => 'DATE_TYPE_FIX_TIME_RANGE', 'begin_timestamp' => strtotime($beginDatetime), 'end_timestamp' => strtotime($endDatetime) ), 'sku' => array( 'quantity' => 0 ), 'get_limit' => $getLimit, 'use_limit' => $useLimit, 'bind_openid' => false, 'can_share' => !!$canShare, 'can_give_friend' => !!$canGiveFriend, // GET_CUSTOM_CODE_MODE_DEPOSIT用法,参考:https://blog.csdn.net/u011738153/article/details/50457167 'use_custom_code' => true, 'get_custom_code_mode' => 'GET_CUSTOM_CODE_MODE_DEPOSIT', ), 'default_detail' => str_replace(array('\r\n', '\r', '\n'), chr(13) . chr(10), $defaultDetail) ) ) ); return curl_jsonPost($url, $data); } function WxPublic_Card_AddCode($publicToken, $cardId, $codes) { $url = 'http://api.weixin.qq.com/card/code/deposit?access_token=' . $publicToken; $data = array( 'card_id' => $cardId, 'code' => $codes ); return curl_jsonPost($url, $data); } function WxPublic_Card_CodeCount($publicToken, $cardId) { $url = 'http://api.weixin.qq.com/card/code/getdepositcount?access_token=' . $publicToken; $data = array( 'card_id' => $cardId ); return curl_jsonPost($url, $data); } function WxPublic_Card_ModifyStock($publicToken, $cardId, $increase = 0, $reduce = 0) { $url = 'https://api.weixin.qq.com/card/modifystock?access_token=' . $publicToken; $data = array( 'card_id' => $cardId, 'increase_stock_value' => $increase, 'reduce_stock_value' => $reduce, ); return curl_jsonPost($url, $data); } function WxPublic_Card_CheckCode($publicToken, $cardId, $codes) { $url = 'http://api.weixin.qq.com/card/code/checkcode?access_token=' . $publicToken; $data = array( 'card_id' => $cardId, 'code' => $codes ); return curl_jsonPost($url, $data); } function WxPublic_Card_BatchGet($publicToken) { $url = 'https://api.weixin.qq.com/card/batchget?access_token=' . $publicToken; $data = array( 'offset' => 0, 'count' => 50, 'status_list' => array( // 'CARD_STATUS_NOT_VERIFY', // 待审核 // 'CARD_STATUS_VERIFY_FAIL', // 审核失败 'CARD_STATUS_VERIFY_OK', // 通过审核 // 'CARD_STATUS_DELETE', // 卡券被商户删除 // 'CARD_STATUS_DISPATCH' // 在公众平台投放过的卡券 ) ); return curl_jsonPost($url, $data); } function WxPublic_Card_Get($publicToken, $cardId) { $url = 'https://api.weixin.qq.com/card/get?access_token=' . $publicToken; $data = array( 'card_id' => $cardId ); return curl_jsonPost($url, $data); } function WxPublic_Card_Delete($publicToken, $cardId) { $url = 'https://api.weixin.qq.com/card/delete?access_token=' . $publicToken; $data = array( 'card_id' => $cardId ); return curl_jsonPost($url, $data); } // 重点:use_custom_code=true和get_custom_code_mode=GET_CUSTOM_CODE_MODE_DEPOSIT时,不需要传code生成(PS:不带code可以一码多人领取) function WxPublic_Card_QrcodeCreate($publicToken, $cardId, $code = '', $openId = '', $outerStr = '') { $url = 'https://api.weixin.qq.com/card/qrcode/create?access_token=' . $publicToken; $data = array( 'action_name' => 'QR_CARD', 'expire_seconds' => 0, 'action_info' => array( 'card' => array( 'card_id' => $cardId, 'code' => $code, 'openid' => $openId, 'is_unique_code' => false, 'outer_str' => $outerStr ) ) ); return curl_jsonPost($url, $data); } // 需要客户领取后才能有数据 function WxPublic_Card_UserCardList($publicToken, $openId, $cardId = '') { $url = 'https://api.weixin.qq.com/card/user/getcardlist?access_token=' . $publicToken; $data = array( 'openid' => $openId, 'card_id' => $cardId ); return curl_jsonPost($url, $data); } // 需要客户领取后才能查询 function WxPublic_Card_CodeGet($publicToken, $cardId, $code) { $url = 'https://api.weixin.qq.com/card/code/get?access_token=' . $publicToken; $data = array( 'card_id' => $cardId, 'code' => $code, 'check_consume' => true ); return curl_jsonPost($url, $data); } // 需要客户领取后才能核销 function WxPublic_Card_CodeConsume($publicToken, $cardId, $code) { $url = 'https://api.weixin.qq.com/card/code/consume?access_token=' . $publicToken; $data = array( 'card_id' => $cardId, 'code' => $code ); return curl_jsonPost($url, $data); } // 需要客户领取后才能失效,已使用的不能失效 function WxPublic_Card_CodeUnavailable($publicToken, $cardId, $code, $reason = '') { $url = 'https://api.weixin.qq.com/card/code/unavailable?access_token=' . $publicToken; $data = array( 'card_id' => $cardId, 'code' => $code, 'reason' => $reason ); return curl_jsonPost($url, $data); } /* // 失败 function WxPublic_Card_CodeUpdate($publicToken, $code, $new_code, $cardId = null) { $url = 'https://api.weixin.qq.com/card/code/update?access_token=' . $publicToken; $data = array( 'card_id' => $cardId, 'code' => $code, 'new_code' => $new_code, ); return curl_jsonPost($url, $data); } */ // $beginDate必须是<=62,$endDate必须是小于今天 function WxPublic_Card_BizuinInfo($publicToken, $beginDate, $endDate, $condSource) { $url = 'https://api.weixin.qq.com/datacube/getcardbizuininfo?access_token=' . $publicToken; $data = array( 'begin_date' => $beginDate, 'end_date' => $endDate, 'cond_source' => $condSource ); return curl_jsonPost($url, $data); } function WxPublic_Card_CardInfo($publicToken, $beginDate, $endDate, $condSource, $cardId = null) { $url = 'https://api.weixin.qq.com/datacube/getcardcardinfo?access_token=' . $publicToken; $data = array( 'begin_date' => $beginDate, 'end_date' => $endDate, 'cond_source' => $condSource, 'card_id' => $cardId ); return curl_jsonPost($url, $data); } function WxPublic_Card_CodeDecrypt($publicToken, $encryptCode) { $url = 'https://api.weixin.qq.com/card/code/decrypt?access_token=' . $publicToken; $data = array( 'encrypt_code' => $encryptCode ); return curl_jsonPost($url, $data); } // ======================================== function WxJsApi_GetTicket($publicToken, $type) { static $cache = array(); $name = strtoupper('__TICKET_' . sha1($publicToken . $type) . '__'); $data = isset($cache[$name]) ? $cache[$name] : null; if($data == null || $data['expires_datetime'] <= time()) { // jsapi:jsapi_ticket // wx_card:api_ticket $data = curl_get('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . $publicToken . '&type=' . $type); $data['expires_datetime'] = time() + intval($data['expires_in']); $cache[$name] = $data; } return $data; } // ======================================== // 权限签名算法 // ======================================== // 签名生成规则如下: // 参与签名的字段包括有效的 // jsapi_ticket:获取方式详见微信JSSDK文档 // noncestr:随机字符串,由开发者随机生成 // timestamp:由开发者生成的当前时间戳) // url:当前网页的URL,不包含#及其后面部分。注意:对于没有只有域名没有path的URL,浏览器会自动加上/作为path // 对所有待签名参数按照字段名的ASCII码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符 // 接下来对string1作sha1加密,字段名和字段值都采用原始值,不进行URL转义。即signature=sha1(string1) function Wx_AuthoritySignature($publicToken, $url) { $ticket = WxJsApi_GetTicket($publicToken, 'jsapi'); if($ticket != null && $ticket['expires_datetime'] >= time()) { static $cache = array(); $name = strtoupper('__AUTHORITYSIGNATURE_' . sha1($ticket['ticket'] . $url) . '__'); $data = isset($cache[$name]) ? $cache[$name] : null; if($data == null || $ticket['expires_datetime'] <= time()) { $input = array( 'jsapi_ticket' => $ticket['ticket'], 'noncestr' => sha1(uniqid(microtime(true), true)), 'timestamp' => time(), 'url' => $url ); $data = array( 'appid' => APPID, 'noncestr' => $input['noncestr'], 'timestamp' => $input['timestamp'], 'signature' => sha1('jsapi_ticket=' . $input['jsapi_ticket'] . '&noncestr=' . $input['noncestr'] . '×tamp=' . $input['timestamp'] . '&url=' . $input['url']), // 必须按小写字段名升序排序 //'plaintext' => 'jsapi_ticket=' . $input['jsapi_ticket'] . '&noncestr=' . $input['noncestr'] . '×tamp=' . $input['timestamp'] . '&url=' . $input['url'], ); $cache[$name] = $data; } return $data; } return null; } // ======================================== // 卡券签名算法 // ======================================== // 重点:use_custom_code=true和get_custom_code_mode=GET_CUSTOM_CODE_MODE_DEPOSIT时,不需要传code进行签名 // 重点:code和openid是空字符串时,只能传null或不传给wx.addCard,否则报出参数错误 function Wx_CardSignature($publicToken, $cardId, $code = '', $openId = '') { $ticket = WxJsApi_GetTicket($publicToken, 'wx_card'); if($ticket != null && $ticket['expires_datetime'] >= time()) { static $cache = array(); $name = strtoupper('__CARDSIGNATURE_' . sha1($ticket['ticket'] . $cardId . $code . $openId) . '__'); $data = isset($cache[$name]) ? $cache[$name] : null; if($data == null || $ticket['expires_datetime'] <= time()) { $input = array( 'api_ticket' => $ticket['ticket'], 'timestamp' => time(), 'nonce_str' => sha1(uniqid(microtime(true), true)), 'card_id' => $cardId, 'code' => strval($code), 'openid' => $openId, ); asort($input, SORT_STRING); // 按键值升序排序 $data = array( 'api_ticket' => $input['api_ticket'], 'timestamp' => $input['timestamp'], 'nonce_str' => $input['nonce_str'], 'card_id' => $input['card_id'], 'code' => (!isset($input['code']) || empty($input['code'])) ? null : $input['code'], 'openid' => (!isset($input['openid']) || empty($input['openid'])) ? null : $input['openid'], 'signature' => sha1(implode('', $input)), //'plaintext' => implode(';', $input), ); $cache[$name] = $data; } return $data; } return null; }
前端代码:
<!doctype html> <html class="w-100 h-100"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0, shrink-to-fit=no" /> <meta name="format-detection" content="telephone=no" /> <title>测试</title> </head> <body> <script type="text/javascript" src="{$_W['siteroot']}app/resource/pad/js/jquery-3.3.1.min.js"></script> <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script> <script type="text/javascript"> // https://www.cnblogs.com/ka-bu-qi-nuo/p/8659688.html $(function() { $.ajax({ url: '{url "pad/store_pad/wx_authority_signature" array("store" => $_GPC["store"])}', type: 'GET', dataType: 'json', data: { 'url': encodeURIComponent(window.location.href.split('#')[0]) // 获取最新url }, success: function(signData) { wx.config({ debug: true, // true时,即使正确也会提示签名无效,这是官方bug appId: signData.appid, timestamp: signData.timestamp, nonceStr: signData.noncestr, signature: signData.signature, jsApiList: [ // 'updateAppMessageShareData', // 'updateTimelineShareData', // 'onMenuShareTimeline', // 即将废弃 // 'onMenuShareAppMessage', // 即将废弃 // 'onMenuShareQQ', // 即将废弃 // 'onMenuShareWeibo', // 'onMenuShareQZone', // 'startRecord', // 'stopRecord', // 'onVoiceRecordEnd', // 'playVoice', // 'pauseVoice', // 'stopVoice', // 'onVoicePlayEnd', // 'uploadVoice', // 'downloadVoice', // 'chooseImage', // 'previewImage', // 'uploadImage', // 'downloadImage', // 'translateVoice', // 'getNetworkType', // 'openLocation', // 'getLocation', // 'hideOptionMenu', // 'showOptionMenu', // 'hideMenuItems', // 'showMenuItems', // 'hideAllNonBaseMenuItem', // 'showAllNonBaseMenuItem', // 'closeWindow', // 'scanQRCode', // 'chooseWXPay', // 'openProductSpecificView', 'addCard', // 'chooseCard', // 'openCard', ] }); wx.ready(function() { wx.checkJsApi({ jsApiList: ['addCard'], success: function(res1) { //alert(JSON.stringify(res1)); if(res1.checkResult.addCard) { $.ajax({ url: '{url "pad/store_pad/wx_getcard" array("store" => $_GPC["store"])}', type: 'GET', dataType: 'json', success: function(signData2) { if(typeof(signData2['errcode']) === 'undefined' || signData2['errcode'] == '0') { var cardList = []; for(var i = 0; i < signData2.length; ++i) { cardList.push({ cardId: signData2[i].card_id, cardExt: JSON.stringify({ // 全部字段赋上,别管有没有值 code: signData2[i].card_ext.code, openid: signData2[i].card_ext.openid, timestamp: signData2[i].card_ext.timestamp, nonce_str: signData2[i].card_ext.nonce_str, signature: signData2[i].card_ext.signature }) }); } if(cardList.length > 0) { wx.addCard({ cardList: cardList, // 需要添加的卡券列表 success: function (res2) { var cardList = res2.cardList; // 添加的卡券列表信息 alert(JSON.stringify(cardList)); } }); } } else { alert('获取失败\r\nCode:' + signData2['errcode'] + '\r\nMessage:' . signData2['errmsg']); } } }); } else { alert('不支持addCard!'); } } }); /* wx.checkJsApi({ jsApiList: ['scanQRCode'], success: function(res) { //alert(JSON.stringify(res)); if(res.checkResult.scanQRCode) { alert('支持scanQRCode'); } else { alert('不支持scanQRCode!'); } } }); wx.checkJsApi({ jsApiList: [ 'updateAppMessageShareData', 'updateTimelineShareData', ], success: function(res) { //alert(JSON.stringify(res)); if(res.checkResult.updateAppMessageShareData) { alert('支持分享到朋友/QQ'); / * wx.updateAppMessageShareData({ title: '分享标题', desc: '分享描述', link: signData.url, imgUrl: '{$_W["siteroot"]}favicon.png', success: function () { alert('分享到朋友/QQ成功'); } }); * / } else { alert('不支持分享到朋友/QQ'); } if(res.checkResult.updateAppMessageShareData) { alert('支持分享到朋友圈/QQ空间'); / * wx.updateTimelineShareData({ title: '分享标题', link: signData.url, imgUrl: '{$_W["siteroot"]}favicon.png', success: function () { alert('分享到朋友圈/QQ空间成功'); } }); * / } else { alert('不支持分享到朋友圈/QQ空间'); } } }); wx.checkJsApi({ jsApiList: ['openCard'], success: function(res) { //alert(JSON.stringify(res)); if(res.checkResult.openCard) { alert('支持openCard!'); } else { alert('不支持openCard!'); } } }); */ }); wx.error(function(res) { alert('初始化失败!'); }); } }); }); </script> <script type="text/javascript"> /** * @param {String} errorMessage 错误信息 * @param {String} scriptURI 出错的文件 * @param {Long} lineNumber 出错代码的行号 * @param {Long} columnNumber 出错代码的列号 * @param {Object} errorObj 错误的详细信息,Anything */ window.onerror = function(errorMessage, scriptURI, lineNumber, columnNumber, errorObj) { var msg = ''; var CRLF = String.fromCharCode(13) + String.fromCharCode(10); msg += '错误信息:' + errorMessage + CRLF; msg += '出错文件:' + scriptURI + '(' + lineNumber + ',' + columnNumber + ')' + CRLF; msg += '错误详情:' + errorObj; alert(msg); } </script> </body> </html>
个性签名:做要做好,做到不三不四不如不做。