必须先url安全base64解码、再分离iv、最后用openssl_decrypt配合正确标志解密;跳过任一预处理步骤均导致失败。

PHP 中如何安全地解密 GET 参数
直接对 URL 中的 $_GET 参数做“解密”,前提是这些参数**确实是加密后编码传入的**。如果只是普通 URL 参数(比如 ?id=123),不存在“解密”一说;强行套用解密逻辑,只会报错或返回乱码。真实场景中,加密 GET 参数通常用于防篡改、隐藏原始值(如订单 ID、用户 ID),常见做法是:服务端加密 → Base64 URL 安全编码 → 拼入 URL → 客户端请求 → 服务端接收 → 解码 → 解密。
解密前必须完成的三步预处理
跳过任何一步都可能导致 openssl_decrypt() 返回 false 或警告“Invalid ciphertext”。
- 从
$_GET中取出参数值(如$_GET['token']),并确认它不为空且长度合理(比如短于 500 字符) - 对参数值做 URL 安全 Base64 解码:
str_replace(['-', '_'], ['+', '/'], $encoded),再用base64_decode();否则openssl_decrypt()会因填充错误失败 - 检查解码后数据是否包含完整的 IV(通常前 16 字节为 AES-128-CBC 的 IV,剩余为密文),否则无法分离出初始化向量,解密必然失败
使用 openssl_decrypt 正确还原明文
不要硬编码密钥或忽略选项。AES-CBC 模式下,IV 必须与加密时完全一致,且 OPENSSL_ZERO_PADDING 和 OPENSSL_RAW_DATA 标志缺一不可。
function decryptGetParam(string $encrypted, string $key): ?string
{
$decoded = base64_decode(str_replace(['-', '_'], ['+', '/'], $encrypted));
if ($decoded === false || strlen($decoded) < 16) {
return null;
}
$iv = substr($decoded, 0, 16);
$ciphertext = substr($decoded, 16);
$plaintext = openssl_decrypt($ciphertext, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
return $plaintext === false ? null : $plaintext;
}
注意:$key 必须是 16 字节(不是 16 个字符!),建议用 hash('sha256', $your_secret, true) 截取前 16 字节生成;若用字符串字面量,需确认 strlen($key) === 16,否则会静默失败。
立即学习“PHP免费学习笔记(深入)”;
为什么 file_get_contents('php://input') 对 GET 参数无效
php://input 只能读取原始 POST 请求体,在 GET 请求中始终为空。试图用它获取 $_GET 参数是典型误解。所有 URL 查询参数都已由 PHP 解析进 $_GET 超全局数组,直接读取即可。混淆点常出现在:前端用 fetch 发 GET 但 body 里塞了 JSON(这是非法的),后端误以为要读 php://input —— 实际应检查是否本该用 POST。
真正容易被忽略的是:加密参数在 Nginx/Apache 中可能被自动解码或截断(比如含 + 被转为空格,含 %2F 被拒绝)。务必在 Web 服务器日志里确认接收到的原始 QUERY_STRING 是否与前端发出的一致。











