跳到主要内容

🐘 PHP

声明

本 SDK 由 AI 生成,仅供参考使用。建议在实际生产环境使用前进行充分测试。

概述

平台 PHP Server SDK 提供了便捷的服务端接入方式,支持签名生成、请求加密、响应验签和解密等核心功能。

功能特性

  • 支持 SHA256withRSA 签名算法
  • 支持 AES 对称加密/解密
  • 灵活的 HTTP 客户端接口设计,支持多种 HTTP 客户端实现
  • 自动处理签名和加密逻辑
  • 完整的响应验签和解密

环境要求

  • PHP 7.4+
  • Composer

安装

composer.json 依赖

{
"require": {
"php": "^7.4|^8.0"
}
}

SDK使用 PHP 标准库和扩展,无需额外依赖。

快速开始

1. 创建配置

<?php

require_once 'vendor/autoload.php';

use KudianSDK\KudianClient;
use KudianSDK\Http\CurlClient;

// 创建配置
$config = [
'gateway_url' => 'https://pay.kudianvip.com', // 正式环境
// 'gateway_url' => 'https://pay.test.kudianvip.com', // 测试环境
'mch_id' => 'your_mch_id',
'app_id' => 'your_app_id',
'app_private_key' => 'your_app_private_key', // Base64格式
'app_secret_key' => 'your_secret_key', // AES加密密钥
'api_public_key' => 'your_api_public_key' // Base64格式
];

// 创建客户端
$client = new KudianClient($config, new CurlClient());

2. 发起API请求

<?php

// 构造业务参数
$bizParams = [
'param1' => 'value1',
'param2' => 'value2'
];

// 发送请求
$response = $client->post('/api/path', $bizParams);

// 解析响应
$apiResponse = json_decode($response, true);

if ($apiResponse['code'] == 0) {
echo "业务数据: " . json_encode($apiResponse['data']);
} else {
echo "请求失败: " . $apiResponse['msg'];
}

核心 API

KudianClient

主客户端类,提供所有API调用功能。

配置参数

参数类型必填说明
gateway_urlstring网关地址,正式环境: https://pay.kudianvip.com,测试环境: https://pay.test.kudianvip.com
mch_idstring商户编号
app_idstring应用ID
app_private_keystring应用私钥(Base64编码格式),用于请求签名
app_secret_keystringAES加密密钥,用于请求/响应内容加密
api_public_keystringAPI平台公钥(Base64编码格式),用于响应验签

主要方法

post(string $apiPath, array $bizParams): string

发送POST请求到指定API路径。

参数:

  • $apiPath: API路径,如 /api/pay/create
  • $bizParams: 业务参数数组

返回:

  • 自动解密后的业务数据JSON字符串

示例:

$params = [
'order_no' => 'ORDER202401010001',
'amount' => 10000,
'subject' => '测试订单'
];

$result = $client->post('/api/pay/create', $params);

verifyNotify(array $notifyParams): bool

验证回调通知的签名。

参数:

  • $notifyParams: 回调参数数组

返回:

  • true: 验签成功
  • false: 验签失败

示例:

// 在你的控制器中
public function handleNotify(Request $request) {
$params = $request->json()->all();

// 验证签名
if (!$client->verifyNotify($params)) {
return 'FAIL';
}

// 获取业务数据(已自动解密)
$bizData = $client->decryptNotify($params['result']);
echo "回调数据: " . $bizData;

// 处理业务逻辑...

return 'SUCCESS';
}

完整代码实现

1. ClientConfig.php - 配置类

<?php

namespace KudianSDK\Model;

