$v) { if (is_array($v)) { // 关键:在 JSON 编码前对数组进行递归排序 //$v = self::sortArrayRecursive($v); $v = json_encode($v, JSON_UNESCAPED_UNICODE); } if ($platform == 'shansong') { $str .= "{$k}{$v}"; } else { $str .= "{$k}={$v}&"; } } $str = rtrim($str, '&'); switch (strtolower($method)) { case 'hmac_sha256': $sign = hash_hmac('sha256', $str, $secret); break; case 'sha256': if ($platform == 'fengniao') { $sign = $secret . $str; } else { $sign = $str . $secret; } $sign = hash('sha256', $sign); break; case 'md5': default: if ($platform == 'shansong') { $sign = $secret . $str; } else { $sign = $str . $secret; } $sign = md5($sign); break; } return strtoupper($sign); } /** * 验证签名(用于第三方回调) */ public static function verify(array $params, string $secret, string $signKey = 'sign', string $method = 'md5') { if (!isset($params[$signKey])) return false; $sign = $params[$signKey]; unset($params[$signKey]); $expect = self::makeSign($params, $secret, $method); return strtoupper($sign) === strtoupper($expect); } /** * 递归过滤数组中的空值(null、空字符串、空数组) * 确保签名时不包含空值参数 * * @param array $data 需要过滤的数组 * @return array 过滤后的数组 */ private static function filterEmptyValues($data) { $filtered = []; foreach ($data as $key => $value) { // 过滤掉 null、空字符串、空数组 if ($value === null || $value === '' || (is_array($value) && empty($value))) { continue; } // 如果是数组,递归处理 if (is_array($value)) { $value = self::filterEmptyValues($value); // 递归过滤后如果变成空数组,也要跳过 if (empty($value)) { continue; } } $filtered[$key] = $value; } return $filtered; } /** * 递归对数组进行排序(包括嵌套数组) * 确保 JSON 编码时键的顺序一致 * * @param array $arr 需要排序的数组 * @return array 排序后的数组 */ private static function sortArrayRecursive($arr) { if (!is_array($arr)) { return $arr; } // 对当前数组进行排序 ksort($arr); // 递归处理嵌套数组 foreach ($arr as $key => $value) { if (is_array($value)) { $arr[$key] = self::sortArrayRecursive($value); } } return $arr; } }