PHP项目如何对接微信支付功能?

wen PHP项目 4

本文目录导读:

PHP项目如何对接微信支付功能?

  1. 前期准备
  2. 核心配置
  3. 支付SDK封装
  4. 支付接口实现
  5. 支付回调处理
  6. 前端调用示例
  7. 完整流程示例
  8. 注意事项

我来详细介绍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']
            ]);
        }
    }
}

注意事项

  1. 安全性

    • 不要在前端暴露API密钥
    • 验证回调签名
    • 使用HTTPS传输
  2. 错误处理

    • 记录支付日志
    • 设置合理的超时时间
    • 处理重复通知
  3. 性能优化

    • 使用Redis缓存access_token
    • 异步处理订单状态
  4. 建议使用现成SDK

这样,你的PHP项目就可以成功对接微信支付功能了,记得在生产环境中做好充分的测试和错误处理。

抱歉,评论功能暂时关闭!