ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
**开发之前配置篇:** 一、登陆公众号平台(https://mp.weixin.qq.com),点击设置-》公众号设置-》功能设置-》JS接口安全域名 (这里设置你网站的根域名),主意要将下载的文件放到你的网络根域名设置的路径下,不然会提示设置不成功。 二、登陆公众号平台(https://mp.weixin.qq.com),点击设置-》公众号设置-》功能设置-》网页授权域名 (这里设置你网站的根域名),作用是为了获取微信服务器的code,说明白一点就是微信的验证。 三、登陆公众号平台(https://mp.weixin.qq.com),点击微信支付-》开发配置-》支付授权目录(这里面要设置到你要访问具体方法的那个控制器,并且以反斜杠结束,如果是做分享,这步可以跳过)。 四、设置Api密匙:登陆商户平台(https://pay.weixin.qq.com/),账户中心-》API安全(这里要下载安装操作证书,才可以设置Api密匙) 四、 **开发之前获取参数篇:** 一、获取原始Id:登陆公众号平台(https://mp.weixin.qq.com),点击设置-》公众号设置-》账号详情,拉到底就见这个值。 二、获取商户号:登陆公众号平台(https://mp.weixin.qq.com),点击微信支付-》商户信息,这里就可见这个值。 三、应用Id:登陆公众号平台(https://mp.weixin.qq.com),点击开发-》基本配置,即可看见这个值 四、应用密匙:登陆公众号平台(https://mp.weixin.qq.com),点击开发-》基本配置,即可看见这个值(需要短信验证和授权) 五、Api密匙:登陆商户平台(https://pay.weixin.qq.com/),账户中心-》API安全(这里要下载安装操作证书,才可以查看Api密匙,同时还要下载这里面的操作证书到你的网站中,文件夹名称一般为cert) **准备之后开发微信分享后台代码篇** 只需调用getSignPackage传入公众号配置信息,和缓存的信息即可。 这里特别要主要分享的页面必须是和我们现在当前页面的URL是一致的,不然签名会出现错误 public function getSignPackage($config,$weixinConfig) { $jsapiTicket = $this->getJsApiTicket($config,$weixinConfig); // 注意 URL 一定要动态获取,不能 hardcode. $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://"; $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; // $url = $_GET['url']; $timestamp = time(); $nonceStr = $this->createNonceStr(); // 这里参数的顺序要按照 key 值 ASCII 码升序排序 $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url"; $signature = sha1($string); $signPackage = array( "appId" => $config['appId'], "nonceStr" => $nonceStr, "timestamp" => $timestamp, "url" => $url, "signature" => $signature, "rawString" => $string ); return $signPackage; } 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($config,$weixinConfig) { // jsapi_ticket 应该全局存储与更新,以下代码以写入到数据库中做示例 // https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi //return 'sM4AOVdWfPE4DxkXGEs8VMSQstUYjbUtfFD4m78lNEyU_NEJkjLLJlzrfdKU-x_JPDdAS-jbru9EmpFHy2Omvw'; $access_token = $this->getAccessToken($config,$weixinConfig); if (UTC_TIME + 1800 < $weixinConfig['jsapi_ticket_expired']) { $jsapi_ticket = $weixinConfig['jsapi_ticket']; } else { $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='.$access_token.'&type=jsapi'; $jsapi_json = Http::get($url); $jsapi_json = empty($jsapi_json) ? false : @json_decode($jsapi_json, true); if(!$jsapi_json || empty($jsapi_json['ticket'])){ return false; } $jsapi_ticket = $jsapi_json['ticket']; SystemConfigService::updateConfig('jsapi_ticket', $jsapi_ticket); SystemConfigService::updateConfig('jsapi_ticket_expired', UTC_TIME + (int)$jsapi_json['expires_in']); } return $jsapi_ticket; } private function getAccessToken($config,$weixinConfig) { if (UTC_TIME + 1800 < $weixinConfig['access_token_expired']) { $access_token = $weixinConfig['access_token']; } else { $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $config['appId'] . '&secret=' .$config['appSecret']; $token_json = Http::get($url); $token_json = empty($token_json) ? false : @json_decode($token_json, true); if(!$token_json || empty($token_json['access_token'])){ return false; } $access_token = $token_json['access_token']; SystemConfigService::updateConfig('access_token', $access_token); SystemConfigService::updateConfig('access_token_expired', UTC_TIME + (int)$token_json['expires_in']); } return $access_token; } ** 准备之后开发微信分享前端代码篇:** <script type="text/javascript" src="{{ asset('wap/community/newclient/js/jweixin-1.0.0.js') }}"></script> <script type="text/javascript"> //初始化微信配置 wx.config({ debug: false, // 关闭调试模式 appId: "{{ $data['appId'] }}", // 必填,公众号的唯一标识 timestamp: "{{ $data['timestamp'] }}", // 必填,生成签名的时间戳 nonceStr: "{{ $data['nonceStr'] }}", // 必填,生成签名的随机串 signature: "{{ $data['signature'] }}",// 必填,签名 jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage'] // 必填,需要使用的JS接口列表 }); wx.ready(function(){ $(".sha-frame").click(function(){ $(this).addClass('none'); }); // 分享给朋友 wx.onMenuShareAppMessage({ title: "{{ $share['share_title'] }}", // 分享标题 desc:"{{ $share['share_conten'] }}", // 分享描述 link: location.href, // 分享链接 imgUrl: 'img.png', // 分享图标 type: 'link', // 分享类型,music、video或link,不填默认为link dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空 success: function () { // 用户确认分享后执行的回调函数 }, cancel: function () { // 用户取消分享后执行的回调函数 } }); // 分享到朋友圈 wx.onMenuShareTimeline({ title: "{{ $share['share_title'] }}", // 分享标题 desc:"{{ $share['share_conten'] }}", // 分享描述 link: location.href, // 分享链接 imgUrl: 'img.png', // 分享图标 success: function () { // 用户确认分享后执行的回调函数 }, cancel: function () { // 用户取消分享后执行的回调函数 } }); }); </script> **准备之后微信支付后台代码篇:** 首先判断wxpay_open_id是否存在(wxpay_open_id存在session中),没有存在就去请求微信接口,获取回来。然后调用staffweixinJsPay,传入必要参数,调用后的结果集绑定到前端页面中。 <?php namespace YiZan\Http\Controllers\Wap; use Session, Redirect; /** * 微信控制器 */ class WeixinController extends BaseController { public function authorize(){ $url = urldecode($_REQUEST['url']); // file_put_contents(storage_path().DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.'zhifu.log',date('Y-m-d H:i:s',time())."\n"."2"."\n",FILE_APPEND); $flage = $_REQUEST['flage']; if(!$flage){ if (empty($url)) { return $this->error('参数错误'); } } $result = $this->requestApi('config.getpayment',['code' => 'weixinJs']); if (!$result || $result['code'] != 0) { return $this->error('获取微信配置信息失败', $url); } $payment = $result['data']; $config = $payment['config']; Session::set('authorize_return_url', $url); Session::save(); $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$config['appId']. '&redirect_uri='.urlencode(u('Weixin/accesstoken',['flage'=>$flage])) .'&response_type=code&scope=snsapi_base&state=YZ#wechat_redirect'; // file_put_contents('/mnt/www/fanwewb8/storage/logs/ceshi.log',date('Y-m-d H:i:s',time()).$url."\n",FILE_APPEND); return Redirect::to($url); } public function accesstoken() { $code = $_REQUEST['code']; // file_put_contents(storage_path().DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.'zhifu.log',date('Y-m-d H:i:s',time())."\n"."3 $code"."\n",FILE_APPEND); $flage = $_REQUEST['flage']; if($flage){ $url = "http://staff.wai8.fanwe.net/Weixin/accesstoken?code={$code}"; Header("Location: $url"); exit(); } $url = Session::get('authorize_return_url'); if (empty($code)) { return $this->error('授权失败', $url); } $result = $this->requestApi('config.getpayment',['code' => 'weixinJs']); if (!$result || $result['code'] != 0) { return $this->error('获取微信配置信息失败', $url); } $payment = $result['data']; $config = $payment['config']; $wxurl = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$config['appId']. '&secret='.$config['appSecret'].'&code='.$code.'&grant_type=authorization_code'; $result = @file_get_contents($wxurl); $result = empty($result) ? false : @json_decode($result, true); if (!$result) { return $this->error('授权失败', $url); } elseif (isset($result['errcode']) && $result['errcode'] != 0) { return $this->error('授权失败:'.$result['errmsg'], $url); } $openid = $result['openid']; $url = $url.'&openId='.$openid; return Redirect::to($url); } } //商户微信JS支付 public function staffweixinJsPay($userPayLog, $payment, $extend ) { //$payment = array('appId','partnerId','partnerKey'); //$userPayLog= array('content','sn','money') //$extend=array('openId') // var_dump($userPayLog,$payment,$extend);die; $config = $payment; $money = $userPayLog['money']; //$sellerId, $money, $sn if(!$this->createSellerPayLog1($extend['seller_id'],$money,$userPayLog['sn'])){ return false; } // return $config; $order_data = array( 'appid' => $config['appId'],// 'body' => $userPayLog['content'],// 'mch_id' => $config['partnerId'],// 'nonce_str' => md5(String::randString(16)), 'notify_url' => Config::get('app.callback_url').'Payment/StaffWeixin/jsnotify', 'openid' => $extend['openId'],// 'out_trade_no' => $userPayLog['sn'],// 'spbill_create_ip' => CLIENT_IP, 'total_fee' => round($money * 100),// 'trade_type' => 'JSAPI' ); // return array($money,$order_data['total_fee']); $xml = '<xml>'; $sign = ''; foreach ($order_data as $key => $data) { if ($key == 'body') { $xml .= "\n<{$key}><![CDATA[{$data}]]></{$key}>"; } else { $xml .= "\n<{$key}>{$data}</{$key}>"; } $sign .= "{$key}={$data}&"; } $sign = strtoupper(md5("{$sign}key={$config['partnerKey']}")); $xml .= "\n<sign>{$sign}</sign>\n</xml>"; file_put_contents(storage_path().DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.'zhifu.log',date('Y-m-d H:i:s',time())."\n".$xml."\n",FILE_APPEND); // return $xml; $response = Http::post('https://api.mch.weixin.qq.com/pay/unifiedorder', $xml);//统一下单 // file_put_contents(storage_path().DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.'zhifu.log',date('Y-m-d H:i:s',time())."\n".$response."\n",FILE_APPEND); // return $response; if (empty($response)) { return false; } $response = @simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA); if (!$response || !isset($response->return_code) || $response->return_code != 'SUCCESS') { return false; } $weixinConfig = SystemConfigService::getConfigByGroup('weixin'); if (UTC_TIME + 1800 < $weixinConfig['access_token_expired']) { $access_token = $weixinConfig['access_token']; } else { $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $config['appId'] . '&secret=' .$config['appSecret']; $token_json = Http::get($url); $token_json = empty($token_json) ? false : @json_decode($token_json, true); if(!$token_json || empty($token_json['access_token'])){ return false; } $access_token = $token_json['access_token']; SystemConfigService::updateConfig('access_token', $access_token); SystemConfigService::updateConfig('access_token_expired', UTC_TIME + (int)$token_json['expires_in']); } if (UTC_TIME + 1800 < $weixinConfig['jsapi_ticket_expired']) { $jsapi_ticket = $weixinConfig['jsapi_ticket']; } else { $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='.$access_token.'&type=jsapi'; $jsapi_json = Http::get($url); $jsapi_json = empty($jsapi_json) ? false : @json_decode($jsapi_json, true); if(!$jsapi_json || empty($jsapi_json['ticket'])){ return false; } $jsapi_ticket = $jsapi_json['ticket']; SystemConfigService::updateConfig('jsapi_ticket', $jsapi_ticket); SystemConfigService::updateConfig('jsapi_ticket_expired', UTC_TIME + (int)$jsapi_json['expires_in']); } //js-sdk接口配置信息 $jsapi_request = array( 'jsapi_ticket' => $jsapi_ticket, 'noncestr' => md5(String::randString(16)), 'timestamp' => UTC_TIME, 'url' => $extend['url'] ); $jsapi_request['signature'] = self::weixinSign($jsapi_request, '', 'sha1'); $jsapi_request['appId'] = $config['appId']; //支付配置 $pay_request = [ 'appId' => $config['appId'], 'nonceStr' => md5(String::randString(16)), 'package' => 'prepay_id='.$response->prepay_id, 'signType' => 'MD5', 'timeStamp' => UTC_TIME + date('Z') ]; $pay_request['paySign'] = strtoupper(self::weixinSign($pay_request, $config['partnerKey'])); $pay_request['jsapi'] = $jsapi_request; return $pay_request; } ** 准备之后微信支付前端篇:** <script type="text/javascript" src="{{ asset('staff/js/jweixin-1.0.0.js') }}"></script> <script type="text/javascript"> //微信分享配置文件 wx.config({ debug: false, // 调试模式 appId: "{{$pay['appId']}}", // 公众号的唯一标识 timestamp: "{{$pay['jsapi']['timestamp']}}", // 生成签名的时间戳 nonceStr: "{{$pay['jsapi']['noncestr']}}", // 生成签名的随机串 signature: "{{$pay['jsapi']['signature']}}",// 签名 jsApiList: ['checkJsApi','chooseWXPay'] // 需要使用的JS接口列表 }); function callpay() { wx.chooseWXPay({ timestamp: "{{$pay['timeStamp']}}", // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 nonceStr: "{{$pay['nonceStr']}}", // 支付签名随机串,不长于 32 位 package: "{{$pay['package']}}", // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***) signType: "{{$pay['signType']}}", // 签名方式,默认为'SHA1',使用新版支付需传入'MD5' paySign: "{{$pay['paySign']}}", // 支付签名 success: function (res) { alert('支付成功'); location.href = "{{ u('Mine/index') }}"; }, cancel: function (res) { alert('取消支付'); location.href = "{{ u('Mine/index') }}"; }, fail: function (res) { alert('支付失败'); location.href = "{{ u('Mine/index') }}"; } }); } </script>