PHP 7.4 在 Windows 下 fopen() 必须显式加 b 才能正确处理二进制或非纯 ASCII 文本,否则换行符被转换、0x1A 触发假 EOF;t 标记已无效,应弃用。

PHP 7.4 在 Windows 下处理文件时,fopen() 的模式参数里加不加 t 或 b 看似小事,实则直接决定读写结果是否正确——尤其在涉及二进制内容(如图片、PDF、加密数据)或跨平台传输的文本时,漏掉 b 会导致换行符被静默修改、文件损坏、fread() 返回长度异常,甚至 md5_file() 校验失败。
Windows下 fopen("xxx", "r") 默认是文本模式,不是二进制
PHP 7.4 在 Windows 上沿用 C 运行时的默认行为:"r"、"w"、"a" 这类不含 b 的模式,全部按文本模式打开。这意味着:
-
\n会被自动转成\r\n写入("w"),读取时又把\r\n转回\n - 遇到字节值
0x1A(ASCII SUB 字符)会提前触发 EOF,哪怕文件后面还有数据 - 对非 UTF-8 编码的文本(如 GBK 日志)可能因换行转换引发乱码
这不是 PHP 的 bug,是 Windows CRT 的历史设计。你用 fread($fp, 1024) 读一个 PNG 文件,实际拿到的数据可能比原始少、中间夹杂多余 \r,imagecreatefromstring() 直接返回 false。
什么时候必须显式加 b:所有非纯 ASCII 文本和所有二进制场景
只要文件内容不是“确定只含 ASCII 字符 + 换行符”,且你关心字节级准确性,就必须用 b:
立即学习“PHP免费学习笔记(深入)”;
- 读写图片(
.jpg、.png)、音频(.mp3)、PDF、ZIP、EXE - 处理 Base64 编码后的字符串(本身含
\n分隔,但本质是二进制载体) - 调用
openssl_encrypt()/hash_hmac()后写入文件 - 从
php://input读取 POST 原始 body(尤其 multipart/form-data 中的文件段) - 即使你只是读一个 UTF-8 文本文件,且后续要做
mb_strlen($data, '8bit')或bin2hex(),也建议用"rb"
反例:fopen("config.json", "w") → 应该写成 fopen("config.json", "wb")。JSON 规范允许任意 Unicode 字符,UTF-8 编码中多字节序列可能包含 0x1A,文本模式会截断。
通过 handsfree-windows CLI控制 Windows 本机应用 (UIA) 和浏览器 (Playwright) 的引导技能,用于自动化或测试桌面应用。
t 标记在 PHP 7.4 中已无实际作用,别用
PHP 官方文档明确说明:t 是为兼容旧版而保留的占位符,自 PHP 5.6 起就不再影响行为。Windows 下 "rt" 和 "r" 完全等价,Linux/macOS 下两者都忽略 t。PHP 7.4 更不会做额外处理。
所以:
- 不要写
"rt"或"wt"—— 多余且误导 - 不要依赖
t来“确保文本安全”——它什么也不保证 - 真要处理文本换行,用
str_replace("\n", "\r\n", $content)显式控制,而非靠模式
唯一例外是极老的 PHP 4 代码迁移,但你现在用的是 7.4,直接删掉所有 t。
PHP 7.4 的 fwrite/fread 在二进制模式下仍需注意编码
加了 b 只解决换行和 EOF 问题,不解决字符编码。例如:
- 用
fopen("log.txt", "ab")追加中文,如果源字符串是 GBK 编码,而文件原本是 UTF-8,就会写入乱码 -
fwrite()不做任何编码转换,它只管字节流。你传进去什么字节,它就写什么字节 - 推荐做法:统一用 UTF-8 存储文本,并在写入前确认
$content是合法 UTF-8(可用mb_check_encoding($content, 'UTF-8'))
顺带一提:file_get_contents() 和 file_put_contents() 默认也是二进制语义(底层调用 fopen(..., "rb")),所以它们天然适合处理任意文件——但如果你用 FILE_TEXT 标志,反而会触发 Windows 下的文本模式转换,得不偿失。
真正容易被忽略的点是:PHP 7.4 的 stream_wrapper_register() 自定义协议(比如封装 S3 或 FTP 流)如果没显式指定 b,其内部 fopen 调用仍走 Windows 默认文本模式,导致二进制流被污染。这时候必须在 wrapper 的 stream_open() 实现里,把 mode 参数中的 t 替换成 b,或者直接强制追加 b。


















