目录
申请商户号与服务号
可使用公司营业执照或个体工商户申请
微信商户平台(申请商户号)(微信支付审核 需要交300块钱)
https://pay.weixin.qq.com/index.php
微信公众平台(申请服务号)
https://mp.weixin.qq.com/
设置配置
商户号与服务号要先绑定
APPID:绑定支付的APPID
MCHID:商户号
KEY:商户支付密钥
登录商户品台自行设置,设置地址:https://pay.weixin.qq.com/core/cert/api_cert
可使用 http://suijimimashengcheng.51240.com 生成32位密码
APPSECRET:公众帐号secert
登录公众平台进入开发者中心可设置https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
登录微信商户平台后下载配置文件 apiclient_cert.pem 和 apiclient_key.pem
回调解密密钥
回调地址设置
官网支付demo下载
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
进行对接(使用Thinkphp5.1)
前台操作
<!DOCTYPE html>
<html>
<head>
<title>{$user_login} - 支付充值</title>
<meta name="keywords" content="" />
<meta name="description" content="">
<include file="public@head" />
</head>
<body class="body-white" id="top">
<include file="public@nav" />
<div class="container tc-main">
<div class="row">
<div class="col-md-3">
<include file="public@usernav" />
</div>
<div class="col-md-9">
<div class="tabs">
<ul class="nav nav-tabs">
<li class="active"><a href="#one" data-toggle="tab"><i class="fa fa-edit"></i> 支付充值</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="one">
<br>
<form class="js-ajax-form" method="post">
<div class="form-group">
<label for="input-sex">支付方式</label>
<div>
<div>微信支付<input type="radio" name="type" value="1" checked></div>
<div>支付宝支付<input type="radio" name="type" value="2"></div>
</div>
</div>
<div class="form-group">
<label for="input-birthday">支付金额</label>
<input class="form-control" type="number" name="money" value="0.01">
</div>
<div class="form-group">
<input type="button" id="pay" class="btn btn-primary js-ajax-submit" value="确定">
</div>
<div id="pay_bolck" style="display: none;">
<div id="pay_qrcode"></div>
<span id="pay_text"></span>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<include file="public@footer" />
</div>
<!-- /container -->
<include file="public@scripts" />
<script src="https://cdn.bootcss.com/jquery.qrcode/1.0/jquery.qrcode.min.js"></script>
<script>
var out_trade_no = '';
$('#pay').click(function (e) {
$.ajax({
type: "method",
url: "{:url('pay')}",
data: $("form").serialize(),
method: "POST",
dataType: "json",
success: function (response) {
var type = $("input:radio[name=type]:checked").val();
if (type == 1) {
$("#pay_bolck").css('display', 'block');
$("#pay_qrcode").html('');
out_trade_no = response.out_trade_no;
$("#pay_qrcode").qrcode({
width: 200,
height: 200,
text: response.url,
// background:,//背景色,
// foreground://前景色
})
$("#pay_text").text("打开微信,扫描二维码支付");
}
}
});
});
//轮询订单状态
$(document).ready(function () {
setInterval("ajaxstatus()", 3000);
});
function ajaxstatus() {
if (out_trade_no != '') {
$.ajax({
url: "{:url('payFind')}?out_trade_no=" + out_trade_no,
type: "POST",
dataType: "json",
data: "",
success: function (data) {
if (data.code == 1) { //订单状态为1表示支付成功
window.location.href = "/"; //页面跳转
}
},
error: function () {
alert("请求订单状态出错");
}
});
}
}
</script>
</body>
</html>
接口扩展文件配置
从官方示例demo中拿出这些文件丢入thinkphp框架中
require_once路径需修改
填入各项配置 加密选择MD5
public function GetSignType()
{
return "MD5";
}
扩展示例文件
链接:https://pan.baidu.com/s/1wQ8r17PhDYcQ-OWvRjWHdQ
提取码:0sb4
支付操作
入口文件index.php中加入常量配置
// 支付目录
define('PAY_PATH', CMF_ROOT . 'extend/Library/');
/**
* 支付充值页面
*
*/
//$result返回的内容
// array(10) {
// ["appid"] => string(18) "XXXX"
// ["code_url"] => string(35) "weixin://wxpay/bizpayurl?pr=XXXX"
// ["mch_id"] => string(10) "XXX"
// ["nonce_str"] => string(16) "XXX"
// ["prepay_id"] => string(36) "XXXX"
// ["result_code"] => string(7) "SUCCESS"
// ["return_code"] => string(7) "SUCCESS"
// ["return_msg"] => string(2) "OK"
// ["sign"] => string(64) "XXXXX"
// ["trade_type"] => string(6) "NATIVE"
// }
public function pay()
{
if ($this->request->isPost()) {
//1微信 2支付宝
$type = $this->request->param('type', 0, 'intval');
//充值金额
$money = $this->request->param('money', 0, 'floatval');
if ($type == 1) {
require PAY_PATH . '/wx_pay/WxPay.Api.php'; //引入微信支付
$input = new \WxPayUnifiedOrder(); //统一下单
$config = new \WxPayConfig(); //配置参数
//$paymoney = input('post.paymoney'); //支付金额
$paymoney = $money; //金额
$out_trade_no = 'WXPAY' . date("YmdHis"); //商户订单号(自定义)
$goods_name = '扫码支付' . $paymoney . '元'; //商品名称(自定义)
$input->SetBody($goods_name);
$input->SetAttach($goods_name);
$input->SetOut_trade_no($out_trade_no);
$input->SetTotal_fee($paymoney * 100); //金额乘以100
$input->SetTime_start(date("YmdHis"));
$input->SetTime_expire(date("YmdHis", time() + 600));
$input->SetGoods_tag("test");
$input->SetNotify_url("http://www.XXXX.com/common/third/paycallback"); //回调地址
$input->SetTrade_type("NATIVE");
$input->SetProduct_id("123456789"); //商品id
$result = \WxPayApi::unifiedOrder($config, $input);
// dump($result);exit;
if ($result['result_code'] == 'SUCCESS' && $result['return_code'] == 'SUCCESS') {
$url = $result["code_url"];
$data = [
'uid' => cmf_get_current_user_id(),
'total_fee' => $paymoney,
'out_trade_no' => $out_trade_no, //微信交易单号
'create_time' => time(), //创建时间
'type' => 1 //微信支付
];
//创建订单
DB::name('recharge')->insert($data);
return [
'url' => $url,
'out_trade_no' => $out_trade_no, //微信交易单号
];
} else {
$this->error('参数错误');
}
return view();
}
} else {
$user = cmf_get_current_user();
$this->assign($user);
return $this->fetch();
}
}
//轮询订单
public function payFind()
{
//商家订单号
$out_trade_no = $this->request->param('out_trade_no');
$status = DB::name('recharge')
->where('out_trade_no', $out_trade_no) //商户自定义订单号
->value('status');
if ($status == 2) {
$this->success("支付成功");
} else {
$this->error('支付失败');
}
}
回调操作(回调url一定要写可访问的url 避免权限问题)
<?php
namespace app\common\controller;
use cmf\controller\BaseController;
use think\Db;
//第三方接口
class ThirdController extends BaseController
{
/**
* wx支付回调处理
*/
//$xmlObj 输出内容
// Array
// (
// [appid] => XXXX
// [attach] => 扫码支付0.01元
// [bank_type] => OTHERS
// [cash_fee] => 1
// [fee_type] => CNY
// [is_subscribe] => Y
// [mch_id] => 1574582441
// [nonce_str] => XXXX
// [openid] => XXXX
// [out_trade_no] => XXXX
// [result_code] => SUCCESS
// [return_code] => SUCCESS
// [sign] => XXXXX
// [time_end] => 20200124125552
// [total_fee] => 1
// [trade_type] => NATIVE
// [transaction_id] => XXXX
// )
public function paycallback()
{
//获取微信回调的数据
$notifiedData = file_get_contents('php://input');
// cmh_log('pay',$notifiedData);
//XML格式转换
$xmlObj = simplexml_load_string($notifiedData, 'SimpleXMLElement', LIBXML_NOCDATA);
$xmlObj = json_decode(json_encode($xmlObj), true);
$this->cmh_log('pay', print_r($xmlObj, true));
//支付成功
if ($xmlObj['return_code'] == "SUCCESS" && $xmlObj['result_code'] == "SUCCESS") {
foreach ($xmlObj as $k => $v) {
if ($k == 'sign') {
$xmlSign = $xmlObj[$k];
unset($xmlObj[$k]);
};
}
$sign = $this->WxSign($xmlObj);
if ($sign === $xmlSign) {
//改变订单状态
DB::name('recharge')
->where('out_trade_no', $xmlObj['out_trade_no']) //商户自定义订单号
->update([
'transaction_id' => $xmlObj['transaction_id'], //微信交易单号
'status' => 2, //已支付
'end_time' => time() //完成时间
]);
$recharge = DB::name('recharge')
->where('out_trade_no', $xmlObj['out_trade_no']) //商户自定义订单号
->field('uid,total_fee')
->find();
//增加用户余额
DB::name('user')
->where('id', $recharge['uid'])
->setInc('balance', $recharge['total_fee']);
//告诉微信已经收到了
return sprintf("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");;
}
}
}
//微信签名算法
private function WxSign($param)
{
$signkey = 'XXXX'; //秘钥
$sign = '';
foreach ($param as $key => $val) {
$sign .= $key . '=' . $val . '&';
}
$sign .= 'key=' . $signkey;
$sign = strtoupper(MD5($sign));
return $sign;
}
/**
* 统一日志记录
* @author
* @date
* @param string $path 路径
* @param string $content 日志内容
* @param string $mode 记录格式,day=天,month=月,year=年
* @param string $env 请求模式
*
* @return bool
*/
function cmh_log($path, $content, $mode = 'day', $env = '')
{
if (!$content) {
return false;
}
$content = strval($content) . "\n";
if (PHP_SAPI == 'cli') {
$path = 'cli/' . $path;
}
$path = '/www/wwwroot/log/' . $path . '/';
if ($mode == 'year') {
$fileName = date('Y') . '.log';
} else if ($mode == 'month') {
$path = $path . date('Y');
$fileName = '/' . date('m') . '.log';
} else {
$path = $path . date('Y') . '/' . date('m') . '/';
$fileName = date('d') . '.log';
}
if (!is_dir($path)) {
$res = mkdir($path, 0777, true);
if (!$res) {
return false;
}
}
$file = $path . $fileName;
$content = date('Y-m-d H:i:s') . ':' . $content;
$res = file_put_contents($file, $content, FILE_APPEND);
if ($res) {
return true;
} else {
return false;
}
}
}