好久没有更新博客,最近做项目遇到了微信支付,整理一下需求,目的一个活动页面需要调微信支付! 应用框架THINKPHP5.1 注意:微信支付 需要注意 如果是h5页面调取支付的话,需要静默一个登录状态获取code,这样才可以保证支付调取的参数openid正常,这里的坑填了好久,微信内浏览器h5用户输入完手机号登录后,页面存cookie信息,有时候会不更新获取的openid 导致“下单账号和支付账号不一致,请核对”; 微信内浏览器刷新页面用jq执行: window.location.href = location.href+'?time='+((new Date()).getTime()); 直接上代码:前端 function get_form(){ var price1 =$(".get_price1").val(); var price2 =$(".get_price2").val(); var price3 =$(".get_price3").val(); var price4 =$(".get_price4").val(); var pid =$(".pid").val(); var username =$(".username").val(); var mobile =$(".mobile").val(); var address =$(".address").val(); if(!username && !mobile && !address){ layer.alert('收货人信息不能为空'); return false; } $.post("home/get_from",//get_from 是后台请求支付的逻辑 {"price1":price1,"price2":price2,"price3":price3,"price4":price4,"username":username,"mobile":mobile,"address":address,"pid":pid},function(apiConfig){ console.log(apiConfig); var ua = navigator.userAgent.toLowerCase();//获取判断用的对象是微信内还是外部 if (ua.match(/MicroMessenger/i) == "micromessenger") { //内部 WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId":apiConfig.appId, //公众号名称,由商户传入 "timeStamp":apiConfig.timeStamp, //时间戳,自1970年以来的秒数 "nonceStr":apiConfig.nonceStr, //随机串 "package":apiConfig.package, "signType":apiConfig.signType, //微信签名方式: "paySign":apiConfig.paySign //微信签名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ){ window.location.href ="方法路径" } }); if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } }else{ onBridgeReady(); } }else{ //外部 var url="支付成功跳转"; window.location.href =apiConfig.mweb_url+"&redirect_url="+url; } }); } 后端代码: 静默登录 请求页面的时候通过tp5 redirect重置路由 再进入页面的方法里 查找有没有openid $sa = Cookie::get('kj_phone'); $uid =$sa['id'];//用户id $userAgent = $_SERVER['HTTP_USER_AGENT']; // 判断是 公众号支付还是外部网址支付 if (strpos($userAgent, 'MicroMessenger')) { // 公众号支付 $uid =$sa['id'];//用户id $open_id= Cache::get($uid); // print_r($open_id); if(empty($open_id)){ $this->redirect("https://open.weixin.qq.com/connect/oauth2/authorize?appid=Appid&redirect_uri=页面进入后先通过get_open方法获得code获取openid&response_type=code&scope=snsapi_base&state=1#wechat_redirect"); } } get_open方法 public function get_open(){ $code1=empty($_GET['code']) ? '' : $_GET['code']; $sa =Cookie::get('kj_phone'); // $appId ='appId '; //$secret ='secret'; $get_token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=Appid&secret=secre&code=' . $code1 . '&grant_type=authorization_code'; $json_obj = $this->http_request($get_token_url); $json_obj = json_decode($json_obj,true); $openid = empty($json_obj['openid']) ? "" : $json_obj['openid']; $uid =$sa['id'];//用户id Cache::set($uid,$openid,3600); if($code1 == ''){ $this->redirect('重定向到渲染页面'); } if(!empty($open_id)){ $this->redirect('重定向到渲染页面'); }else{ $this->redirect('重定向到渲染页面'); } } get_from: public function get_from(){ if(request()->isPost()){ $data =input("post.");// 前端传过来的数据 自己写逻辑吧 $userAgent = $_SERVER['HTTP_USER_AGENT']; // 判断是 公众号支付还是外部网址支付 if (strpos($userAgent, 'MicroMessenger')) { // 公众号支付 $sa = Cookie::get('kj_phone'); $uid =$sa['id'];//用户id $open_id= Cache::get($uid); //print_r($open_id);exit; $return = $this->weixinapp($open_id,$body,$order_id,$price,$attact); return $return; }else{ $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; $parameters = array( 'appid' => "小程序ID", //小程序ID 'mch_id' => "商户号", //商户号 'attach'=>$attact, 'nonce_str' => $this->createNoncestr(), //随机字符串 'body' =>$body, //商品描述 'out_trade_no' =>$order_id,//商户订单号 'total_fee' => $price * 100, //总金额 单位 分 'spbill_create_ip' => '111111', //终端IP 'notify_url' => '回调地址', //通知地址 确保外网能正常访问 'trade_type' => 'MWEB'//交易类型 ); //统一下单签名 $parameters['sign'] = $this->getSign($parameters); $xmlData = $this->arrayToXml($parameters); $return = $this->xmlToArray($this->postXmlCurl($xmlData, $url, 60)); return $return; } } } } //统一下单接口 private function weixinapp($openid,$body,$orderId,$price,$attact) { $unifiedorder = $this->unifiedorder($openid,$body,$orderId,$price,$attact); $parameters = array( 'appId' => "appId", //小程序ID 'timeStamp' => '' . time() . '', //时间戳 'nonceStr' => $this->createNoncestr(), //随机串 'package' => 'prepay_id=' . $unifiedorder['prepay_id'], //数据包 'signType' => 'MD5'//签名方式 ); //签名 $parameters['paySign'] = $this->getSign($parameters); return $parameters; } //作用:产生随机字符串,不长于32位 private function createNoncestr($length = 32) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str = ""; for ($i = 0; $i < $length; $i++) { $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); } return $str; } private function getSign($Obj) { //halt($Obj); foreach ($Obj as $k => $v) { $Parameters[$k] = $v; } //签名步骤一:按字典序排序参数 ksort($Parameters); $String = $this->formatBizQueryParaMap($Parameters, false); //签名步骤二:在string后加入KEY $String = $String . "&key=d18e10ad06222c972499296f1cefa481" ; //签名步骤三:MD5加密 $String = md5($String); //签名步骤四:所有字符转为大写 $result_ = strtoupper($String); return $result_; } ///作用:格式化参数,签名过程需要使用 private function formatBizQueryParaMap($paraMap, $urlencode) { $buff = ""; ksort($paraMap); foreach ($paraMap as $k => $v) { if ($urlencode) { $v = urlencode($v); } $buff .= $k . "=" . $v . "&"; } $reqPar=""; if (strlen($buff) > 0) { $reqPar = substr($buff, 0, strlen($buff) - 1); } return $reqPar; } //数组转换成xml private function arrayToXml($arr) { $xml = ""; foreach ($arr as $key => $val) { if (is_array($val)) { $xml .= "<" . $key . ">" . arrayToXml($val) . ""; } else { $xml .= "<" . $key . ">" . $val . ""; } } $xml .= ""; return $xml; } //xml转换成数组 private function xmlToArray($xml) { //禁止引用外部xml实体 libxml_disable_entity_loader(true); $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); $val = json_decode(json_encode($xmlstring), true); return $val; } function http_curl($url){//用curl传参 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//关闭ssl验证 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($ch,CURLOPT_HEADER, 0); $output = curl_exec($ch); curl_close($ch); return json_decode($output, true); } private static function postXmlCurl($xml, $url, $second = 30) { $ch = curl_init(); //设置超时 curl_setopt($ch, CURLOPT_TIMEOUT, $second); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验 //设置header curl_setopt($ch, CURLOPT_HEADER, FALSE); //要求结果为字符串且输出到屏幕上 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); //post提交方式 curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20); curl_setopt($ch, CURLOPT_TIMEOUT, 40); set_time_limit(0); //运行curl $data = curl_exec($ch); //返回结果 if ($data) { curl_close($ch); return $data; } else { $error = curl_errno($ch); curl_close($ch); throw new WxPayException("curl出错,错误码:$error"); } } //回调 private function unifiedorder($openid,$body,$orderId,$price,$attact) { $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; $parameters = array( 'appid' => "appid", //小程序ID 'mch_id' =>"mch_id", //商户号 'attach'=>$attact, 'nonce_str' => $this->createNoncestr(), //随机字符串 'body' => $body, 'out_trade_no'=> $orderId, 'total_fee' => $price * 100, 'spbill_create_ip' => '11111111', //终端IP 'notify_url' => 回调, //通知地址 确保外网能正常访问 'openid' => $openid, //用户id 'trade_type' => 'JSAPI'//交易类型 ); //统一下单签名 $parameters['sign'] = $this->getSign($parameters); $xmlData = $this->arrayToXml($parameters); $return = $this->xmlToArray($this->postXmlCurl($xmlData, $url, 60)); return $return; } //回调 public function callback(){ $xml = file_get_contents("php://input"); // 将XML 转换为数组 $xml = json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)); $result = json_decode($xml, true); //如果成功返回 if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){ $where['order_id']=$result['out_trade_no']; $data_e['states']=2; $ud= db('hc_pr_order')->where($where)->update($data_e); } // 给微信的返回值 if ($ud) { $str=''; }else{ $str=''; } return $str; return $result; }