/**
* SDK配置类
*/
class ClientConfig
{
/**
* 网关地址
* @var string
*/
public $gatewayUrl;

/**
* 商户编号
* @var string
*/
public $mchId;

/**
* 应用ID
* @var string
*/
public $appId;

/**
* 应用私钥(Base64格式)
* @var string
*/
public $appPrivateKey;

/**
* API平台公钥(Base64格式)
* @var string
*/
public $apiPublicKey;

/**
* AES加密密钥
* @var string
*/
public $appSecretKey;

/**
* 连接超时时间(秒),默认30秒
* @var int
*/
public $connectTimeout = 30;

/**
* 读取超时时间(秒),默认30秒
* @var int
*/
public $readTimeout = 30;

/**
* 构造函数
*
* @param array $config 配置数组
*/
public function __construct(array $config = [])
{
if (isset($config['gateway_url'])) {
$this->gatewayUrl = $config['gateway_url'];
}
if (isset($config['mch_id'])) {
$this->mchId = $config['mch_id'];
}
if (isset($config['app_id'])) {
$this->appId = $config['app_id'];
}
if (isset($config['app_private_key'])) {
$this->appPrivateKey = $config['app_private_key'];
}
if (isset($config['api_public_key'])) {
$this->apiPublicKey = $config['api_public_key'];
}
if (isset($config['app_secret_key'])) {
$this->appSecretKey = $config['app_secret_key'];
}
if (isset($config['connect_timeout'])) {
$this->connectTimeout = $config['connect_timeout'];
}
if (isset($config['read_timeout'])) {
$this->readTimeout = $config['read_timeout'];
}
}
}

2. CryptoUtil.php - 加密工具类

<?php

namespace KudianSDK\Util;

/**
* 加密工具类
*/
class CryptoUtil
{
/**
* AES加密
*
* @param string $plainText 明文
* @param string $key 密钥
* @return string Base64编码的密文
* @throws \Exception 加密异常
*/
public static function aesEncrypt(string $plainText, string $key): string
{
// 确保密钥是32字节(AES-256)
$keyBytes = substr($key . str_repeat("\0", 32), 0, 32);

// AES加密
$cipher = 'aes-256-ecb';
$ivLength = openssl_cipher_iv_length($cipher);
$iv = str_repeat("\0", $ivLength);

$encrypted = openssl_encrypt($plainText, $cipher, $keyBytes, OPENSSL_RAW_DATA, $iv);
if ($encrypted === false) {
throw new \Exception('AES加密失败: ' . openssl_error_string());
}

return base64_encode($encrypted);
}

/**
* AES解密
*
* @param string $cipherText Base64编码的密文
* @param string $key 密钥
* @return string 明文
* @throws \Exception 解密异常
*/
public static function aesDecrypt(string $cipherText, string $key): string
{
// 确保密钥是32字节(AES-256)
$keyBytes = substr($key . str_repeat("\0", 32), 0, 32);

// AES解密
$cipher = 'aes-256-ecb';
$ivLength = openssl_cipher_iv_length($cipher);
$iv = str_repeat("\0", $ivLength);

$decoded = base64_decode($cipherText);
$decrypted = openssl_decrypt($decoded, $cipher, $keyBytes, OPENSSL_RAW_DATA, $iv);
if ($decrypted === false) {
throw new \Exception('AES解密失败: ' . openssl_error_string());
}

return $decrypted;
}

/**
* SHA256withRSA签名
*
* @param string $message 待签名消息
* @param string $privateKeyString 私钥字符串(Base64格式或PEM格式)
* @return string Base64编码的签名
* @throws \Exception 签名异常
*/
public static function signSHA256withRSA(string $message, string $privateKeyString): string
{
// 如果是Base64格式,先解码
$keyString = $privateKeyString;
if (strpos($privateKeyString, '-----') === false) {
// Base64格式,解码后添加PEM头
$decoded = base64_decode($privateKeyString);
$keyString = "-----BEGIN PRIVATE KEY-----\n" . chunk_split($decoded, 64, "\n") . "-----END PRIVATE KEY-----";
}

$privateKey = openssl_pkey_get_private($keyString);
if ($privateKey === false) {
throw new \Exception('私钥格式错误: ' . openssl_error_string());
}

$result = openssl_sign($message, $signature, $privateKey, OPENSSL_ALGO_SHA256);
if ($result === false) {
openssl_free_key($privateKey);
throw new \Exception('签名失败: ' . openssl_error_string());
}

openssl_free_key($privateKey);

return base64_encode($signature);
}

/**
* SHA256withRSA验签
*
* @param string $message 待验签消息
* @param string $publicKeyString 公钥字符串(Base64格式)
* @param string $sign Base64编码的签名
* @return bool true-验签成功,false-验签失败
*/
public static function verifySHA256withRSA(string $message, string $publicKeyString, string $sign): bool
{
// 如果是Base64格式,先解码
$keyString = $publicKeyString;
if (strpos($publicKeyString, '-----') === false) {
// Base64格式,解码后添加PEM头
$decoded = base64_decode($publicKeyString);
$keyString = "-----BEGIN PUBLIC KEY-----\n" . chunk_split($decoded, 64, "\n") . "-----END PUBLIC KEY-----";
}

$publicKey = openssl_pkey_get_public($keyString);
if ($publicKey === false) {
return false;
}

$signature = base64_decode($sign);
$result = openssl_verify($message, $signature, $publicKey, OPENSSL_ALGO_SHA256);

openssl_free_key($publicKey);

return $result === 1;
}
}

