目录

  1. 核心概念与流程
    • 为什么需要服务端?
    • App支付的核心流程
  2. 开发前准备
    • 微信支付
    • 支付宝
  3. 通用PHP开发环境准备
    • 推荐工具
    • 必要的PHP扩展
  4. 第一步:生成支付订单 (创建预支付交易)
    • 微信支付:统一下单
    • 支付宝:统一当面付(App支付)
    • PHP代码实现
  5. 第二步:处理支付结果通知 (最重要的环节)
    • 为什么需要异步通知?
    • 微信支付:支付结果通知
    • 支付宝:异步通知
    • PHP代码实现与注意事项
  6. 第三步:查询订单状态
    • 什么时候需要查询?
    • PHP代码实现
  7. 完整项目结构与代码示例
  8. 安全与最佳实践

核心概念与流程

为什么需要服务端?

App本身无法直接与微信/支付宝的支付服务器进行安全通信,所有涉及资金、敏感信息和核心业务逻辑的操作,都必须在你自己的服务端完成。

app支付php服务端开发教程
(图片来源网络,侵删)
  • 安全性:你的App Secret、商户密钥等绝不能放在App客户端,否则极易被反编译获取。
  • 业务逻辑:支付成功后,是增加用户余额、发放商品还是开通会员?这些核心逻辑由服务端控制,确保数据一致性。
  • 权威性:服务端是唯一可信的数据源,App客户端可能通过作弊或修改本地数据来模拟支付成功,但服务端的订单状态才是最终结果。

App支付的核心流程

这是一个标准的App支付流程,以微信支付为例,支付宝流程类似。

  1. 用户下单:用户在你的App中选择商品,点击“去支付”。
  2. App请求服务端:App向你的PHP服务端发送一个支付请求,通常包含商品ID、数量、用户ID等信息。
  3. 服务端统一下单
    • PHP服务端接收到请求后,生成一个唯一的订单号。
    • 调用微信/支付宝的统一下单API,将订单信息(金额、商品描述等)和你的商户信息一起发送给支付平台。
    • 支付平台验证后,返回一个预支付交易会话标识,例如微信的prepay_id
  4. 服务端返回参数给App
    • PHP服务端将prepay_id和其他必要参数(如时间戳、随机字符串、签名)打包,返回给App。
  5. App发起支付

    App接收到这些参数后,调用微信/支付宝的SDK,拉起对应的支付界面。

  6. 用户完成支付:用户在微信/支付宝App中输入密码或使用指纹完成支付。
  7. 支付平台通知服务端(异步通知)
    • 支付成功后,微信/支付宝服务器会立即向你在商户后台配置的支付结果通知URL发送一个POST请求,这是最关键的步骤!
  8. 服务端处理通知并更新数据库
    • PHP服务端接收通知,验证通知的真伪。
    • 验证通过后,更新自己数据库中对应订单的状态为“已支付”。
    • 向支付平台服务器返回一个success响应。
  9. App轮询或接收推送显示结果
    • App可能会在支付页面通过轮询(每隔几秒请求一次)你的服务端API来查询订单状态。
    • 当服务端订单状态变为“已支付”后,App收到响应,显示“支付成功”,并跳转到相应页面。

开发前准备

微信支付

  1. 注册微信商户平台https://pay.weixin.qq.com/
  2. 获取必要信息
    • 微信支付商户号mch_id
    • API密钥 (API Key / 32位):在 账户中心 -> API安全 -> API密钥 中设置和获取。极其重要,请妥善保管!
    • AppID:你的App在微信开放平台申请的唯一标识。
    • API证书:推荐使用,更安全,在 产品中心 -> 开发配置 中下载API证书。
  3. 产品开通:在 产品中心 -> 开发配置 中确保已开通“Native支付”或“App支付”产品。
  4. 配置支付授权目录/域名:在 产品中心 -> 开发配置 -> 支付授权目录 中配置你的服务端域名(用于接收异步通知)。

支付宝

  1. 注册支付宝开放平台https://open.alipay.com/
  2. 创建应用:进入“控制台” -> “开发者中心” -> “应用详情”,创建一个移动应用。
  3. 获取必要信息
    • APPID:创建应用后获得。
    • 应用私钥:在应用详情的“接口加签方式”处生成并下载。这是你用来生成签名的密钥。
    • 支付宝公钥:在应用详情的“接口加签方式”处查看。这是你用来验证支付宝签名的公钥。
  4. 产品开通:在应用详情的“产品绑定”中,绑定“手机网站支付”或“App支付”产品。
  5. 配置应用网关:在应用详情的“开发设置”中,配置授权回调域(用于网页授权)加密方式(推荐RSA2)。

