跳到主内容

WordPress 7.2 默认关闭 NO_BACKSLASH_ESCAPES:反斜杠转义、会踩的坑与 db.php 兜底

100%
WordPress 7.2 默认关闭 NO_BACKSLASH_ESCAPES:反斜杠转义、会踩的坑与 db.php 兜底

结论先说:WordPress 7.2 把 NO_BACKSLASH_ESCAPES 正式列入「 WordPress 不支持的 SQL 模式」,并在每次连接数据库时把它从会话里剔除。对绝大多数站点,升级后什么都不会变;真正受影响的是两类人:被主机商强行打开过这个模式的站点(它们此前一直在悄悄出数据错误),以及依赖反斜杠字面量的插件或自定义查询(它们必须改用绑定参数或改写 SQL)。本文讲清三件事:这个模式到底改了什么行为、你现在的环境是不是踩在上面、以及万一真的需要它该怎么兜底。

一、这次核心改了什么

改动本身只有几行逻辑。 WordPress 连上数据库后会执行一次「设置会话 SQL 模式」的动作,把一堆它不支持的模式从会话里去掉。此前名单里已有 STRICT_ALL_TABLES、TRADITIONAL、ANSI,7.2 起新增 NO_BACKSLASH_ESCAPES。

关键点在于 作用范围:

  • 只改 WordPress 这一条连接的会话变量,不碰服务器的全局设置;
  • 不写配置文件、不需要重启 MySQL;
  • 其他程序(同一台机器上的别的站点、报表工具、命令行客户端)完全不受影响。

这种「只收缩自己那条连接」的做法值得学。数据库是共享资源,WordPress 作为租户之一,正确姿态是调整自己的会话约定,而不是替所有人改服务器参数。想了解 7.2 的整体节奏,可以对照7.2 路线图和发布派对日程一起看。

二、为什么一个转义约定值得单独发开发通告

因为反斜杠在 MySQL 里承担了「转义字符」的角色,而 WordPress 的数据库层大量依赖这个约定。举个最小例子:

-- 默认模式(反斜杠是转义符)
SELECT 'It\'s here';
-- 返回: It's here

-- 打开 NO_BACKSLASH_ESCAPES 后(反斜杠是普通字符)
SELECT 'It\'s here';
-- 语法错误,或者按字面量截断,返回值里多出一个反斜杠