3. SignUtil.php - 签名工具类

<?php

namespace KudianSDK\Util;

/**
* 签名工具类
*/
class SignUtil
{
/**
* 生成签名字符串
* 将参数按ASCII码排序后拼接成 key1=value1&key2=value2 格式
*
* @param array $params 参数数组
* @return string 待签名字符串
*/
public static function makeSignString(array $params): string
{
// 过滤sign字段和空值
$filteredParams = [];
foreach ($params as $key => $value) {
if ($key !== 'sign' && $value !== '' && $value !== null) {
$filteredParams[$key] = (string)$value;
}
}

// 按ASCII码排序
ksort($filteredParams);

// 拼接字符串
$pairs = [];
foreach ($filteredParams as $key => $value) {
$pairs[] = $key . '=' . $value;
}

return implode('&', $pairs);
}
}

4. HttpClient.php - HTTP客户端接口

<?php

namespace KudianSDK\Http;

/**
* HTTP客户端接口
* 支持多种HTTP客户端实现
*/
interface HttpClient
{
/**
* 发送POST请求
*
* @param string $url 请求URL
* @param array $headers 请求头
* @param string $requestBody 请求体(JSON字符串)
* @return string 响应体(JSON字符串)
* @throws \Exception 请求异常
*/
public function post(string $url, array $headers, string $requestBody): string;
}

5. CurlClient.php - Curl客户端实现

<?php

namespace KudianSDK\Http;

/**
* 基于cURL的HTTP客户端实现
*/
class CurlClient implements HttpClient
{
/**
* @var int 连接超时时间(秒)
*/
private $connectTimeout;

/**
* @var int 读取超时时间(秒)
*/
private $readTimeout;

/**
* 构造函数
*
* @param int $connectTimeout 连接超时时间(秒),默认30秒
* @param int $readTimeout 读取超时时间(秒),默认30秒
*/
public function __construct(int $connectTimeout = 30, int $readTimeout = 30)
{
$this->connectTimeout = $connectTimeout;
$this->readTimeout = $readTimeout;
}

/**
* 发送POST请求
*
* @param string $url 请求URL
* @param array $headers 请求头
* @param string $requestBody 请求体(JSON字符串)
* @return string 响应体(JSON字符串)
* @throws \Exception 请求异常
*/
public function post(string $url, array $headers, string $requestBody): string
{
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectTimeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->connectTimeout + $this->readTimeout);

// 设置请求头
if (!empty($headers)) {
$headerArray = [];
foreach ($headers as $key => $value) {
$headerArray[] = "$key: $value";
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headerArray);
}

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);

curl_close($ch);

if ($error) {
throw new \Exception('cURL请求失败: ' . $error);
}

if ($httpCode !== 200) {
throw new \Exception('HTTP请求失败: ' . $httpCode);
}

return $response;
}
}

6. KudianClient.php - 主客户端类

<?php

namespace KudianSDK;

