本文讲解如何开发微信小程序支付,包含小程序发起支付,后端统一下单,查询订单,订单回调,订单入库等操作。
流程
微信小程序获取订单参数->向后端发起同意下单请求->获取订单参数->小程序调用Api进行发起支付->支付完成->发送回调->支付结果入库->查询订单支付状态。
后端代码
getOpenid.php
需要配置的参数有 $appid、$secret、orderPrice
,其中 $appid、$secret、orderPrice
是你小程序的两个参数,orderPrice
是订单金额,以元为单位。
200,
'msg' => '获取openid成功',
'openid' => $openid,
'orderPrice' => 0.01 // 单位:元
);
// 输出JSON
echo json_encode($result,JSON_UNESCAPED_UNICODE);
?>
creatOrder.php
需要配置的参数都在代码中有说明。$appid、$mchid、$xlid、$data['notify_url']、$set_body、$price
$appid,
'timestamp' => $timeStamp,
'package' => 'prepay_id='.$ret,
'paySign' => $str,
'noncestr' => $noncestr,
'orderNum' => $ordernumber,
'orderPrice' => intval($money * 1) // 可用number_format转换金额
);
exit(json_encode($arr));
}
// 微信支付签名
function getSign($data=array(),$url,$randstr,$time){
$str = "POST"."\n".$url."\n".$time."\n".$randstr."\n".$data."\n";
$key = file_get_contents('apiclient_key.pem');// 在商户平台下载的秘钥
$str = getSha256WithRSA($str,$key);
return $str;
}
// 调起支付的签名
function getWechartSign($appid,$timeStamp,$noncestr,$prepay_id){
$str = $appid."\n".$timeStamp."\n".$noncestr."\n".$prepay_id."\n";
$key = file_get_contents('apiclient_key.pem');
$str = getSha256WithRSA($str,$key);
return $str;
}
function getSha256WithRSA($content, $privateKey){
$binary_signature = "";
$algo = "SHA256";
openssl_sign($content, $binary_signature, $privateKey, $algo);
$sign = base64_encode($binary_signature);
return $sign;
}
/* PHP CURL HTTPS POST */
function curl_post_https($url,$data,$header){ // 模拟提交数据函数
$curl = curl_init(); // 启动一个CURL会话
curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在
curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包
curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
$tmpInfo = curl_exec($curl); // 执行操作
if (curl_errno($curl)) {
echo 'Errno'.curl_error($curl);//捕抓异常
}
curl_close($curl); // 关闭CURL会话
return $tmpInfo; // 返回数据,json格式
}
// 生成noncestr
function creatnoncestr($length){
$str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
$randStr = str_shuffle($str);
$rands= substr($randStr,0,$length);
return $rands;
}
// 商品名称
$set_body = '小程序支付';
// 支付金额(单位:分)
// 还需要去getOpenid.php里面修改这个价格才会在小程序显示准确的价格
$price = 1;
// 商户自定义订单号
$out_trade_no = date('Ymd').time();
// 时间戳
$timeStamp = time();
// 支付用户
$openid = trim($_GET['openid']);
// 随机字符串
$noncestr = creatnoncestr(8);
// 创建订单
wechartAddOrder($set_body,$out_trade_no,$price,$openid,$timeStamp,$noncestr);
?>
notify.php
这个文件是支付回调。
decryptToString($associatedData,$nonceStr,$ciphertext);
// 解析JSON
$out_trade_no = json_decode($result)->out_trade_no; // 订单号
$trade_state = json_decode($result)->trade_state; // 支付结果
$openid = json_decode($result)->payer->openid; // 支付用户
$payer_total = json_decode($result)->amount->payer_total; // 支付金额
// 如果支付支付结果是已支付的
if($trade_state == 'SUCCESS'){
// 将结果存入数据库
$conn = new mysqli($dbhost, $dbuser, $dbpwd, $dbname);
// 去重
$sql_checkNotify = "SELECT * FROM xcxpay_order WHERE order_num='$out_trade_no'";
$result_checkNotify = $conn->query($sql_checkNotify);
if ($result_checkNotify->num_rows > 0) {
// 如果已经存在这个订单
// 代表服务器多次下发回调
// 就不需要再次存进来了
// 返回接收结果
$ret = array(
'code' => 200,
'message' => '接收成功'
);
echo json_encode($ret);
}else{
// 否则就需要把这个订单存进来
$sql_notify = "INSERT INTO xcxpay_order (order_num, openid, order_total) VALUES ('$out_trade_no', '$openid', '$payer_total')";
if ($conn->query($sql_notify) === TRUE) {
// 返回接收结果
$ret = array(
'code' => 200,
'message' => '接收成功'
);
echo json_encode($ret);
}else{
// 返回接收结果
$ret = array(
'code' => 'FAIL',
'message' => '接收失败'
);
echo json_encode($ret);
}
}
}else{
// 返回接收结果
$ret = array(
'code' => 200,
'message' => '接收成功'
);
echo json_encode($ret);
}
?>
v3OrderCallBack.php
这个文件是支付回调的验签,需要配置的参数是 ApiV3Key
aesKey = $aesKey;
}
public function decryptToString($associatedData, $nonceStr, $ciphertext)
{
$ciphertext = \base64_decode($ciphertext);
if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
return false;
}
if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available()) {
return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
}
if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') && \Sodium\crypto_aead_aes256gcm_is_available()) {
return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
}
if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
$ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
$authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);
return \openssl_decrypt($ctext, 'aes-256-gcm', $this->aesKey, \OPENSSL_RAW_DATA, $nonceStr,
$authTag, $associatedData);
}
throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
}
}
Db.php
数据库配置。
数据库表结构如下:
可通过以下SQL语句执行建表。
SQL语句
CREATE TABLE `xcxpay_order` (
`id` int(10) NOT NULL COMMENT '自增ID',
`order_num` varchar(32) DEFAULT NULL COMMENT '订单号',
`openid` varchar(32) DEFAULT NULL COMMENT 'openid',
`order_total` varchar(10) DEFAULT NULL COMMENT '订单金额(分)',
`order_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '订单时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
证书文件
还需要前往商户平台下载证书文件。
获取方式:
小程序代码
pay.wxml
你需要支付{{orderPrice}}元
立即支付
支付成功
pay.js
需要配置域名和后端目录名。
Page({
data: {
paySuccess:false
},
// 进入页面加载
onLoad(e) {
var that = this;
// 获取用户
wx.login({
success: function(res) {
if (res.code) {
wx.request({
url: "https://你的域名/目录/getOpenid.php?code="+res.code,
header: {"content-type": "application/json"},
success: function(res) {
console.log(res.data)
// 获取到openid和订单金额
that.setData({
openid:res.data.openid,
orderPrice:res.data.orderPrice
})
}
});
}
}
})
},
// 发起支付
Reqpay: function(){
var that = this;
wx.request({
url: "https://你的域名/目录/creatOrder.php?openid="+that.data.openid,
header: {'content-type': 'application/json'},
success (res) {
console.log(res.data)
// 请求支付参数
var timestamp_ = res.data.timestamp;
var noncestr_ = res.data.noncestr;
var package_ = res.data.package;
var paySign_ = res.data.paySign;
// 订单参数
var orderNum = res.data.orderNum; // 订单号
wx.requestPayment({
timeStamp: timestamp_.toString(),
nonceStr: noncestr_,
package: package_,
signType: 'MD5',
paySign: paySign_,
success (res) {
console.log(res)
if(res.errMsg == 'requestPayment:ok'){
// 支付成功
console.log('支付成功')
that.setData({
paySuccess:true
})
// 请勿使用requestPayment:ok的结果作为判断支付成功的依据
// 如需确定订单支付的真实结果请往下继续添加你的查询订单支付结果的逻辑
}
}
})
}
})
}
})
pay.wxss
.orderInfo{
width: 88%;
height: 100px;
background: #eee;
border-radius: 20px;
margin: 30px auto 0;
line-height: 100px;
text-align: center;
font-size: 25px;
}
.paybtn{
width: 88%;
height: 55px;
line-height: 55px;
background: #f7c58a;
border-radius: 10px;
margin: 10px auto 0;
text-align: center;
font-size: 18px;
}
.paySuccess{
text-align: center;
margin-top: 30px;
font-size: 16px;
color: #f7c58a;
font-weight: bold;
}
pay.json
{
"usingComponents": {},
"navigationBarTextStyle": "black",
"backgroundColor": "#eee",
"navigationBarBackgroundColor": "#f7c58a",
"navigationBarTitleText": "微信小程序支付demo"
}
图例
作者
TANKING
有问题请联系Wechat:sansure2016