通用PHP开发环境准备

  • PHP版本:建议 PHP 7.2+
  • 必要扩展
    • openssl:用于生成和验证签名(微信和支付宝都使用)。
    • curl:用于发送HTTP请求。
    • simplexmlDOMDocument:用于解析XML(微信支付常用)。
    • json:处理JSON数据(支付宝常用)。
  • 推荐工具
    • Composer:用于管理依赖,特别是微信和支付宝的官方PHP SDK。
    • IDE:PHPStorm, VS Code等。

第一步:生成支付订单

我们将使用官方SDK来简化开发。

安装SDK

在你的项目根目录下,通过Composer安装:

app支付php服务端开发教程
(图片来源网络,侵删)
# 微信支付SDK
composer require wechatpay/wechatpay
# 支付宝SDK
composer require alipaysdk/easysdk/php

PHP代码实现

创建一个文件 create_order.php

<?php
// 引入Composer的自动加载器
require 'vendor/autoload.php';
// --- 微信支付部分 ---
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\Random;
// 配置信息 - 从你的商户平台获取
$wechatConfig = [
    'mchid'    => '你的商户号',
    'serial'   => '你的API证书序列号',
    'private_key' => Rsa::from('你的商户API私钥文件路径', Rsa::KEY_TYPE_FILE), // 私钥文件
    'cert'     => Rsa::from('你的商户API证书文件路径', Rsa::KEY_TYPE_FILE),   // 证书文件
    'key'      => Rsa::from('你的平台证书文件路径', Rsa::KEY_TYPE_FILE),       // 平台证书文件
    'notify_url' => 'https://你的域名/api/wechat_notify.php', // 支付结果通知地址
];
// 构建一个实例
$wechatClient = Builder::factory($wechatConfig);
// 准备下单参数
$wechatOrderData = [
    'appid' => '你的AppID',
    'mchid' => $wechatConfig['mchid'],
    'description' => '商品描述:测试商品',
    'out_trade_no' => 'WX' . uniqid(), // 商户系统内部订单号,必须唯一
    'notify_url' => $wechatConfig['notify_url'],
    'amount' => [
        'total' => 1, // 金额,单位:分
        'currency' => 'CNY'
    ],
];
try {
    // 调用统一下单API
    $result = $wechatClient->v3->pay->transactions->app->post($wechatOrderData);
    $prepayId = $result['prepay_id'];
    // 将prepay_id和其他参数返回给App
    $wechatResponseToApp = [
        'appId' => $wechatConfig['appid'],
        'timeStamp' => (string)time(),
        'nonceStr' => Random::str(32),
        'package' => 'prepay_id=' . $prepayId,
        'signType' => 'RSA',
    ];
    // 注意:这里App端需要用同样的方式生成签名,但我们服务端只需要返回原始数据
    // 微信SDK也提供了生成签名的方法,但通常由App端完成
    // $wechatResponseToApp['paySign'] = $wechatClient->jssdk->app->sdkConfig($wechatResponseToApp)['paySign'];
    echo json_encode(['status' => 'success', 'platform' => 'wechat', 'data' => $wechatResponseToApp]);
} catch (\Exception $e) {
    // 处理异常
    echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
// --- 支付宝部分 ---
use Alipay\EasySDK\Kernel\Factory;
use Alipay\EasySDK\Kernel\Util\AES;
// 配置信息 - 从你的开放平台获取
$alipayConfig = [
    'protocol' => 'https',
    'gatewayUrl' => 'https://openapi.alipay.com/gateway.do',
    'appId' => '你的APPID',
    'alipayPublicKey' => '你的支付宝公钥',
    'merchantPrivateKey' => '你的应用私钥',
    'notifyUrl' => 'https://你的域名/api/alipay_notify.php',
    'encryptKey' => '你的AES密钥' // 在开放平台配置
];
// 初始化
Factory::setOptions($alipayConfig);
$alipayOrderData = [
    'out_trade_no' => 'ALI' . uniqid(), // 商户订单号
    'total_amount' => '0.01', // 金额,单位:元
    'subject' => '测试商品',
    'product_code' => 'QUICK_MSECURITY_PAY', // App支付固定值
    'notify_url' => $alipayConfig['notifyUrl'],
];
try {
    // 调用统一当面付API
    $result = Factory::payment()->common()->create($alipayOrderData);
    // 将返回的订单信息(主要是`orderString`)返回给App
    $alipayResponseToApp = [
        'orderString' => $result['alipay_trade_app_pay_response']['code'] // 支付宝SDK会生成一个完整的字符串
    ];
    echo json_encode(['status' => 'success', 'platform' => 'alipay', 'data' => $alipayResponseToApp]);
} catch (\Exception $e) {
    echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}

第二步:处理支付结果通知

这是整个支付流程中最关键的一环,必须严谨处理。

为什么需要异步通知?

  • 可靠性:用户支付成功后,网络可能不稳定,导致App无法立即收到成功回调,异步通知是支付平台主动推送的,最可靠。
  • 幂等性:即使网络问题,支付平台也可能会多次发送通知,你的服务端必须能正确处理重复的通知。

PHP代码实现

微信支付通知处理 (wechat_notify.php)

<?php
require 'vendor/autoload.php';
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
// 配置信息(同上)
$wechatConfig = [ ... ];
$wechatClient = Builder::factory($wechatConfig);
// 1. 接收POST数据
$xmlData = file_get_contents('php://input');
$notificationData = simplexml_load_string($xmlData, 'SimpleXMLElement', LIBXML_NOCDATA);
// 2. 验证签名
$verifyResult = $wechatClient->v3->pay->transactions->outtrade->no->combine->verify(
    ['timestamp' => $notificationData->time_end, 'nonce' => $notificationData->nonce_str, 'sign' => $notificationData->sign],
    $xmlData
);
// 3. 检查业务结果
if ($verifyResult && $notificationData->result_code === 'SUCCESS') {
    // 验证成功,且业务成功
    $outTradeNo = (string)$notificationData->out_trade_no;
    $transactionId = (string)$notificationData->transaction_id;
    $amount = (int)$notificationData->amount->total;
    // --- 在这里更新你的数据库 ---
    // 1. 根据$outTradeNo查询你的订单
    // 2. 检查订单状态是否已经是“已支付”,防止重复处理(幂等性处理)
    // 3. 验证金额是否与订单金额一致
    // 4. 更新订单状态为“已支付”,记录支付流水号$transactionId等
    updateOrderStatus($outTradeNo, 'paid', $transactionId);
    // 5. 返回成功给微信服务器
    echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
    exit;
}
// 验证失败或业务失败
echo '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[Verify Fail]]></return_msg></xml>';
function updateOrderStatus($outTradeNo, $status, $transactionId) {
    // 你的数据库更新逻辑
    //  $pdo->prepare("UPDATE orders SET status = ?, transaction_id = ? WHERE out_trade_no = ?")->execute([$status, $transactionId, $outTradeNo]);
    error_log("Order {$outTradeNo} updated to status {$status} with transaction_id {$transactionId}");
}

支付宝通知处理 (alipay_notify.php)

<?php
require 'vendor/autoload.php';
use Alipay\EasySDK\Kernel\Factory;
// 配置信息(同上)
$alipayConfig = [ ... ];
Factory::setOptions($alipayConfig);
// 1. 接收POST数据
$notificationData = $_POST;
// 2. 验证签名
$verifyResult = Factory::payment()->common()->verifyNotify($notificationData);
// 3. 检查业务结果
if ($verifyResult && $notificationData['trade_status'] == 'TRADE_SUCCESS' || $notificationData['trade_status'] == 'TRADE_FINISHED') {
    // 验证成功,且交易成功
    $outTradeNo = $notificationData['out_trade_no'];
    $tradeNo = $notificationData['trade_no'];
    $amount = $notificationData['receipt_amount'];
    // --- 在这里更新你的数据库 ---
    // 1. 根据$outTradeNo查询你的订单
    // 2. 检查订单状态是否已经是“已支付”,防止重复处理
    // 3. 验证金额是否与订单金额一致
    // 4. 更新订单状态为“已支付”,记录支付流水号$tradeNo等
    updateOrderStatus($outTradeNo, 'paid', $tradeNo);
    // 5. 返回success给支付宝服务器
    echo 'success';
    exit;
}
// 验证失败或业务失败
echo 'fail';
function updateOrderStatus($outTradeNo, $status, $tradeNo) {
    // 你的数据库更新逻辑
    error_log("Order {$outTradeNo} updated to status {$status} with trade_no {$tradeNo}");
}

第三步:查询订单状态

当App支付页面长时间未收到结果时,可以通过轮询服务端来主动查询。

PHP代码实现

创建一个文件 query_order.php

app支付php服务端开发教程
(图片来源网络,侵删)
<?php
require 'vendor/autoload.php';
// 接收App传来的订单号和平台
$outTradeNo = $_GET['out_trade_no'];
$platform = $_GET['platform'];
// 从数据库查询订单状态
$orderStatus = queryOrderFromDatabase($outTradeNo);
// 如果订单状态是'paid',直接返回
if ($orderStatus === 'paid') {
    echo json_encode(['status' => 'success', 'message' => '订单已支付']);
    exit;
}
// 如果数据库中未支付,则调用支付平台API进行实时查询
if ($platform === 'wechat') {
    // 微信查询逻辑...
    // $result = $wechatClient->v3->pay->transactions->outtrade->no->{outTradeNo}->get();
    // if (isset($result['trade_state']) && $result['trade_state'] === 'SUCCESS') {
    //     updateOrderStatus($outTradeNo, 'paid', $result['transaction_id']);
    //     echo json_encode(['status' => 'success', 'message' => '订单已支付']);
    //     exit;
    // }
    echo json_encode(['status' => 'processing', 'message' => '订单处理中']);
} elseif ($platform === 'alipay') {
    // 支付宝查询逻辑...
    // $result = Factory::payment()->common()->query($outTradeNo);
    // if (isset($result['alipay_trade_query_response']) && $result['alipay_trade_query_response']['trade_status'] == 'TRADE_SUCCESS') {
    //     updateOrderStatus($outTradeNo, 'paid', $result['alipay_trade_query_response']['trade_no']);
    //     echo json_encode(['status' => 'success', 'message' => '订单已支付']);
    //     exit;
    // }
    echo json_encode(['status' => 'processing', 'message' => '订单处理中']);
} else {
    echo json_encode(['status' => 'error', 'message' => '无效的平台']);
}
function queryOrderFromDatabase($outTradeNo) {
    // 你的数据库查询逻辑
    //  $stmt = $pdo->prepare("SELECT status FROM orders WHERE out_trade_no = ?");
    // $stmt->execute([$outTradeNo]);
    // $result = $stmt->fetch(PDO::FETCH_ASSOC);
    // return $result ? $result['status'] : null;
    return 'unpaid'; // 模拟返回
}

完整项目结构与代码示例

一个典型的项目结构可能如下:

/app-payment-tutorial
|-- /api
|   |-- create_order.php     # 创建支付订单
|   |-- wechat_notify.php    # 微信支付回调
|   |-- alipay_notify.php    # 支付宝支付回调
|   |-- query_order.php      # 查询订单状态
|-- /config
|   |-- wechat_config.php    # 微信配置信息
|   |-- alipay_config.php    # 支付宝配置信息
|-- /vendor                  # Composer自动生成
|-- /logs                   # 日志目录
|-- composer.json
|-- composer.lock
|-- README.md

安全与最佳实践

  1. HTTPS:所有与支付相关的接口(统一下单、接收通知、查询)必须使用 HTTPS 协议。
  2. 验证签名:永远不要相信客户端传来的任何数据,所有来自支付平台的通知,必须验证签名。
  3. 幂等性处理:在处理异步通知时,务必检查订单状态,避免重复更新数据库导致的问题。
  4. 金额校验:在通知中,将支付平台返回的金额与你自己数据库中存储的订单金额进行比对,防止金额被篡改。
  5. 日志记录:详细记录请求、响应、错误和业务处理过程,便于排查问题。
  6. App端安全:虽然本教程重点是服务端,但App端也应妥善处理订单状态,避免用户在支付成功后误以为失败而重复支付。
  7. 使用官方SDK:尽量使用官方提供的SDK,它们已经封装了签名、验签等复杂逻辑,更安全可靠。

通过以上步骤,你已经掌握了使用PHP开发App支付服务端的核心流程:

  1. 准备:注册商户/开放平台,获取必要的密钥和证书。
  2. 下单:服务端调用统一下单API,获取prepay_idorderString,返回给App。
  3. 通知:编写接收和处理异步通知的接口,验证签名,更新数据库,并返回success
  4. 查询:提供查询接口,供App主动拉取订单状态。

支付开发的核心在于严谨安全,请务必仔细阅读官方文档,并在每个环节都做好验证和异常处理,祝你开发顺利!