90 行
3.1 KiB
PHP
90 行
3.1 KiB
PHP
<?php
|
||
|
||
namespace addons\shopro_huifu\library;
|
||
|
||
use think\Request;
|
||
|
||
/**
|
||
* 解析汇付异步通知原始报文(不可走 htmlspecialchars 等全局 filter)
|
||
*/
|
||
class HuifuNotifyParser
|
||
{
|
||
public static function parse(Request $request = null)
|
||
{
|
||
$request = $request ?: Request::instance();
|
||
|
||
// 优先从原始 body 解析,避免 PHP 将 form 中 Base64 签名的 + 转成空格
|
||
$raw = method_exists($request, 'getInput') ? (string) $request->getInput() : '';
|
||
if ($raw === '') {
|
||
$raw = (string) file_get_contents('php://input');
|
||
}
|
||
if ($raw !== '') {
|
||
$contentType = strtolower((string) $request->contentType());
|
||
if (strpos($contentType, 'application/json') !== false) {
|
||
$decoded = json_decode($raw, true);
|
||
if (is_array($decoded)) {
|
||
$sign = self::normalizeSign((string) ($decoded['sign'] ?? ''));
|
||
$respData = $decoded['resp_data'] ?? '';
|
||
if (is_array($respData)) {
|
||
$respData = json_encode($respData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||
}
|
||
return [
|
||
'sign' => $sign,
|
||
'resp_data' => (string) $respData,
|
||
];
|
||
}
|
||
} else {
|
||
$parsed = self::parseFormPreservePlus($raw);
|
||
if (!empty($parsed['resp_data']) || !empty($parsed['sign'])) {
|
||
return $parsed;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!empty($_POST['resp_data']) || !empty($_POST['sign'])) {
|
||
return [
|
||
'sign' => self::normalizeSign((string) ($_POST['sign'] ?? '')),
|
||
'resp_data' => (string) ($_POST['resp_data'] ?? ''),
|
||
];
|
||
}
|
||
|
||
return ['sign' => '', 'resp_data' => ''];
|
||
}
|
||
|
||
/**
|
||
* parse_str 会把 + 解码为空格,会破坏 Base64 签名
|
||
*/
|
||
protected static function parseFormPreservePlus($raw)
|
||
{
|
||
$parsed = [];
|
||
parse_str(str_replace('+', '%2B', $raw), $parsed);
|
||
|
||
$sign = self::normalizeSign((string) ($parsed['sign'] ?? ''));
|
||
$respData = (string) ($parsed['resp_data'] ?? '');
|
||
|
||
if ($respData === '' && isset($parsed['data']) && is_string($parsed['data'])) {
|
||
$inner = json_decode($parsed['data'], true);
|
||
if (is_array($inner)) {
|
||
$respData = $inner['resp_data'] ?? '';
|
||
if (is_array($respData)) {
|
||
$respData = json_encode($respData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||
}
|
||
$respData = (string) $respData;
|
||
if ($sign === '' && !empty($inner['sign'])) {
|
||
$sign = self::normalizeSign((string) $inner['sign']);
|
||
}
|
||
}
|
||
}
|
||
|
||
return [
|
||
'sign' => $sign,
|
||
'resp_data' => $respData,
|
||
];
|
||
}
|
||
|
||
public static function normalizeSign($sign)
|
||
{
|
||
return str_replace(' ', '+', trim((string) $sign));
|
||
}
|
||
}
|