前端代码
1. 前端发起代码请求,去后台换取code_url.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>微信支付</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{include file="Common/pcmeta" /}
<script type="text/javascript" src="//static.runoob.com/assets/qrcode/qrcode.min.js"></script>
</head>
<body>
<!-- 中间频道 -->
<div class="consult">
<div class="wxLogo">
<img src="__STATIC__/pc/./image/icon/wxlogo.png" alt="">
</div>
<hr />
<div class="payTips">
<div class="payTips_a">
<span>服务名称:</span>{$cont.server}
</div>
<div class="payTips_a">
<span>服务价格:</span>{$cont.salary} 元
</div>
<div class="payTips_a">
<span>订单编号:</span><input type="text" value="{$cont.key}" id="orderNum" readonly>
</div>
<!-- 接收二维码地址-->
<input type="hidden" value="{$imgStr}" id="codeurl">
<input type="hidden" value="{$cont.id}" id="orderid">
<input type="hidden" value="{$cont.server}" id="server">
</div>
<div class="qrBox">
<div class="qrBox_title">
<img src="__STATIC__/pc/./image/icon/wxlogo.png" alt="">
</div>
<div id="qrcode" class="qrcodeimg"></div>
<div class="qrbox_tips" id="tipsMess">请使用手机微信扫一扫付款</div>
</div>
</div>
<script>
let qrCode = new QRCode(document.getElementById("qrcode"),{
width:200,
height:200
});
function makeCode()
{
var elText = document.getElementById("codeurl");
if (!elText.value) {
layer.msg("未获取到支付二维码");
elText.focus();
return;
}
qrCode.makeCode(elText.value);
}
makeCode();
</script>
<!-- 支付回调-->
<script>
let orderNum = document.getElementById("orderNum").value;
let id = $('#orderid').val();
let server = $('#server').val();
let i = setInterval(getNotifiy,2000);
function getNotifiy()
{
$.ajax({
type:'post',
data:{orderNum:orderNum},
url:"{:url('../patient/pay/selPayState')}",
dataType:'json',
success:function (data)
{
if(data.trade_state_desc === '支付成功')
{
clearInterval(i);
location.href="{:url('../patient/pay/payment')}?trader="+data.out_trade_no+'&id='+id+'&transaction='+data.transaction_id+'&amount='+data.amount.total+'&server='+server;
}
},
error:function ()
{
layer.msg('请求失败');
}
})
}
</script>
</body>
</html>
2.控制器代码
const appid = '';//公众号应用APPID
const mchid = '';//直联商户号
private $nocesStr;
public function __construct(){
//使用父类的构造函数,也就是调用Controller类的构造函数
parent::__construct();
$str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$key = "";
for($i=0;$i<strlen($str)-4;$i++)
{
$key .= $str{mt_rand(0,32)}; //生成php随机数
}
$this -> nocesStr = $key;
}
//微信支付展示页
public function index()
{
$key = $this -> nocesStr;
$id = $_GET['id'];
$salary = (float)$_GET['salary']*100;
$server = $_GET['server'];
$arr = [
'id' =>$id,
'salary'=>$salary/100,
'server'=>$server,
'key' =>$key
];
$url = 'https://xxxxxx.com/patient/notify';//回调链接
$result = $this -> wxPay($server,$url,$salary,$key);
$code_url = str_replace("}",'',str_replace('"','',substr($result,12)));
$this -> assign('cont',$arr);
$this -> assign('imgStr',$code_url);
return $this -> fetch('Pc/pay');
}
/*
* 微信支付拼接json请求字符串
*/
public function wxPay($descr,$url,$salary,$key)
{
$arr = [
'mchid' => self::mchid,//商户号
'out_trade_no' => $key,//商户订单号
'appid' => self::appid,//appID
'description' => $descr,
'notify_url' => $url,
'amount'=>['total' => $salary,'currency'=>'CNY'],
];
$jsonStr = json_encode($arr);
$result = $this -> toPay($jsonStr,$key);
return $result;
}
/*
* 调用接口
*/
public function toPay($str,$key)
{
$requestUrl = 'https://api.mch.weixin.qq.com/v3/pay/transactions/native';//Native支付请求地址
$message = wxPay_native($key,$str);
$headers = ['Accept: application/json',
'Content-Type: application/json; charset=utf-8',
'User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)',
$message
];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $requestUrl);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,FALSE);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $str);
curl_setopt($curl, CURLOPT_HTTPHEADER,$headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$codeUrl = curl_exec($curl);
curl_close($curl);
return $codeUrl;
}
3.公共方法,主要为调起支付进行加密
//微信扫码支付
function wxPay_native($key,$jsonStr)
{
$method = "POST";
$URL = "/v3/pay/transactions/native";//对应要请求的接口域名后的所有参数
$time = time();
$reStr = $key;//请求支付所用的随机字符串
$body = $jsonStr;//请求报文【请求接口所用的所有参数】
$mch_private_key = openssl_get_privatekey(file_get_contents("https://xxxx.com/cert/apiclient_key.pem"));//用微信支付提供的秘钥进行加密
$message = $method."\n". $URL."\n". $time."\n". $reStr."\n". $body."\n";//拼接加密字符串
openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');//进行加密
$base = base64_encode($raw_sign);
$schema = "WECHATPAY2-SHA256-RSA2048";
$endStr_a = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', mchid, $reStr, $time, "69DB9A9B394F307DB87163DB52D579DE29765C30", $base);
return 'Authorization:'.$schema.' '.$endStr_a;//返回请求头用于上方发起支付的请求头
}
4.将获取回来的url_code返回到支付页面进行转化为二维码,用的qrcodeJS进行转化。然后轮训2秒轮训微信支付查询接口【也需要进行加密】进行判断用户是否已经支付进行下一步逻辑操作 核心代码如下:
<script>
let qrCode = new QRCode(document.getElementById("qrcode"),{
width:200,
height:200
});
function makeCode()
{
var elText = document.getElementById("codeurl");
if (!elText.value) {
layer.msg("未获取到支付二维码");
elText.focus();
return;
}
qrCode.makeCode(elText.value);
}
makeCode();
</script>
<!-- 支付回调-->
<script>
let orderNum = document.getElementById("orderNum").value;
let id = $('#orderid').val();
let server = $('#server').val();
let i = setInterval(getNotifiy,2000);
function getNotifiy()
{
$.ajax({
type:'post',
data:{orderNum:orderNum},
url:"{:url('../patient/pay/selPayState')}",
dataType:'json',
success:function (data)
{
if(data.trade_state_desc === '支付成功')
{
clearInterval(i);
location.href="{:url('../patient/pay/payment')}?trader="+data.out_trade_no+'&id='+id+'&transaction='+data.transaction_id+'&amount='+data.amount.total+'&server='+server;
}
},
error:function ()
{
layer.msg('请求失败');
}
})
}
</script>
控制器代码
*
* 查询是否支付完成
*/
public function selPayState()
{
header("Access-Control-Allow-Origin:*");
header("Access-Control-Allow-Methods:GET,POST");
$key = $this -> nocesStr;
$orderNum = $_POST['orderNum'];
$url = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/".$orderNum.'?mchid='.self::mchid;
$result = selPayState($url,$key,$orderNum);
return $result;
}
//支付成功进行入库记录
public function payment()
{
$sess = Session::get('login');
$customer = $sess['h_name'];
$customerid = $sess['h_customerid'];
$phone = $sess['h_phone'];
$id = $_GET['id'];
$trader = $_GET['trader'];
$transaction= $_GET['transaction'];
$amount = $_GET['amount']/100;
$server = $_GET['server'];
$arr = [
'h_customer' => $customer,
'h_customerid' => $customerid,
'h_phone' => $phone,
'h_trader' => $trader,
'h_transaction' => $transaction,
'h_total' => $amount,
'h_server' =>$server,
'h_date' => Date('Y-m-d H:i:s')
];
$insert = Db::name('payment') -> insert($arr);
if(!$insert)
{
return json('error:网络环境错误');
}
$changeState = Db::name('operation') -> where('h_oid',$id)
-> where('h_opercode',$customerid)
-> update(['h_paystate'=>'2']);
if(!$changeState)
{
return json('error:网络环境错误');
}
$this->assign('cont',$arr);
return $this -> fetch('Pc/paySuccess');
加密公共函数
//查询支付状态
function selPayState($url,$key,$orderNum)
{
header("Access-Control-Allow-Origin:*");
header("Access-Control-Allow-Methods:GET,POST");
$method = "GET";
$URL = "/v3/pay/transactions/out-trade-no/".$orderNum."?mchid=".mchid;
$time = time();
$reStr = $key;
$body = "";
$mch_private_key = openssl_get_privatekey(file_get_contents("https://xxx.com/cert/apiclient_key.pem"));
$message = $method."\n". $URL."\n". $time."\n". $reStr."\n". $body."\n";
openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
$base = base64_encode($raw_sign);
$schema = "WECHATPAY2-SHA256-RSA2048";
$endStr_a = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', mchid, $reStr, $time, "69DB9A9B394F307DB87163DB52D579DE29765C30", $base);
$sign_str = 'Authorization:'.$schema.' '.$endStr_a;
$headers = ['Accept: application/json',
'Content-Type: application/json; charset=utf-8',
'User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)',
$sign_str
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);
$output = curl_exec($ch);
curl_close($ch);
$output = json_decode($output,true);
return $output;
总结
微信支付,整体文档写的并非是按部就班,我们应该先从指引文档->基础支付里选择要接入的接口,认真仔细的去阅读,可以用官方的SDK 也可以自行封装。自行封装主要去看下签名生成,根据文档提示一步一步进行封装即可。
整体来说,V3版本微信支付,比V2接入更简单一些了,全部数据交互用到json,而非XML。对于新手来说还是比较好的!加密过程是核心。后期更新一下jsapi的接入过程,其实和native一样,只不过是多了一个参数需要获取到支付用户的openid。
如果对于小白本文有帮助的话留个赞,大佬的话也不要嫌弃小弟的代码毕竟都是自学嘛~~bye~