<?php
|
|
namespace app\home\controller;
|
|
/**
|
* PHP版万里汇API签名生成工具
|
* 对应JavaScript逻辑:RSA-SHA256签名 + Base64编码
|
*/
|
|
use app\BaseController;
|
use think\facade\Request;
|
|
class Testpay extends BaseController
|
{
|
private $config = [
|
'domain' => 'https://open-sea.worldfirst.com', // 万里汇支付域名
|
'is_sandbox' => 1, // 是否沙箱环境,true为沙箱环境,false为正式环境
|
'ClientID' => '5YEU5A2ZUGHC03903', //商户id
|
'CustomerId' => '2120120341978772', //商户id
|
'CertificationType' => 'RSA2', //商户密钥
|
'publicKey' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsQrc4mu33M3lo+EehBo+/GHmBTC4OdyqdkbB9YAUWH1xfHa3o6frFTS0JhgZa3RX7W5g4AGMhNynaytsErFaUVuij95rQhU5rVIPAE6mxlmjZMQszzOjJZdLuEe8uQIlzxbdgJZ6s1qElrJzfCoBl3UP/3h4e29Wyfp0c9rKg8/PT5TIM5MkL0X5Bs/gU3sclziAO/HVkgSqeOVah4HRYOjTxJeLv4UlkJr7iSXshv0THDIdFbwi9b83yclOTdqZpReo41Bec8SAEQz8ITb81iFHVRuCxKL7ZtRIjlMIZHbZdZdQijZfVsMrD0Y/7eK8tuCpfvBRCsxLOaUH5Tkx6wIDAQAB', //公钥
|
'privateKey' => 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCxCtzia7fczeWj4R6EGj78YeYFMLg53Kp2RsH1gBRYfXF8drejp+sVNLQmGBlrdFftbmDgAYyE3KdrK2wSsVpRW6KP3mtCFTmtUg8ATqbGWaNkxCzPM6Mll0u4R7y5AiXPFt2AlnqzWoSWsnN8KgGXdQ//eHh7b1bJ+nRz2sqDz89PlMgzkyQvRfkGz+BTexyXOIA78dWSBKp45VqHgdFg6NPEl4u/hSWQmvuJJeyG/RMcMh0VvCL1vzfJyU5N2pmlF6jjUF5zxIARDPwhNvzWIUdVG4LEovtm1EiOUwhkdtl1l1CKNl9WwysPRj/t4ry24Kl+8FEKzEs5pQflOTHrAgMBAAECggEBAI4mp7ZRQT7UP3d3EPaG0F37CSLPvIwRBvmS1LeXED8A8fc6pzaLZDERsTgJD5f8wYDNqJEUDUy8ktx08ACOUHOUvREBSGO2ASqOAaeAf14xqQUGkugHkQ5kzZJ4Xyq5c7w0osNVj82kd2M8g4eFfuOqRZ8djrelbS0doRVI7mQoQyxb2ms4priD4Zgv+YqnGIQz9++f9aguCpmTRLp8VC/N4CqszLhJ3N4f+X4sAfttPbkT1lKXXB4Gx1oBnpDwXpxfvocC2E4xwBprr7pVqlvMkpdmZnDBHgAk4nLISk3hv3kLC9FVVfhEgpJJlMUW0Qb3IbPx64UgV9k9pCCsSXECgYEA/ap6WAstyS3zZDAacazhqCbVDc6/IPQW6Y78ahObpV9ViCVoDPiYVimStNIZKQvCOIwo9N5PHeCNHNOp30DoY1MOV26vu9hFLGqukoIAsMhM9c9E1ZtN0IkSzTK5eP0vKHLTeB4vuq2f6eR7g4bHNRLfHplE6smFNZ4/ZW9w1hkCgYEAsqvlCA5/0j13IuVORY2iVmQ2xC86fjTRRmpZ0KRPauUjp25WIYZUc/Dh2sAwT62digL7lPTXJ9dXyGEkiMxVrck9wN6fsdgmFkcAbOQeI5v0hc/NBmsfuhNH5Lmho/ZFbrAE2ha8viK5zBZr6ZIha7d8EFQZ+6TFoeBHISDD4KMCgYBXdqGKnAgkduCWKfPkQCzqcsFBaokCTsdbrr6fwLUJF08Bi4xN9KVqCBmamVqtiW1lXAZ/L+vtrFBboSvQW6wFG001nmefiFmJkBszTvn3+oh2tQnR8SOqhKjj8dp7uii5dKYvo5DneBhMaEiiOCWVyjT+cvCNWADDVRYc3oj0eQKBgDxzFekU5sAd1Znz1PiJQ9xQyYq0o+ihPBDD2KFThh8XaWmzVea/yQD1BaT6Ex5SEhPokG/EKqsrG2MLIs45u98xT/haGdOU2sX8vbMZtuy7Tg6b0LUUN0bAUTmcaIjNwI4DdZDH0pHNs+jNyTLcIvyLtqjbm3LdO5RaCha2PC9bAoGAHDRox1+xXWJ1p1qMu73kmTjwTNIgtfZkV5un5KybpLLkpF28K61yGNTGHXN8mnNxWYiITb6LzO7OB2A97YmlVB2DYBkDfSLIL2kWCsDnHA5iiWewmrm2t3079YgiRWtN224/z+CVspaiOKgypLZzyxrPfqajXjwwOEEVkb7HO4o=', //商户私钥privateKey
|
];
|
public function index()
|
{
|
// 从表单获取的参数(模拟$_POST)
|
//获取请求时间(<Request-Time>) 为 2022-04-28T12:31:30+08:00,时间遵循ISO 8601标准
|
$requestTime = date('Y-m-d\TH:i:sP');
|
$clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID'];
|
$post_data = ["paymentId" => "202205311234234"];
|
// 包裹私钥
|
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----";
|
$publicKey = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->config['publicKey'], 64, "\n", true) . "\n-----END PUBLIC KEY-----";
|
$httpMethod = 'POST'; // 请求方法(GET/POST等)
|
$api_url = '/amsin/api/v1/business/inquiryPayOrder'; // 请求API路径
|
$bodyData = json_encode($post_data); // 请求体JSON字符串
|
$params = [
|
'clientId' => $clientId,
|
//'customerId' => $this->config['CustomerId'],
|
'requestTime' => $requestTime,
|
'httpMethod' => $httpMethod,
|
'api' => $api_url,
|
'bodyData' => $bodyData,
|
'privkey' => $privateKey,
|
];
|
$signatureBody = $this->getSignatureBody($post_data, $httpMethod, $api_url, $requestTime);
|
// 生成签名
|
$signature = $this->generateSignature($signatureBody, $privateKey);
|
|
// 验证签名示例(需要公钥)
|
$isValid = $this->verifySignature(
|
$signatureBody,
|
$signature,
|
$publicKey
|
);
|
$params['signature'] = $signature;
|
$params['isValid'] = $isValid;
|
return dhkSuccess($params);
|
echo $signature;
|
}
|
public function getFirst()
|
{
|
$post_data = [
|
"inquiryRateConditionList" => [
|
[
|
"sellCurrency" => "USD",
|
"buyCurrency" => "EUR"
|
],
|
[
|
"sellCurrency" => "USD",
|
"buyCurrency" => "GBP"
|
]
|
]
|
];
|
$requestTime = date('Y-m-d\TH:i:sP');
|
$httpMethod = 'POST'; // 请求方法(GET/POST等)
|
|
$api_url = '/amsin/api/v1/business/inquiryPayOrder'; //支付完成后,集成商可以使用此接口来查询支付结果。
|
$signatureBody = $this->getSignatureBody($post_data, $httpMethod, $api_url, $requestTime);
|
// 包裹私钥
|
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----";
|
|
// 生成签名
|
$signature = $this->generateSignature($signatureBody, $privateKey);
|
$post_url = $this->config['domain'] . $api_url;
|
$header = [];
|
$clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID'];
|
$header['client-id'] = $clientId;
|
$header['request-time'] = $requestTime;
|
$header['Content-Type'] = 'application/json';
|
$header['signature'] = 'algorithm=RSA256,keyVersion=1,signature=' . $signature;
|
$dhkhttp = new \app\common\toole\Dhkhttp();
|
echo_dhklog($api_url, '请求地址:', 'pay_notify');
|
$res = $dhkhttp->dhkpost($post_url, $post_data, $header);
|
return dhkSuccess($res);
|
}
|
//查询支付状态http://zhc.test.com/home/testpay/query?pay_code=202504171234234
|
public function query()
|
{
|
$params = Request::param();
|
$payToRequestId = $params['pay_code'] ?? ''; //商户生成的支付单号
|
$payToId = $params['payToId'] ?? ''; //万里汇生成的支付单号
|
if (!$payToRequestId and !$payToId) {
|
return dhkMsg('支付单号不能为空');
|
}
|
$post_data = [];
|
if ($payToRequestId) {
|
$payToRequestIds = [$payToRequestId];
|
$post_data['payToRequestIds'] = $payToRequestIds;
|
}
|
if ($payToId) {
|
$payToIds = [$payToId];
|
$post_data['payToIds'] = $payToIds;
|
}
|
$requestTime = date('Y-m-d\TH:i:sP');
|
$httpMethod = 'POST'; // 请求方法(GET/POST等)
|
|
$api_url = '/amsin/api/v1/business/inquiryPayOrder'; //支付完成后,集成商可以使用此接口来查询支付结果。
|
$signatureBody = $this->getSignatureBody($post_data, $httpMethod, $api_url, $requestTime);
|
// 包裹私钥
|
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----";
|
|
// 生成签名
|
$signature = $this->generateSignature($signatureBody, $privateKey);
|
$post_url = $this->config['domain'] . $api_url;
|
$header = [];
|
$clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID'];
|
$header['client-id'] = $clientId;
|
$header['request-time'] = $requestTime;
|
$header['Content-Type'] = 'application/json';
|
$header['signature'] = 'algorithm=RSA256,keyVersion=1,signature=' . $signature;
|
$dhkhttp = new \app\common\toole\Dhkhttp();
|
$res = $dhkhttp->dhkpost($post_url, $post_data, $header);
|
return dhkSuccess($res);
|
}
|
public function notify()
|
{
|
$params = Request::param();
|
echo_dhklog($params, '支付通知data:', 'pay_notify');
|
$headers = Request::header();
|
echo_dhklog($headers, '支付通知header:', 'pay_notify');
|
$requestTime = $headers['request-time'] ?? ''; //请求时间
|
$signature = $headers['signature'] ?? ''; //签名
|
//algorithm=RSA256,keyVersion=1,signature=IHZfFMPNQITqmz%2FDZTlm6DEfm6yfR3NtK0LkONscZxZLqOuCa5b%2FDyLGqwZaSrGIQeFFNnGS5EgqRtFFdOmBSuSSiwK%2BjvhnIE6qHP7xr%2BjBpjFFztTOyyniGJdN5HlT8UE2wONjPIsIMh8koXa6Kb8uh1ScnCGbTzY8ogfihupFXJt%2B1%2BHPYno9483cVyA2l9UOYb6ai6SWgAxnJJUWi%2BkBQLXp%2FzvRG6SmDETbZ8MpMM2gUTbRGB4p4eSqVcX6KgwVyLSgrzAGekPv6dkZOH5zulHCv%2FmMXdO3%2FWmQn%2FX2rS1unS9yilDJbzDW86XwUf46UD2qgxkFGi6UPWaTfw%3D%3D
|
//从$signature中提取signature=后面的内容
|
$signature = str_replace('algorithm=RSA256,keyVersion=1,signature=', '', $signature);
|
echo_dhklog($signature, 'HEADER签名', 'pay_notify');
|
|
|
$clientId = $headers['client-id'] ?? '';
|
$httpMethod = 'POST';
|
$api_url = '/home/testpay/notify';
|
// 包裹私钥
|
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----";
|
|
$res = ["result" => ["resultStatus" => "S", "resultCode" => "SUCCESS", "resultMessage" => "success"]];
|
$signatureBody = $this->getSignatureBody($params, $httpMethod, $api_url, $requestTime);
|
// 生成签名
|
$signature_new = $this->generateSignature($signatureBody, $privateKey);
|
if ($signature_new != $signature) {
|
echo_dhklog($signature_new, '签名不匹配', 'pay_notify');
|
} else {
|
echo_dhklog('验证通过', '签名匹配', 'pay_notify');
|
}
|
//返回响应头
|
header('Content-Type: application/json');
|
header('client-id: ' . $clientId);
|
header('request-time: ' . $requestTime);
|
header('signature: algorithm=RSA256,keyVersion=1,signature=' . $signature_new);
|
return json($res);
|
}
|
|
//1. 构造待签名字符串(与JavaScript逻辑完全一致)
|
public function getSignatureBody($post_data = [], $httpMethod = 'POST', $api_url = '', $requestTime = '')
|
{
|
$bodyData = json_encode($post_data);
|
$clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID'];
|
$signatureBody = sprintf(
|
"%s %s\n%s.%s.%s",
|
strtoupper($httpMethod),
|
$api_url,
|
$clientId,
|
$requestTime,
|
$bodyData
|
);
|
return $signatureBody;
|
}
|
/**
|
* 生成签名
|
* @param string $clientId 商户ID
|
* @param string $requestTime 请求时间戳
|
* @param string $httpMethod HTTP方法(GET/POST等)
|
* @param string $api 请求API路径
|
* @param string $bodyData 请求体JSON字符串
|
* @param string $privateKey 私钥(PEM格式)
|
* @return string 返回URL编码后的签名
|
*/
|
public static function generateSignature($signatureBody, $privateKey): string
|
{
|
// 2. 使用私钥进行SHA256签名
|
$signature = '';
|
if (!openssl_sign($signatureBody, $signature, $privateKey, OPENSSL_ALGO_SHA256)) {
|
// 输出错误信息
|
echo_dhklog(openssl_error_string(), 'OpenSSL错误', 'pay_notify');
|
return '';
|
}
|
// 3. Base64编码签名
|
$ss = base64_encode($signature);
|
echo_dhklog($ss, '签名', 'pay_notify');
|
// 4. URL编码签名,非必要
|
$ss = urlencode($ss);
|
return $ss;
|
}
|
|
/**
|
* 验证签名(可选)
|
*/
|
public static function verifySignature(
|
string $plainText,
|
string $signature,
|
string $publicKey
|
): bool {
|
$signature = base64_decode(urldecode($signature));
|
return (bool)openssl_verify(
|
$plainText,
|
$signature,
|
$publicKey,
|
OPENSSL_ALGO_SHA256
|
);
|
}
|
}
|