一、准备工作在开始之前,我们需要确保已经满足以下准备工作: 安装ThinkPHP 6框架:可以通过Composer进行安装,执行命令 composer create-project topthink/think=6.* project_name 即可创建一个新的
一、准备工作 在开始之前,我们需要确保已经满足以下准备工作:
- 安装ThinkPHP 6框架:可以通过Composer进行安装,执行命令
composer create-project topthink/think=6.* project_name
即可创建一个新的ThinkPHP 6项目。 - 获取微信支付接口:登录微信公众平台,进入开发者中心,申请并获取到微信支付的相关接口信息,包括商户号、支付密钥等。
- 配置微信支付参数:在ThinkPHP 6项目中,打开位于
config
目录下的pay.php
文件,根据所获取到的微信支付接口信息,配置相应的参数。
二、创建支付控制器
在ThinkPHP 6中,我们可以通过生成器快速创建一个控制器及其相关的模板和路由。执行以下命令生成一个名为Pay
的控制器:
php think make:controller Pay
生成的控制器文件位于app/controller
目录下,我们可以在该文件中编写支付相关的业务逻辑。
三、实现微信支付功能
- 创建统一下单接口 在
Pay
控制器中,创建一个名为unifiedOrder
的方法来处理统一下单请求,代码如下:
php
<?php
namespace app\controller;
use think\Controller;
use think\facade\Config;
use think\facade\Request;
use think\facade\View;
use think\facade\Log;
use think\facade\Db;
use think\facade\Cache;
class Pay extends Controller
{
// 统一下单接口
public function unifiedOrder()
{
// 获取统一下单所需的参数,根据业务需求自行获取
$orderNo = Request::post('order_no');
$totalAmount = Request::post('total_amount');
// ...
// 构建统一下单所需的数据
$params = [
'appid' => Config::get('pay.app_id'),
'mch_id' => Config::get('pay.mch_id'),
'nonce_str' => uniqid(), // 随机字符串,根据实际情况生成
'body' => '订单支付', // 商品描述,根据实际情况设置
'out_trade_no' => $orderNo, // 商户订单号,根据实际情况生成
'total_fee' => $totalAmount * 100, // 订单总金额,单位:分,需要转换成整数
'spbill_create_ip' => Request::ip(), // 客户端IP,根据实际情况获取
'notify_url' => Config::get('pay.notify_url'), // 支付回调通知地址
'trade_type' => 'JSAPI', // 交易类型,根据实际情况设置
'openid' => $this->getOpenId(), // 用户的OpenID,根据实际情况获取
];
// 生成签名并添加到请求参数中
$params['sign'] = $this->generateSign($params);
// 发起统一下单请求
$responseXml = $this->postXmlCurl($this->arrayToXml($params), 'https://api.mch.weixin.qq.com/pay/unifiedorder');
// 解析返回的XML数据
$responseData = $this->xmlToArray($responseXml);
if ($responseData['return_code'] == 'SUCCESS' && $responseData['result_code'] == 'SUCCESS') {
// 统一下单成功,返回预支付订单信息给前端
return json([
'code' => 0,
'msg' => '统一下单成功',
'data' => [
'appId' => Config::get('pay.app_id'),
'timeStamp' => time(),
'nonceStr' => uniqid(),
'package' => 'prepay_id=' . $responseData['prepay_id'],
'signType' => 'MD5',
'paySign' => $this->generateSign([
'appId' => Config::get('pay.app_id'),
'timeStamp' => time(),
'nonceStr' => uniqid(),
'package' => 'prepay_id=' . $responseData['prepay_id'],
'signType' => 'MD5',
]),
],
]);
} else {
// 统一下单失败
return json([
'code' => -1,
'msg' => '统一下单失败',
]);
}
}
// 支付回调接口
public function notify()
{
// 获取微信支付的回调数据
$data = file_get_contents('php://input');
Log::write('微信支付回调数据:' . $data);
// 解析回调数据
$responseData = $this->xmlToArray($data);
if ($this->checkSign($responseData)) {
// 验证签名成功
if ($responseData['return_code'] == 'SUCCESS' && $responseData['result_code'] == 'SUCCESS') {
// 支付成功,处理订单逻辑,更新订单状态等
// ...
return 'SUCCESS';
} else {
// 支付失败
return 'FAIL';
}
} else {
// 验证签名失败
return 'FAIL';
}
}
// 获取用户的OpenID,根据实际情况获取
private function getOpenId()
{
// ...
}
// 生成签名
private function generateSign($params)
{
// 排序
ksort($params);
// 拼接字符串
$string = '';
foreach ($params as $key => $value) {
if ($key != 'sign' && $value != '' && !is_array($value)) {
$string .= $key . '=' . $value . '&';
}
}
$string .= 'key=' . Config::get('pay.api_key');
// MD5加密并转换为大写
return strtoupper(md5($string));
}
// 验证签名
private function checkSign($params)
{
$sign = $params['sign'];
unset($params['sign']);
return $sign == $this->generateSign($params);
}
// 数组转XML
private function arrayToXml($data)
{
$xml = '<xml>';
foreach ($data as $key => $value) {
$xml .= "<{$key}><![CDATA[{$value}]]></{$key}>";
}
$xml .= '</xml>';
return $xml;
}
// XML转数组
private function xmlToArray($xml)
{
libxml_disable_entity_loader(true);
return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
}
// 发送POST请求
private function postXmlCurl($xml, $url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: text/xml']);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}
- 处理支付回调 在
Pay
控制器中,创建一个名为notify
的方法来处理微信支付的异步通知回调,代码如下:
public function notify()
{
// 获取微信支付的回调数据
$data = file_get_contents('php://input');
// 处理回调数据,如验证签名等
// ...
// 根据回调结果更新订单状态等业务逻辑
// ...
// 返回响应给微信支付平台
return 'SUCCESS';
}
四、配置路由
在ThinkPHP 6中,可以通过编辑route
目录下的route.php
文件来配置路由规则。我们需要为支付接口和支付回调接口配置相应的路由规则,示例如下:
// 支付接口路由
Route::post('pay/unifiedOrder', 'Pay/unifiedOrder');
// 支付回调路由
Route::post('pay/notify', 'Pay/notify');
五、前端集成 根据业务需求,在前端页面中调用支付接口,获取到预支付订单信息后,可以使用微信JSAPI提供的支付功能进行支付操作。