PHP需手动实现全文搜索,推荐用RecursiveDirectoryIterator遍历目录,配合isFile()过滤、setMaxDepth()防深度过深,大文件用fgets()流式读取,中文搜索须用mb_strpos或/u正则。

PHP 本身没有内置的“全文搜索文件内容”功能,glob()、scandir() 只能列文件名,真正要搜文件里有没有某段文字,得自己读取并匹配。
用 RecursiveDirectoryIterator 遍历子目录
这是 PHP 原生推荐的方式,比手写递归更可靠,自动跳过 . 和 ..,也支持过滤文件类型。
常见错误是直接用 foreach 遍历迭代器却没调用 getChildren() 或忽略异常(比如权限不足的子目录)。
- 必须包裹在
try/catch中,否则遇到无权限目录会 fatal error - 用
isFile()显式判断,别只靠扩展名后缀过滤 - 大目录下建议加
setMaxDepth(3)防止无限深入
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('/path', FilesystemIterator::SKIP_DOTS)
);
foreach ($it as $file) {
if ($file->isFile() && preg_match('/\.php$/i', $file->getFilename())) {
// 后续读内容
}
}
读文件内容时避免内存爆掉
用 file_get_contents() 一次性加载整个文件,在搜索日志或模板类大文件时极易 OOM。特别是当你要查上百个文件时,累积内存压力很大。
立即学习“PHP免费学习笔记(深入)”;
系统简介系统三大特色:1、全静态:全站生成.html静态页面。降低服务器压力,增强百度收录。2、高优化:特别针对搜索引擎进行优化处理,让客户快速找到你。3、够简单:拥有完善后台管理系统,所有内容均可在后台进行更新。非专业人士也可操作。网站后台后台管理地址:http://你的网站域名/Admin/login.asp用户名:admin密码:admin后台文件夹名:Admin数据库存放位置:Data21
- 优先用
file()按行读,配合stripos()判断每行是否含关键词 - 对超大文件(>10MB),改用
fopen()+fgets()流式处理 - 记得设
ini_set('memory_limit', '256M')(仅开发环境,生产慎用)
中文内容搜索要注意编码和正则
PHP 默认字符串函数(如 strpos())按字节匹配,UTF-8 中文占多字节,直接搜会漏掉或错位。用正则又容易因未声明 u 修饰符导致 warning 或结果为空。
- 确认文件真实编码(不是所有 .txt 都是 UTF-8),可用
mb_detect_encoding($content, ['UTF-8', 'GB2312', 'GBK'], true) - 用
mb_strpos($content, $keyword, 0, 'UTF-8')替代strpos() - 正则必须加
u修饰符:/关键词/u,否则中文字符被当乱码处理
实际组合:查找所有 PHP 文件中含 mysqli_connect 的行
这不是“教程式封装”,而是你复制粘贴就能跑的最小可行脚本——它兼顾了路径安全、编码容错、异常捕获和性能控制。
$root = '/var/www/project';
$keyword = 'mysqli_connect';
$files = [];
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root));
foreach ($it as $file) {
if (!$file->isFile() || !preg_match('/\.php$/i', $file->getExtension())) continue;
$content = @file_get_contents($file->getPathname());
if ($content === false) continue;
// 先用 mb_strpos 快速判断是否可能命中
if (mb_strpos($content, $keyword, 0, 'UTF-8') !== false) {
$lines = file($file->getPathname());
foreach ($lines as $n => $line) {
if (stripos($line, $keyword) !== false) {
$files[] = [
'file' => $file->getPathname(),
'line' => $n + 1,
'text' => trim($line)
];
break; // 找到第一处就停,避免重复记录同一文件
}
}
}
}
print_r($files);
注意 @ 抑制警告只是临时手段;真实项目里应统一用 set_error_handler() 捕获 file_get_contents 的 warning,并区分「文件不可读」和「文件不存在」两种情况。这点很容易被忽略,但线上排查时特别关键。










