本文目录导读:

我来详细介绍PHP项目对接微信支付功能的完整步骤和核心代码实现。
前期准备
申请商户号
- 在微信商户平台(pay.weixin.qq.com)注册商户号
- 获取商户号(MCHID)
- 设置API密钥(Key)
- 下载商户证书
开通产品权限
- 在商户平台开通JSAPI支付、Native支付等
- 配置支付回调域名
核心配置
创建配置文件
<?php
// config/wechat.php
return [
'appid' => '你的公众号APPID', // 公众号APPID
'mch_id' => '你的商户号', // 商户号
'key' => '你的API密钥', // API密钥
'notify_url' => 'https://yourdomain.com/notify', // 回调地址
'cert_path' => __DIR__ . '/cert/apiclient_cert.pem', // 证书路径
'key_path' => __DIR__ . '/cert/apiclient_key.pem', // 密钥路径
];
支付SDK封装
基础工具类
<?php
// lib/WechatPay.php
class WechatPay {
private $config;
public function __construct($config) {
$this->config = $config;
}
/**
* 生成签名
*/
public function makeSign($params) {
// 1. 排序
ksort($params);
// 2. 拼接字符串
$string = '';
foreach ($params as $key => $value) {
if ($value !== '' && $key !== 'sign') {
$string .= $key . '=' . $value . '&';
}
}
$string .= 'key=' . $this->config['key'];
// 3. MD5加密并转大写
return strtoupper(md5($string));
}
/**
* 发送POST请求
*/
public function postXml($url, $xml) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 数组转XML
*/
public function arrayToXml($params) {
$xml = '<xml>';
foreach ($params as $key => $value) {
if (is_numeric($value)) {
$xml .= "<{$key}>{$value}</{$key}>";
} else {
$xml .= "<{$key}><![CDATA[{$value}]]></{$key}>";
}
}
$xml .= '</xml>';
return $xml;
}
/**
* XML转数组
*/
public function xmlToArray($xml) {
libxml_disable_entity_loader(true);
$result = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $result;
}
}
支付接口实现
JSAPI支付(公众号支付)
<?php
// controller/PaymentController.php
class PaymentController {
/**
* 创建JSAPI支付订单
*/
public function jsapiPay($openId, $totalFee, $orderNo, $body) {
$config = require 'config/wechat.php';
$wechatPay = new WechatPay($config);
// 构建请求参数
$params = [
'appid' => $config['appid'],
'mch_id' => $config['mch_id'],
'nonce_str' => $this->createNonceStr(),
'body' => $body,
'out_trade_no' => $orderNo,
'total_fee' => $totalFee, // 单位:分
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
'notify_url' => $config['notify_url'],
'trade_type' => 'JSAPI',
'openid' => $openId,
];
// 生成签名
$params['sign'] = $wechatPay->makeSign($params);
// 发送请求
$xml = $wechatPay->arrayToXml($params);
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$result = $wechatPay->postXml($url, $xml);
$response = $wechatPay->xmlToArray($result);
// 处理返回结果
if ($response['return_code'] == 'SUCCESS' && $response['result_code'] == 'SUCCESS') {
// 生成JSAPI调起支付参数
$jsapiParams = [
'appId' => $config['appid'],
'timeStamp' => (string)time(),
'nonceStr' => $this->createNonceStr(),
'package' => 'prepay_id=' . $response['prepay_id'],
'signType' => 'MD5',
];
$jsapiParams['paySign'] = $wechatPay->makeSign($jsapiParams);
return [
'success' => true,
'data' => $jsapiParams
];
}
return [
'success' => false,
'message' => $response['return_msg']
];
}
/**
* 生成随机字符串
*/
private function createNonceStr($length = 32) {
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$str = '';
for ($i = 0; $i < $length; $i++) {
$str .= $chars[mt_rand(0, strlen($chars) - 1)];
}
return $str;
}
}
Native支付(扫码支付)
/**
* 创建Native支付订单
*/
public function nativePay($totalFee, $orderNo, $body) {
$config = require 'config/wechat.php';
$wechatPay = new WechatPay($config);
$params = [
'appid' => $config['appid'],
'mch_id' => $config['mch_id'],
'nonce_str' => $this->createNonceStr(),
'body' => $body,
'out_trade_no' => $orderNo,
'total_fee' => $totalFee,
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
'notify_url' => $config['notify_url'],
'trade_type' => 'NATIVE',
];
$params['sign'] = $wechatPay->makeSign($params);
$xml = $wechatPay->arrayToXml($params);
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$result = $wechatPay->postXml($url, $xml);
$response = $wechatPay->xmlToArray($result);
if ($response['return_code'] == 'SUCCESS' && $response['result_code'] == 'SUCCESS') {
return [
'success' => true,
'code_url' => $response['code_url'], // 二维码链接
'prepay_id' => $response['prepay_id']
];
}
return [
'success' => false,
'message' => $response['return_msg']
];
}
支付回调处理
<?php
// notify/NotifyController.php
class NotifyController {
/**
* 支付回调处理
*/
public function handleNotify() {
$config = require 'config/wechat.php';
$wechatPay = new WechatPay($config);
// 获取回调数据
$xml = file_get_contents('php://input');
$data = $wechatPay->xmlToArray($xml);
// 验证签名
if ($data['sign'] != $wechatPay->makeSign($data)) {
// 签名验证失败
$this->returnFail('签名验证失败');
return;
}
// 验证订单金额
$orderNo = $data['out_trade_no'];
$totalFee = $data['total_fee'];
// 1. 查询本地订单
$order = $this->getOrderByNo($orderNo);
if (!$order) {
$this->returnFail('订单不存在');
return;
}
// 2. 验证金额
if ($order['total_fee'] != $totalFee) {
$this->returnFail('金额不匹配');
return;
}
// 3. 更新订单状态
$this->updateOrderStatus($orderNo, 'paid', $data['transaction_id']);
// 4. 返回成功
$this->returnSuccess();
}
/**
* 返回处理成功
*/
private function returnSuccess() {
$xml = '<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>';
header('Content-Type: text/xml');
echo $xml;
}
/**
* 返回处理失败
*/
private function returnFail($message) {
$xml = '<xml>
<return_code><![CDATA[FAIL]]></return_code>
<return_msg><![CDATA[' . $message . ']]></return_msg>
</xml>';
header('Content-Type: text/xml');
echo $xml;
}
/**
* 查询订单信息
*/
private function getOrderByNo($orderNo) {
// 从数据库查询订单
// return $orderInfo;
}
/**
* 更新订单状态
*/
private function updateOrderStatus($orderNo, $status, $transactionId) {
// 更新数据库订单状态
}
}
前端调用示例
JSAPI支付前端
// 获取支付参数后调起支付
function onBridgePay(jsapiParams) {
if (typeof WeixinJSBridge === "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
onBridgeReady();
}
function onBridgeReady() {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": jsapiParams.appId,
"timeStamp": jsapiParams.timeStamp,
"nonceStr": jsapiParams.nonceStr,
"package": jsapiParams.package,
"signType": jsapiParams.signType,
"paySign": jsapiParams.paySign
},
function(res) {
if (res.err_msg === "get_brand_wcpay_request:ok") {
// 支付成功
alert('支付成功');
} else if (res.err_msg === "get_brand_wcpay_request:cancel") {
// 支付取消
alert('支付已取消');
} else {
// 支付失败
alert('支付失败:' + res.err_msg);
}
}
);
}
}
生成二维码(Native支付)
// 控制器
public function showQrCode($orderNo) {
$result = $this->nativePay($totalFee, $orderNo, '商品描述');
if ($result['success']) {
// 生成二维码图片
$qrCode = new \Endroid\QrCode\QrCode($result['code_url']);
header('Content-Type: ' . $qrCode->getContentType());
echo $qrCode->writeString();
}
}
完整流程示例
// 支付控制器完整示例
class PaymentDemo {
/**
* 支付流程入口
*/
public function index() {
// 1. 获取用户openid(需有微信网页授权)
$openId = $_SESSION['openid'];
// 2. 生成订单
$orderInfo = $this->createOrder($openId);
// 3. 调用支付接口
$payment = new PaymentController();
$result = $payment->jsapiPay(
$openId,
$orderInfo['total_fee'],
$orderInfo['order_no'],
'测试商品'
);
if ($result['success']) {
// 4. 返回JSON给前端
echo json_encode([
'code' => 200,
'data' => $result['data']
]);
} else {
echo json_encode([
'code' => 400,
'message' => $result['message']
]);
}
}
}
注意事项
-
安全性:
- 不要在前端暴露API密钥
- 验证回调签名
- 使用HTTPS传输
-
错误处理:
- 记录支付日志
- 设置合理的超时时间
- 处理重复通知
-
性能优化:
- 使用Redis缓存access_token
- 异步处理订单状态
-
建议使用现成SDK:
- wechatpay-php(官方)
- EasyWeChat(第三方)
这样,你的PHP项目就可以成功对接微信支付功能了,记得在生产环境中做好充分的测试和错误处理。