use KudianSDK\Http\HttpClient;
use KudianSDK\Model\ClientConfig;
use KudianSDK\Util\CryptoUtil;
use KudianSDK\Util\SignUtil;

/**
* 酷点支付SDK主客户端
*/
class KudianClient
{
/**
* @var ClientConfig 配置对象
*/
private $config;

/**
* @var HttpClient HTTP客户端
*/
private $httpClient;

/**
* @var CryptoUtil 加密工具
*/
private $cryptoUtil;

/**
* @var SignUtil 签名工具
*/
private $signUtil;

/**
* 构造函数
*
* @param ClientConfig|array $config 配置对象或配置数组
* @param HttpClient $httpClient HTTP客户端
*/
public function __construct($config, HttpClient $httpClient)
{
if (is_array($config)) {
$this->config = new ClientConfig($config);
} else {
$this->config = $config;
}
$this->httpClient = $httpClient;
$this->cryptoUtil = new CryptoUtil();
$this->signUtil = new SignUtil();
}

/**
* 发送POST请求
*
* @param string $apiPath API路径
* @param array $bizParams 业务参数
* @return string 解密后的业务数据JSON字符串
* @throws \Exception 请求异常
*/
public function post(string $apiPath, array $bizParams): string
{
// 1. 构造完整请求URL
$url = $this->config->gatewayUrl . $apiPath;

// 2. 将业务参数转换为JSON并加密
$bizJson = json_encode($bizParams, JSON_UNESCAPED_UNICODE);
$encryptedContent = $this->cryptoUtil->aesEncrypt($bizJson, $this->config->appSecretKey);

// 3. 构造公共参数
$publicParams = [
'mch_id' => $this->config->mchId,
'app_id' => $this->config->appId,
'timestamp' => (string)(int)(microtime(true) * 1000),
'nonce_str' => $this->generateNonceStr(),
'sign_type' => 'SHA',
'content' => $encryptedContent,
'version' => '2.0'
];

// 4. 生成签名
$signString = $this->signUtil->makeSignString($publicParams);
$sign = $this->cryptoUtil->signSHA256withRSA($signString, $this->config->appPrivateKey);
$publicParams['sign'] = $sign;

// 5. 发送请求
$requestBody = json_encode($publicParams, JSON_UNESCAPED_UNICODE);
error_log("请求URL: " . $url);
error_log("请求参数: " . $requestBody);

$headers = [
'Content-Type: application/json'
];

$responseBody = $this->httpClient->post($url, $headers, $requestBody);
error_log("响应结果: " . $responseBody);

// 6. 解析响应并验签
$response = json_decode($responseBody, true);
$code = (int)$response['code'];

if ($code === 0) {
// 成功响应,验证签名
$responseSign = $response['sign'] ?? '';
$verifyParams = [];
foreach ($response as $key => $value) {
// 排除sign字段
if ($key !== 'sign' && $value !== null) {
$verifyParams[$key] = (string)$value;
}
}

$verifyString = $this->signUtil->makeSignString($verifyParams);
$verifyResult = $this->cryptoUtil->verifySHA256withRSA(
$verifyString,
$this->config->apiPublicKey,
$responseSign
);

if (!$verifyResult) {
throw new \Exception('响应签名验证失败');
}

// 解密业务数据
$encryptedResult = $response['result'] ?? '';
$decryptedData = $this->cryptoUtil->aesDecrypt($encryptedResult, $this->config->appSecretKey);
error_log("解密后的业务数据: " . $decryptedData);

return $decryptedData;
} else {
// 失败响应
$msg = $response['msg'] ?? '未知错误';
throw new \Exception("请求失败: code={$code}, msg={$msg}");
}
}

/**
* 验证回调通知签名
*
* @param array $notifyParams 回调参数
* @return bool true-验签成功,false-验签失败
*/
public function verifyNotify(array $notifyParams): bool
{
$sign = $notifyParams['sign'] ?? '';
if ($sign === '') {
return false;
}

$verifyParams = $notifyParams;
$verifyString = $this->signUtil->makeSignString($verifyParams);

return $this->cryptoUtil->verifySHA256withRSA(
$verifyString,
$this->config->apiPublicKey,
$sign
);
}

/**
* 解密回调通知的业务数据
*
* @param string $encryptedResult 加密的业务数据
* @return string 解密后的业务数据JSON字符串
* @throws \Exception 解密异常
*/
public function decryptNotify(string $encryptedResult): string
{
return $this->cryptoUtil->aesDecrypt($encryptedResult, $this->config->appSecretKey);
}

/**
* 生成随机字符串
*
* @return string 随机字符串
*/
private function generateNonceStr(): string
{
return bin2hex(random_bytes(16));
}
}

