前端开发
1009
首先从小程序端接收订单号、金额等参数,然后后台进行统一下单,把微信支付的订单号返回,在把订单号发送给前台,前台拉起支付,返回参数后更改支付状态。。。
回调
public function notify() { $wechat=Db::name('wechat')->where('status',1)->find(); //$post = $GLOBALS['HTTP_RAW_POST_DATA']; $post = file_get_contents("php://input"); //接受POST数据XML个数 // $order_over_test['openid']=$post; // Db::name('order_over')->insert($order_over_test); $post_data = $this->xml_to_array($post); //输出订单号 $order_sn = $post_data['out_trade_no']; $order_over['order_sn']=$order_sn; $order_over['money']=$post_data['total_fee']; $order_over['openid']=$post_data['openid']; $order_over['time_end']=$post_data['time_end']; $order_update['status']='1'; // Db::name('order_over')->insert($order_over); $order_info=Db::name('order')->where('order_id',$order_sn)->find(); if ($post_data['return_code'] == 'SUCCESS') { //判断证书是否正确 // if ($postSign != $user_sign) { // Log::write('签名不匹配'); // exit; // } if ($order_info['status'] != '1') { Db::name('order_over')->insert($order_over); $result=Db::name('order')->where('order_id', $order_sn)->update($order_update); } return 'success'; } else { return 'error'; //$this->error('error!'); } } public function xmlToArray($xml) { $p = xml_parser_create(); xml_parse_into_struct($p, $xml, $vals, $index); xml_parser_free($p); $data = ""; foreach ($index as $key => $value) { if ($key == 'xml' || $key == 'XML') continue; $tag = $vals[$value[0]]['tag']; $value = $vals[$value[0]]['value']; $data[$tag] = $value; } return $data; } public function xml_to_array($xml){ if(!$xml){ return false; } //将XML转为array //禁止引用外部xml实体 libxml_disable_entity_loader(true); $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $data; } public static function ToUrlParams($data) { $buff = ""; foreach ($data as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff; }
统一下单
public function getwxpay($orderSn,$money) { // $orderSn=$orderSn; $body='广告投放'; //$orderSn='HB14257311281654'; //$money= '1'; $money=$money*100; $wechat=Db::name('wechat')->where('status',1)->find(); $order_id=$orderSn; // $money= $money; //充值金额 微信支付单位为分 $appid = $wechat['appid']; //应用APPID $mch_id =$wechat['mch_id']; //微信支付商户号 $KEY = $wechat['key']; //微信商户API密钥 $out_trade_no = $orderSn ;//平台内部订单号 $nonce_str = $this->rand_code();//随机字符串 // $openid='oM0TH0nyMtlyrP_J8cOL70oLYaCw'; $openid=session('openid'); //获取系统的配置 //$nonce_str = $this->rand_str(12);//随机字符串 $notify_url = "http://**********************t/Wxnotify/notify"; //支付完成回调地址url,不能带参数 $spbill_create_ip = get_client_ip(); $trade_type = 'JSAPI';//交易类型 默认JSAPI //这里是按照顺序的 因为下面的签名是按照(字典序)顺序 排序错误 肯定出错 $post['appid'] = $appid; $post['body'] = $body; $post['mch_id'] = $mch_id; $post['nonce_str'] = $nonce_str;//随机字符串 $post['notify_url'] = $notify_url; $post['openid'] = $openid; $post['out_trade_no'] = $out_trade_no; $post['spbill_create_ip'] = $spbill_create_ip;//服务器终端的ip $post['total_fee'] = intval($money); //总金额 最低为一分钱 必须是整数 $post['trade_type'] = $trade_type; $sign = $this->MakeSign($post, $KEY); //签名 $this->sign = $sign; $post_xml = " <xml> <appid>$appid</appid> <mch_id>$mch_id</mch_id> <nonce_str>$nonce_str</nonce_str> <body>$body</body> <notify_url>$notify_url</notify_url> <openid>$openid</openid> <out_trade_no>$out_trade_no</out_trade_no> <spbill_create_ip>$spbill_create_ip</spbill_create_ip> <total_fee>{$post["total_fee"]}</total_fee> <trade_type>$trade_type</trade_type> <sign>$sign</sign> </xml>"; //统一下单接口prepay_id $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; $xml = $this->http_request($url, $post_xml); //POST方式请求http $array = $this->xml2array($xml); //将【统一下单】api返回xml数据转换成数组,全要大写 $array['my_sign'] = $sign; $array['post_xml'] = $post_xml; $array['source_xml'] = $xml; if ($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS') { $time = time(); $tmp = ''; //临时数组用于签名 $tmp['appId'] = $appid; $tmp['nonceStr'] = $nonce_str; $tmp['package'] = 'prepay_id=' . $array['PREPAY_ID']; $tmp['signType'] = 'MD5'; $tmp['timeStamp'] = "$time"; // $data['state'] = 1; $data['timeStamp'] = "$time"; //时间戳 $data['nonceStr'] = $nonce_str; //随机字符串 $data['signType'] = 'MD5'; //签名算法,暂支持 MD5 $data['package'] = 'prepay_id='.$array['PREPAY_ID']; //统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=* $data['paySign'] = $this->MakeSign($tmp, $KEY); //签名,具体签名方案参见微信公众号支付帮助文档; $data['prepay_id'] = $array['PREPAY_ID']; $data['out_trade_no'] = $out_trade_no; $data['order_id'] = $order_id; } else { // $data['statusCode'] = ; $data['statusMsg'] = "请求错误"; $data['data']['RETURN_CODE'] = $array['RETURN_CODE']; $data['data']['RETURN_MSG'] = $array['RETURN_MSG']; } return $data; } public 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 $data = curl_exec($ch); //返回结果 if($data){ curl_close($ch); return $data; }else{ $error = curl_errno($ch); curl_close($ch); echo "curl出错,错误码:$error"."<br>"; } } //生成签名 public function MakeSign($params, $KEY) { //签名步骤一:按字典序排序数组参数 ksort($params); $string = $this->ToUrlParams($params); //参数进行拼接key=value&k=v //签名步骤二:在string后加入KEY $string = $string . "&key=" . $KEY; //签名步骤三:MD5加密 $string = md5($string); //签名步骤四:所有字符转为大写 $result = strtoupper($string); return $result; } /** * 格式化参数格式化成url参数 */ public static function ToUrlParams($data) { $buff = ""; foreach ($data as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff; } //发送http请求 public function http_request($url, $data = null, $headers = array()) { $curl = curl_init(); if (count($headers) >= 1) { curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); } curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); // $zs1 = CMF_ROOT . "cert/apiclient_cert.pem"; $zs2 = CMF_ROOT . "cert/apiclient_key.pem"; // curl_setopt ( $curl, CURLOPT_SSLCERT, $zs1 ); // curl_setopt ( $curl, CURLOPT_SSLKEY, $zs2 ); //设置证书 //使用证书:cert 与 key 分别属于两个.pem文件 curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM'); curl_setopt($curl, CURLOPT_SSLCERT, $zs1); curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM'); curl_setopt($curl, CURLOPT_SSLKEY, $zs2); if (!empty($data)) { curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); } curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($curl); curl_close($curl); return $output; } //获取xml里面数据,转换成array public function xml2array($xml) { $p = xml_parser_create(); xml_parse_into_struct($p, $xml, $vals, $index); xml_parser_free($p); $data = ""; foreach ($index as $key => $value) { if ($key == 'xml' || $key == 'XML') continue; $tag = $vals[$value[0]]['tag']; $value = $vals[$value[0]]['value']; $data[$tag] = $value; } return $data; } //随机字符串 public function rand_code($length = 16) { $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; $str = ""; for ($i = 0; $i < $length; $i++) { $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); } return $str; } public function ToXml($data=array()) { if(!is_array($data) || count($data) <= 0) { return '数组异常'; } $xml = "<xml>"; foreach ($data as $key=>$val) { if (is_numeric($val)){ $xml.="<".$key.">".$val."</".$key.">"; }else{ $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml.="</xml>"; return $xml; }
前台页面拉起微信支付
<!DOCTYPE html> <html> <head> <title>订单支付 {$site_info.site_name|default=''}</title> <meta name="keywords" content="{$site_info.site_seo_keywords|default=''}"/> <meta name="description" content="{$site_info.site_seo_description|default=''}"> <include file="public@head"/> </head> <body > <include file="public@top"/> <hook name="before_head_end"/> <!-- top --> <div class="zt"> <div class="am-container"> <div> <div class="order_info"> <h3 class="am-text-center">核实订单</h3> </div> <div class="order_money am-text-center"> <table class="am-table "> <tr> <td>订单号</td> <td class="am-text-right">{$order_info['order_id']}</td> </tr> <tr> <td>金额</td> <td class="am-text-right">{$order_info['money']}¥</td> <input type="hidden" name="money" id="money_input" value=""> </tr> </table> </div> <div class="am-form-group"> <button style="width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer; color:white; font-size:16px;" type="button" onclick="callpay()" >立即支付</button> </div> </div> </div> </div> <include file="public@footer"/> <!-- <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> --> <script type="text/javascript"> //调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId":'{$wechat['appid']}', //公众号名称,由商户传入 "timeStamp":'{$wxpay_status['timeStamp']}', //时间戳,自1970年以来的秒数 "nonceStr":'{$wxpay_status['nonceStr']}', //随机串 "package":'{$wxpay_status['package']}', "signType":"MD5", //微信签名方式: "paySign":'{$wxpay_status['paySign']}'//微信签名 }, function(res){ console.log(res); WeixinJSBridge.log(res.err_msg); //alert('err_code:'+res.err_code+'err_desc:'+res.err_desc+'err_msg:'+res.err_msg); //alert(res.err_code+res.err_desc+res.err_msg); //alert(res); if(res.err_msg == "get_brand_wcpay_request:ok"){ alert("支付成功!"); window.location.href="http://m.sxcrcm.com"; }else if(res.err_msg == "get_brand_wcpay_request:cancel"){ alert("用户取消支付!"); }else{ alert("支付失败!"); } } ); } function callpay() { if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } }else{ jsApiCall(); } } </script> </body>