短链接怎么加密后还原php_双向加密解密流程汇总【汇总】

短链接加密本质是ID映射而非密码学加密,采用Base62编码+自增ID映射实现高效、安全、无密钥的短码生成与还原,可辅以异或等轻量混淆防枚举。

短链接加密本质是 ID 映射,不是密码学加密

短链接服务里所谓“加密”,实际是把原始 URL 对应的数据库自增 id(比如 12345)转换成一串短字符串(比如 aB3xK),还原时再把 aB3xK 解回 12345,查库取原 URL。它不涉及 AES、RSA 等双向密码学加解密,也不需要密钥管理——混淆 ≠ 加密。

强行套用 openssl_encryptmcrypt 反而引入安全风险(如 IV 泄露、填充攻击)和性能开销,且无法支持高并发短码生成与反查。

推荐方案:Base62 编码 + 自增 ID 映射

这是生产环境最常用、最轻量、最可控的方式。核心逻辑是:入库后取 lastInsertId() → 转 Base62 → 存入短码字段;访问时 Base62 解码 → 得到 ID → 查库。

  • Base62 字符集为 0-9a-zA-Z(共 62 字符),比 Base64 少 +/,避免 URL 编码问题
  • PHP 中无需扩展,用 strtr()base_convert() 组合即可实现(注意 base_convert() 不支持 62 进制,需手写)
  • 避免重复:插入前先查是否存在该短码,或用唯一索引 + 重试机制
  • 示例编码函数:
function idToShort($id) {
    $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $short = '';
    while ($id > 0) {
        $short = $chars[$id % 62] . $short;
        $id = (int)($id / 62);
    }
    return $short ?: '0';
}

function shortToId($short) { $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $id = 0; for ($i = 0; $i < strlen($short); $i++) { $id = $id * 62 + strpos($chars, $short[$i]); } return $id; }

想加一层混淆?用固定异或或位移,别碰真实加密函数

如果业务要求“不让 ID 规律暴露”(比如防止爬虫枚举),可在 Base62 前对原始 id 做轻量混淆,例如:

  • 异或一个固定数:$obfId = $id ^ 0x5A3F9C1E;
  • 左移再异或:$obfId = (($id
  • 必须保证运算可逆,且结果仍为正整数、不溢出(尤其在 32 位 PHP 上)
  • 切勿使用 md5()sha1() 等单向哈希,它们不可还原
  • 更别用 openssl_encrypt() 输出二进制或 base64,会导致短码变长、含非法字符

为什么不要用 openssl\_encrypt / mcrypt 做短链加解密

常见错误是把短链接当成敏感数据去“加密”,结果踩坑:

  • openssl_encrypt 输出是二进制或 base64 字符串(如 U2FsdGVkX1+...),长度远超 6~8 字符,失去“短”意义
  • IV 必须随文传输或固定,固定 IV 会降低安全性;随文传输又增加存储/解析负担
  • 不同 PHP 版本对 mcrypt 支持不一,已废弃;openssl 模式、填充、密钥长度稍有偏差就 decrypt 失败,调试极痛苦
  • 数据库查短码时,你没法用 WHERE short = ? 直接匹配加密后的乱码——除非全表解密扫描,性能归零

真正需要加密的,是原始 URL 本身(比如含用户 token),那应该单独字段 AES 加密存储,而不是拿它去生成短码。