可选实现

GuzzleClient.php - Guzzle客户端实现

<?php

namespace KudianSDK\Http;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

/**
* 基于Guzzle的HTTP客户端实现
*/
class GuzzleClient implements HttpClient
{
/**
* @var Client Guzzle客户端
*/
private $client;

/**
* 构造函数
*
* @param int $timeout 超时时间(秒),默认30秒
*/
public function __construct(int $timeout = 30)
{
$this->client = new Client([
'timeout' => $timeout,
'headers' => [
'Content-Type' => 'application/json'
]
]);
}

/**
* 发送POST请求
*
* @param string $url 请求URL
* @param array $headers 请求头
* @param string $requestBody 请求体(JSON字符串)
* @return string 响应体(JSON字符串)
* @throws \Exception 请求异常
*/
public function post(string $url, array $headers, string $requestBody): string
{
try {
$options = [
'body' => $requestBody,
'headers' => $headers
];

$response = $this->client->post($url, $options);

return (string)$response->getBody();
} catch (GuzzleException $e) {
throw new \Exception('Guzzle请求失败: ' . $e->getMessage());
}
}
}

StreamClient.php - Stream客户端实现(无依赖)

<?php

namespace KudianSDK\Http;

/**
* 基于Stream的HTTP客户端实现(无依赖,使用PHP标准库)
*/
class StreamClient implements HttpClient
{
/**
* @var int 连接超时时间(秒)
*/
private $connectTimeout;

/**
* @var int 读取超时时间(秒)
*/
private $readTimeout;

/**
* 构造函数
*
* @param int $connectTimeout 连接超时时间(秒),默认30秒
* @param int $readTimeout 读取超时时间(秒),默认30秒
*/
public function __construct(int $connectTimeout = 30, int $readTimeout = 30)
{
$this->connectTimeout = $connectTimeout;
$this->readTimeout = $readTimeout;
}

/**
* 发送POST请求
*
* @param string $url 请求URL
* @param array $headers 请求头
* @param string $requestBody 请求体(JSON字符串)
* @return string 响应体(JSON字符串)
* @throws \Exception 请求异常
*/
public function post(string $url, array $headers, string $requestBody): string
{
// 构造请求头字符串
$headerString = '';
foreach ($headers as $key => $value) {
$headerString .= "$key: $value\r\n";
}

// 构造Stream上下文
$options = [
'http' => [
'method' => 'POST',
'header' => $headerString,
'content' => $requestBody,
'timeout' => $this->connectTimeout + $this->readTimeout
],
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => true
]
];

$context = stream_context_create($options);

// 发送请求
$response = @file_get_contents($url, false, $context);

if ($response === false) {
$error = error_get_last();
throw new \Exception('HTTP请求失败: ' . ($error['message'] ?? '未知错误'));
}

return $response;
}
}

使用示例

完整示例:创建支付订单

<?php

require_once 'vendor/autoload.php';

use KudianSDK\KudianClient;
use KudianSDK\Http\CurlClient;

