微信app支付接入后端php数据签名方式
我们先看看微信app支付的流程
商户系统和微信支付系统主要交互说明:
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。
步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。
步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appid,partnerid,prepayid,noncestr,timestamp,package。注意:package的值格式为Sign=WXPay
步骤4:商户APP调起微信支付。
步骤5:商户后台接收支付通知。
步骤6:商户后台查询支付结果。
我们再看看微信支付app端的代码
appayBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String url="https://wxpay.wxutil.com/pub_v2/app/app_pay.php"; Button payBtn = (Button) findViewById(R.id.appay_btn); payBtn.setEnabled(false); Toast.makeText(MainActivity.this, "获取订单中...", Toast.LENGTH_SHORT).show(); try{ byte[] buf = HttpUtil.httpGet(url); if (buf != null && buf.length > 0) { String content = new String(buf); Log.e("get server pay params:",content); JSONObject json = new JSONObject(content); if(null != json) ){ PayReq req = new PayReq(); req.appId = json.getString("appid"); req.partnerId = json.getString("partnerid"); req.prepayId = json.getString("prepayid"); req.nonceStr = json.getString("noncestr"); req.timeStamp = json.getString("timestamp"); req.packageValue = json.getString("package"); req.sign = json.getString("sign"); req.extData = "app data"; // optional Toast.makeText(MainActivity.this, "正常调起支付", Toast.LENGTH_SHORT).show(); // 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信 Log.e("wangbo", "checkArgs=" + req.checkArgs()); boolean ret=api.sendReq(req); Log.e("wangbo", "ret=" + ret); }else{ Log.e("PAY_GET", "返回错误"+json.getString("retmsg")); Toast.makeText(MainActivity.this, "返回错误"+json.getString("retmsg"), Toast.LENGTH_SHORT).show(); } }else{ Log.d("PAY_GET", "服务器请求错误"); Toast.makeText(MainActivity.this, "服务器请求错误", Toast.LENGTH_SHORT).show(); } }catch(Exception e){ Log.e("PAY_GET", "异常:"+e.getMessage()); Toast.makeText(MainActivity.this, "异常:"+e.getMessage(), Toast.LENGTH_SHORT).show(); } payBtn.setEnabled(true); } });
通过上面app的代码我们可以看到后台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付!官方文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
下面我看看后台怎么生成预支付交易单和签名的
<?php echo apppay('订单号','价格'); //直接输出json给前台APP //入口函数 function apppay($order_num,$price){ $json = array(); //生成预支付交易单的必选参数: $newPara = array(); //应用ID $newPara["appid"] = "商户appid"; //商户号 $newPara["mch_id"] = "商户id"; //设备号 $newPara["device_info"] = "WEB"; //随机字符串,这里推荐使用函数生成 $newPara["nonce_str"] = createNoncestr(); //商品描述 $newPara["body"] = "APP支付"; //商户订单号,这里是商户自己的内部的订单号 $newPara["out_trade_no"] = $order_num; //总金额 $newPara["total_fee"] = $price*100; //终端IP $newPara["spbill_create_ip"] = $_SERVER["REMOTE_ADDR"]; //通知地址,注意,这里的url里面不要加参数 $newPara["notify_url"] = "支付成功后的回调地址"; //交易类型 $newPara["trade_type"] = "APP"; $key = "密钥:在商户后台个人安全中心设置"; //第一次签名 $newPara["sign"] = appgetSign($newPara,$key); //把数组转化成xml格式 $xmlData = arrayToXml($newPara); $get_data = sendPrePayCurl($xmlData); //返回的结果进行判断。 if($get_data['return_code'] == "SUCCESS" && $get_data['result_code'] == "SUCCESS"){ //根据微信支付返回的结果进行二次签名 //二次签名所需的随机字符串 $newPara["nonce_str"] = createNoncestr(); //二次签名所需的时间戳 $newPara['timeStamp'] = time().""; //二次签名剩余参数的补充 $secondSignArray = array( "appid"=>$newPara['appid'], "noncestr"=>$newPara['nonce_str'], "package"=>"Sign=WXPay", "prepayid"=>$get_data['prepay_id'], "partnerid"=>$newPara['mch_id'], "timestamp"=>$newPara['timeStamp'], ); $json['success'] = 1; $json['ordersn'] = $newPara["out_trade_no"]; //订单号 $json['order_arr'] = $secondSignArray; //返给前台APP的预支付订单信息 $json['order_arr']['sign'] = appgetSign($secondSignArray,$key); //预支付订单签名 $json['data'] = "预支付完成"; //预支付完成,在下方进行自己内部的业务逻辑 /*****************************/ return json_encode($json); } else{ $json['success'] = 0; $json['error'] = $get_data['return_msg']; return json_encode($json); } } //将数组转换为xml格式 function arrayToXml($arr) { $xml = "<xml>"; foreach ($arr as $key=>$val) { if (is_numeric($val)) { $xml.="<".$key.">".$val."</".$key.">"; } else $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } $xml.="</xml>"; return $xml; } //发送请求 function sendPrePayCurl($xml,$second=30) { $url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; $ch = curl_init(); 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); curl_close($ch); $data_xml_arr =XMLDataParse($data); if($data_xml_arr) { return $data_xml_arr; } else { $error = curl_errno($ch); echo "curl出错,错误码:$error"."<br>"; echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>"; curl_close($ch); return false; } } //xml格式数据解析函数 function XMLDataParse($data){ $xml = simplexml_load_string($data,NULL,LIBXML_NOCDATA); $array=json_decode(json_encode($xml),true); return $array; } //随机字符串 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; } /* * 格式化参数格式化成url参数 生成签名sign */ function appgetSign($Obj,$appwxpay_key) { foreach ($Obj as $k => $v) { $Parameters[$k] = $v; } //签名步骤一:按字典序排序参数 ksort($Parameters); $String = formatBizQueryParaMap($Parameters, false); //echo '【string1】'.$String.'</br>'; //签名步骤二:在string后加入KEY if($appwxpay_key){ $String = $String."&key=".$appwxpay_key; } //echo "【string2】".$String."</br>"; //签名步骤三:MD5加密 $String = md5($String); //echo "【string3】 ".$String."</br>"; //签名步骤四:所有字符转为大写 $result_ = strtoupper($String); //echo "【result】 ".$result_."</br>"; return $result_; } //按字典序排序参数 function formatBizQueryParaMap($paraMap, $urlencode) { $buff = ""; ksort($paraMap); foreach ($paraMap as $k => $v) { if($urlencode) { $v = urlencode($v); } //$buff .= strtolower($k) . "=" . $v . "&"; $buff .= $k . "=" . $v . "&"; } $reqPar; if (strlen($buff) > 0) { $reqPar = substr($buff, 0, strlen($buff)-1); } return $reqPar; }
网友评论0