
PHP 使用 password_hash() 生成的哈希值在写入 MySQL 后无法通过 password_verify() 验证,根本原因常是 PHP 源文件编码不一致(如含 BOM 或混合 ANSI/UTF-8),导致哈希字符串被静默截断或污染。
php 使用 `password_hash()` 生成的哈希值在写入 mysql 后无法通过 `password_verify()` 验证,根本原因常是 php 源文件编码不一致(如含 bom 或混合 ansi/utf-8),导致哈希字符串被静默截断或污染。
该问题看似与数据库字段类型(VARCHAR(255))、字符集(utf8mb4_unicode_ci)或 PHP 版本(7→8)相关,实则根源在于PHP 文件自身编码污染了哈希字符串的生成或传输过程。
password_hash() 生成的哈希(如 bcrypt 或 Argon2)是严格 ASCII 的 Base64-like 字符串(仅含 a-z、A-Z、0-9、$、/、. 等),不包含任何 Unicode 或不可见控制字符。但若 PHP 文件以带 BOM 的 UTF-8、UTF-16 或混合编码保存,当脚本执行时,BOM(如 EF BB BF)或非法字节可能被意外拼接到 $newPassword 变量前/后——尤其在 password_hash() 调用前后存在不可见空白、注释或字符串拼接时。这种污染在 INSERT/UPDATE 过程中会被完整写入数据库,而 SELECT 返回时同样携带污染字符,导致 password_verify() 因输入哈希不合法而静默返回 false。
✅ 正确做法:统一并清理所有 PHP 文件编码
使用以下命令递归将项目内所有 .php 文件转为 无 BOM 的 UTF-8:
# Linux/macOS(推荐)
find /path/to/your/project -name "*.php" -exec iconv -f UTF-8 -t UTF-8//IGNORE {} \; -exec sed -i '1s/^\xEF\xBB\xBF//' {} \;
# 或更稳妥地使用 dos2unix + recode(避免 BOM)
find /path/to/your/project -name "*.php" -exec dos2unix {} \; 2>/dev/nullWindows 用户可使用 VS Code:打开文件 → 右下角编码显示(如 “UTF-8 with BOM”)→ 点击 → 选择 “Save with Encoding” → “UTF-8”(明确不含 BOM)。
⚠️ 关键注意事项:
立即学习“PHP免费学习笔记(深入)”;
- 不要依赖 mb_convert_encoding() 或 iconv 在运行时“修复”哈希——哈希必须原生纯净;
- 数据库字段 VARCHAR(255) 和 utf8mb4 是正确且充分的,无需修改;
- PASSWORD_DEFAULT 在 PHP 8 中仍完全兼容,非版本问题;
- 在密码重置逻辑中,建议增加哈希有效性校验(防御性编程):
$newPassword = password_hash($password, PASSWORD_DEFAULT);
if (!is_string($newPassword) || strlen($newPassword) < 60) {
throw new RuntimeException('Invalid hash generated');
}最终验证:将数据库中存储的哈希值复制出来,在独立脚本中直接 var_dump($hash) —— 应严格匹配 password_hash() 原始输出(无空格、无换行、无隐藏字符)。一旦编码统一,password_verify() 将稳定通过,登录流程恢复正常。



