function main()
{
// 1. 创建配置
$config = [
'gateway_url' => 'https://pay.test.kudianvip.com',
'mch_id' => 'your_mch_id',
'app_id' => 'your_app_id',
'app_private_key' => '-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD...', // Base64或PEM格式的私钥
'api_public_key' => '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD...', // Base64或PEM格式的公钥
'app_secret_key' => 'your_secret_key_32_bytes' // 32字节的AES密钥
];

// 2. 创建客户端
$client = new KudianClient($config, new CurlClient());

try {
// 3. 构造业务参数
$bizParams = [
'order_no' => 'ORDER' . (int)(microtime(true) * 1000),
'amount' => 10000,
'currency' => 'CNY',
'subject' => '测试商品',
'notify_url' => 'https://your-domain.com/notify'
];

// 4. 发送请求
$result = $client->post('/api/pay/create', $bizParams);

// 5. 解析响应
$data = json_decode($result, true);

echo "支付订单创建成功!\n";
echo "订单号: " . $data['order_no'] . "\n";
echo "支付URL: " . $data['pay_url'] . "\n";

} catch (\Exception $e) {
echo "订单创建失败: " . $e->getMessage() . "\n";
}
}

main();

Laravel 回调通知处理示例

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use KudianSDK\KudianClient;
use KudianSDK\Http\CurlClient;

class PayNotifyController extends Controller
{
private $client;

public function __construct()
{
// 创建客户端(建议在AppServiceProvider中注册为单例)
$config = [
'gateway_url' => 'https://pay.kudianvip.com',
'mch_id' => 'your_mch_id',
'app_id' => 'your_app_id',
'app_private_key' => 'your_app_private_key',
'app_secret_key' => 'your_secret_key',
'api_public_key' => 'your_api_public_key'
];

$this->client = new KudianClient($config, new CurlClient());
}

public function handlePayNotify(Request $request)
{
try {
// 1. 验证签名
$params = $request->json()->all();
if (!$this->client->verifyNotify($params)) {
\Log::error('签名验证失败', $params);
return 'FAIL';
}

// 2. 解密业务数据
$bizData = $this->client->decryptNotify($params['result']);
\Log::info('收到支付回调', ['data' => $bizData]);

// 3. 解析业务数据并处理
$data = json_decode($bizData, true);
// TODO: 根据业务逻辑处理支付结果
// 更新订单状态、发货等

// 4. 返回成功
return 'SUCCESS';

} catch (\Exception $e) {
\Log::error('处理回调失败', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return 'FAIL';
}
}
}

ThinkPHP 回调通知处理示例

<?php

namespace app\controller;

use think\Request;
use think\facade\Log;
use KudianSDK\KudianClient;
use KudianSDK\Http\CurlClient;

class PayNotifyController
{
private $client;

public function initialize()
{
// 创建客户端
$config = [
'gateway_url' => 'https://pay.kudianvip.com',
'mch_id' => 'your_mch_id',
'app_id' => 'your_app_id',
'app_private_key' => 'your_app_private_key',
'app_secret_key' => 'your_secret_key',
'api_public_key' => 'your_api_public_key'
];

$this->client = new KudianClient($config, new CurlClient());
}

public function handlePayNotify(Request $request)
{
try {
// 1. 验证签名
$params = $request->post();
if (!$this->client->verifyNotify($params)) {
Log::error('签名验证失败', $params);
return 'FAIL';
}

// 2. 解密业务数据
$bizData = $this->client->decryptNotify($params['result']);
Log::info('收到支付回调', ['data' => $bizData]);

// 3. 解析业务数据并处理
$data = json_decode($bizData, true);
// TODO: 根据业务逻辑处理支付结果
// 更新订单状态、发货等

// 4. 返回成功
return 'SUCCESS';

} catch (\Exception $e) {
Log::error('处理回调失败', [
'error' => $e->getMessage()
]);
return 'FAIL';
}
}
}

原生 PHP 回调通知处理示例

<?php

require_once 'vendor/autoload.php';

use KudianSDK\KudianClient;
use KudianSDK\Http\CurlClient;

// 创建客户端
$config = [
'gateway_url' => 'https://pay.kudianvip.com',
'mch_id' => 'your_mch_id',
'app_id' => 'your_app_id',
'app_private_key' => 'your_app_private_key',
'app_secret_key' => 'your_secret_key',
'api_public_key' => 'your_api_public_key'
];
$client = new KudianClient($config, new CurlClient());

// 获取请求体
$input = file_get_contents('php://input');
$params = json_decode($input, true);

try {
// 1. 验证签名
if (!$client->verifyNotify($params)) {
error_log('签名验证失败');
echo 'FAIL';
exit;
}

// 2. 解密业务数据
$bizData = $client->decryptNotify($params['result']);
error_log('收到支付回调: ' . $bizData);

// 3. 解析业务数据并处理
$data = json_decode($bizData, true);
// TODO: 根据业务逻辑处理支付结果
// 更新订单状态、发货等

// 4. 返回成功
echo 'SUCCESS';

} catch (\Exception $e) {
error_log('处理回调失败: ' . $e->getMessage());
echo 'FAIL';
}

异常处理

SDK可能抛出的异常:

异常类型说明处理建议
\InvalidArgumentException配置参数错误检查配置参数是否完整和正确
\Exception签名验签失败检查密钥是否正确
\Exception加解密失败检查appSecretKey是否正确
\ExceptionHTTP请求失败检查网络连接和网关地址

常见问题

1. 如何获取密钥?