WordPress 的 wpdb::prepare()、esc_sql() 以及大量手写查询,都会在字符串里插入反斜杠来做转义。一旦服务端把这个约定换掉,同一句 SQL 的语义就变了:轻则查不到数据(比如带引号的标题搜不出来),重则写进库里的值多出反斜杠(下次读出来变成 It\'s),最坏情况是转义失效导致的注入面扩大。

这类问题的棘手之处在于它不报错。站点照常打开,只是某些带特殊字符的内容莫名其妙不对——而这恰恰是最难归因的一类故障。官方在通告里也点明了动机:有些主机或服务器环境会把这个模式打开,此前的站点会在这些机器上遇到「很难定位的数据库问题」。换句话说,这次改动不是新增能力,而是把一类长期潜伏的环境差异收敛到核心层统一处理。


升级 7.2 之前,先跑一次下面的诊断。如果你的服务器原本就开着 NO_BACKSLASH_ESCAPES,那么升级会改变你站点现有的数据读写行为——过去「能跑但结果微妙不对」的地方会突然变对,也可能反过来暴露此前被掩盖的问题。这种站建议先在预发环境验证一遍再上生产。

三、先确认你踩没踩上

在站点的数据库里执行:

SHOW VARIABLES LIKE 'sql_mode';

看返回的逗号分隔串里有没有 NO_BACKSLASH_ESCAPES。也可以用一条不依赖任何表的语句直接验证转义行为:

SELECT 'a\'b' AS literal_test;
  • 返回 a'b → 反斜杠被当作转义符(正常,WordPress 期望的行为);
  • 报语法错误,或返回里保留了反斜杠 → 这个模式是开着的。

再验一次「实际数据有没有被污染」。下面这条查的是最容易出问题的地方——标题与正文里带单引号、双引号或反斜杠的内容:

SELECT ID, post_title
FROM wp_posts
WHERE post_status = 'publish'
  AND (post_title LIKE '%\\\\%' OR post_title LIKE '%\\\'%')
LIMIT 20;

如果结果里出现明显多出来的反斜杠(例如标题显示成 It\'s),说明历史上的写入已经受环境影响,升级后需要一次数据清理,而不只是改配置。

四、谁真的会受影响

角色影响该做什么
普通站长几乎为零,核心查询都走 wpdb 的封装正常升级,升级后抽查带引号标题的文章与搜索
插件作者自己拼 SQL 且手工转义的代码可能失准改用 $wpdb->prepare() 与占位符,别自己拼反斜杠
主题作者只在用了自定义查询时受影响检查 $wpdb->get_results() 的入参拼接方式
主机商 / 运维需要决定是否继续在服务器层开启该模式建议关掉;要留就明确告知用户并与核心行为隔离

值得注意的是第四行。这个模式本身不是「坏东西」——它的设计初衷是让反斜杠回归普通字符,符合部分团队的安全规范。问题在于它与 WordPress 核心的假设冲突。当平台默认值和应用的假设打架时,代价总是落在最终用户身上(表现为「换个主机就好了」这类玄学)。 7.2 把这件事收进核心,实际上是在替用户兜底。

五、万一你的站确实需要这个模式

官方给了出口:用已有的 incompatible_sql_modes 过滤器,把这一项从「要剔除的名单」里拿掉。

<?php
// wp-content/db.php
add_filter( 'incompatible_sql_modes', function ( $modes ) {
    return array_diff( $modes, array( 'NO_BACKSLASH_ESCAPES' ) );
} );

这里有一个必须注意的加载顺序问题:WordPress 在插件加载之前就已经连上数据库了,所以这段代码写在普通插件里、甚至写在 must-use 插件里都太晚——那时连接已经建立、模式已经被清掉。唯一有效的落点是 wp-content/db.php 这个 drop-in 。它和对象缓存的 object-cache.php 是同一套机制:核心在启动早期主动探测并加载这些文件。对象缓存 drop-in 的完整写法和坑,我在对象缓存与 Redis 持久化那篇里拆过,思路可以互相参照。


官方同时明确提醒:打开这个模式后,WordPress 核心不保证工作正常。所以这不是「开关」,而是「已知风险的知情选择」。如果你只是因为某个自研系统需要它,更稳妥的方案是让那套系统用独立数据库或独立连接,而不是把整个 WordPress 拖进去。
db.php 里能写业务代码吗?会不会被主题或插件覆盖?

db.php 属于 wp-content 层的 drop-in,不会随主题切换消失,但会被某些插件接管——数据库备份、主从读写分离、 HyperDB 这一类插件会重写或替换它。所以正确做法是:如果站点已经存在由插件生成的 db.php,不要直接覆盖,而是在其内部追加过滤器;并在插件升级后重新确认这段代码还在。判断方法很简单:升级后执行一次第三节的 SELECT 'a\'b' 验证,行为不对就说明 drop-in 被换掉了。
有没有可能升级后站点直接白屏?

单就这一项改动而言,几乎不会。它改变的是查询语义,不是代码路径,不会抛致命错误。更常见的表现是「某处内容不对」:搜索结果少了几条、带引号的标题显示多了反斜杠、导出 CSV 时出现转义错位。真出现白屏,请优先怀疑 PHP 版本兼容或插件冲突,而不是 SQL 模式。排查顺序建议:先禁用插件看是否恢复,再切默认主题,最后才查数据库层。

六、插件作者的落地检查清单

如果你维护着带自定义查询的插件,按这个顺序过一遍,成本很低:


  1. 全局搜索代码里手工拼接的反斜杠转义:addslashes、str_replace( "'", "\\'" )、以及字符串里出现的 \\'。这些是最直接的嫌疑点。

  2. 把所有带变量的查询改成 $wpdb->prepare() 加占位符形态(%s / %d / %i)。占位符由驱动负责转义,天然不受模式影响。

  3. LIKE 查询单独处理:% 与 _ 要用 $wpdb->esc_like() 包一层,再套进 prepare()。这是历史上被漏得最多的一处。

  4. 在测试环境把 sql_mode 手动加上 NO_BACKSLASH_ESCAPES 跑一遍集成测试,确认没有依赖反斜杠字面量的断言。

  5. 如果确实需要保留字面量反斜杠(例如存 Windows 路径、正则表达式),改用参数绑定传入,而不是在 SQL 文本里写反斜杠。

七、这件事的方法论价值

把它当成一个普遍模式看,比记住这个模式名更有用:应用的隐含假设,迟早要变成显式约束。 WordPress 靠反斜杠转义跑了很多年,这个假设一直藏在 wpdb 的实现里,从没写进文档;直到环境差异让它偶尔失效,核心才不得不把它固化成「连接时主动修正会话」。同类事情在别处也在发生——字符集、时区、STRICT 模式、ONLY_FULL_GROUP_BY,每一次都是同一个剧本。

对自建站的启示:如果你的项目里也有「一直这么跑所以应该没问题」的假设(比如某个目录一定可写、某个扩展一定装了、某个编码一定是 UTF-8),在升级前把它写成一次启动自检,而不是等它变成线上事故。这也是我在服务器迁移流程里坚持要跑「只读灰度 + 回滚」的原因:可验证的假设才叫假设,不可验证的叫赌博。

查看 Trac #66185 原始工单常见问题


升级 7.2 后我的站点需要做什么吗?
绝大多数情况什么都不用做。建议只做三件抽查:搜索一个带单引号的词、打开一篇标题含引号的文章、导出一次内容。三项都正常就说明没有踩到转义问题。

这个改动会修改服务器上的 MySQL 配置吗?
不会。它只调整 WordPress 自己那条连接的会话变量,服务器全局设置和 MySQL 配置文件都不动,也不需要重启数据库服务。同一台机器上的其他应用不受影响。

为什么我写在插件里的 incompatible_sql_modes 过滤器没有生效?
因为 WordPress 在插件加载之前就建立了数据库连接,等插件跑起来时模式已经被剔除。这个过滤器必须放在 wp-content/db.php 这个 drop-in 里才有效,mu-plugin 也不行。

保留 NO_BACKSLASH_ESCAPES 有哪些实际风险?
核心查询大量依赖反斜杠转义,打开这个模式后可能出现静默的数据错误:查不到本该查到的内容、写入值多出反斜杠、转义失效导致注入面扩大。官方明确表示核心不保证在这种模式下正常工作。

怎么判断历史数据已经被污染了?
查 wp_posts 里标题或正文含多余反斜杠的记录,以及评论、选项表里同类情况。发现后不要盲目全表替换,先导出样本比对原始值,再写针对性的更新脚本——字符串替换很容易把合法的反斜杠(代码片段、正则)一起改坏。

这篇有帮助吗?
云上的幻象
云上的幻象查看主页

七彩云博客,分享 WordPress 建站实战与 AI 工具测评,覆盖服务器运维、站长工具、软件资源与电商运营干货,专注原创实用的主题插件、网站加速与安全优化教程。

989文章4评论

相关文章

评论 (0)

欢迎你,新朋友,感谢参与互动!文明发言,理性交流 · 首次评论将在审核后展示