$value) { if ($key === 'sign') { continue; } if ($value === '' || $value === null) { continue; } $filtered[$key] = $value; } ksort($filtered, SORT_STRING); $pairs = []; foreach ($filtered as $key => $value) { // 原始值拼接,不做 urlencode $pairs[] = $key . '=' . (is_bool($value) ? ($value ? '1' : '0') : (string)$value); } return implode('&', $pairs); } /** * MD5 签名 * - 若提供 secret,则原串末尾追加 &key=SECRET * - 返回 32 位小写 * * @param string $signString * @param string|null $secret * @return string */ protected static function signMd5($signString, $secret = null) { if ($secret !== null && $secret !== '') { $signString .= '&key=' . $secret; } return strtolower(md5($signString)); } /** * RSA 签名 * * @param string $signString * @param array $options 必填:private_key,可选:passphrase * @param string $hashAlgo sha256|sha1 * @return string base64 签名 * @throws \InvalidArgumentException */ protected static function signRsa($signString, array $options, $hashAlgo = 'sha256') { if (empty($options['private_key'])) { throw new \InvalidArgumentException('RSA signing requires private_key.'); } $privateKey = $options['private_key']; $passphrase = isset($options['passphrase']) ? (string)$options['passphrase'] : ''; // 兼容无头尾私钥,自动包裹为 PEM if (strpos($privateKey, 'BEGIN') === false) { $privateKey = "-----BEGIN PRIVATE KEY-----\n" . trim(chunk_split(str_replace(["\r", "\n"], '', $privateKey), 64, "\n")) . "\n-----END PRIVATE KEY-----"; } $pkeyId = openssl_pkey_get_private($privateKey, $passphrase); if ($pkeyId === false) { throw new \InvalidArgumentException('Invalid RSA private key or passphrase.'); } $signature = ''; $algoConst = $hashAlgo === 'sha1' ? OPENSSL_ALGO_SHA1 : OPENSSL_ALGO_SHA256; $ok = openssl_sign($signString, $signature, $pkeyId, $algoConst); openssl_free_key($pkeyId); if (!$ok) { throw new \InvalidArgumentException('OpenSSL sign failed.'); } return base64_encode($signature); } }