  • app_private_key: 商户自行生成RSA密钥对,将公钥上传到商户后台
  • api_public_key: 从商户后台获取平台公钥
  • secret_key: 从商户后台获取或设置

2. 如何生成RSA密钥对?

可以使用OpenSSL命令生成:

# 生成私钥
openssl genrsa -out app_private_key.pem 2048

# 提取公钥
openssl rsa -in app_private_key.pem -pubout -out app_public_key.pem

# 转换为PKCS8格式
openssl pkcs8 -topk8 -inform PEM -in app_private_key.pem -outform PEM -nocrypt -out app_private_key_pkcs8.pem

# PHP支持PEM格式,也可以直接使用PEM文件
# 或转换为Base64格式
base64 -w 0 app_private_key_pkcs8.pem
base64 -w 0 app_public_key.pem

3. 如何使用自定义HTTP客户端?

SDK支持自定义HTTP客户端实现,只需实现 HttpClient 接口:

use KudianSDK\Http\HttpClient;

// 使用内置的CurlClient
$client1 = new KudianClient($config, new CurlClient());

// 使用Guzzle客户端
$client2 = new KudianClient($config, new GuzzleClient());

// 自定义实现
class CustomHttpClient implements HttpClient
{
public function post(string $url, array $headers, string $requestBody): string
{
// 自定义HTTP客户端实现
// 例如使用其他HTTP库或添加特殊逻辑
return '';
}
}

$client3 = new KudianClient($config, new CustomHttpClient());

4. 日志配置

SDK使用 error_log 函数记录日志,可以在 PHP 配置中设置日志输出:

// 在应用初始化时配置日志
ini_set('error_log', '/path/to/sdk.log');

// 或者自定义错误处理器
set_error_handler(function($errno, $errstr, $errfile, $errline) {
// 自定义日志记录
file_put_contents('/path/to/custom.log', date('[Y-m-d H:i:s]') . " $errstr\n", FILE_APPEND);
});

5. Composer 依赖

{
"name": "your-vendor/kudian-sdk",
"description": "酷点支付SDK",
"type": "library",
"require": {
"php": "^7.4|^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"autoload": {
"psr-4": {
"KudianSDK\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"KudianSDK\\Tests\\": "tests/"
}
}
}

6. 目录结构

kudian-sdk/
├── src/
│ ├── Http/
│ │ ├── HttpClient.php
│ │ ├── CurlClient.php
│ │ ├── GuzzleClient.php
│ │ └── StreamClient.php
│ ├── Model/
│ │ └── ClientConfig.php
│ ├── Util/
│ │ ├── CryptoUtil.php
│ │ └── SignUtil.php
│ └── KudianClient.php
├── tests/
│ └── KudianClientTest.php
├── composer.json
└── README.md
预约咨询