接手无文档网站,如何追踪页面加载时调用的所有PHP文件?
追踪PHP网站访问时调用的所有文件
这种接手无文档、非常规开发网站的糟心事我太熟了!靠ps aux | grep php确实抓不全,给你几个靠谱的方案,从简单到进阶都有:
1. 用PHP自动前置脚本记录加载文件
这是最不需要额外扩展的方法,核心思路是让每个PHP请求都先跑一个自定义脚本,在请求结束时记录所有被加载的文件。
- 第一步:创建一个
trace_loaded_files.php脚本,内容如下:
<?php register_shutdown_function(function() { $logFile = '/var/log/php_loaded_files.log'; // 改成你有权限写入的路径 $requestUrl = $_SERVER['REQUEST_URI'] ?? 'unknown'; $timestamp = date('Y-m-d H:i:s'); $loadedFiles = get_included_files(); $logContent = "[{$timestamp}] Request: {$requestUrl}\n"; $logContent .= "Loaded files:\n"; foreach ($loadedFiles as $file) { $logContent .= "- " . realpath($file) . "\n"; } $logContent .= "-------------------------\n"; file_put_contents($logFile, $logContent, FILE_APPEND | LOCK_EX); }); ?>
第二步:配置PHP加载这个脚本
- 如果是用Apache,可以在
.htaccess里加:php_value auto_prepend_file "/path/to/trace_loaded_files.php" - 如果是Nginx+PHP-FPM,编辑
php.ini或者对应站点的php-fpm.conf,添加:auto_prepend_file = "/path/to/trace_loaded_files.php" - 改完后重启PHP-FPM或Apache生效。
- 如果是用Apache,可以在
注意:确保日志文件所在目录有PHP进程的写入权限,避免报错。
2. 用Xdebug生成详细跟踪日志
如果需要更细致的执行流程(比如函数调用、文件加载顺序),Xdebug的跟踪功能是绝佳选择。
- 第一步:安装并启用Xdebug(如果还没装),然后在
php.ini里添加以下配置:
xdebug.mode = trace xdebug.start_with_request = yes xdebug.trace_output_dir = "/var/log/xdebug_traces" # 自定义日志目录 xdebug.trace_output_name = trace.%c.%t # 用进程ID和时间戳命名文件,避免覆盖 xdebug.trace_format = 0 # 生成人类可读的文本格式,1是机器格式
第二步:重启PHP-FPM或Apache,之后每访问一个URL,都会在指定目录生成一个跟踪文件,里面包含所有被加载的PHP文件、函数调用栈等信息。
注意:Xdebug跟踪会生成大量日志,用完记得把
xdebug.start_with_request改成no,避免占满磁盘。
3. 用strace跟踪进程文件操作
如果服务器层面的跟踪更适合你,可以用strace来监控PHP-FPM进程打开的所有文件。
- 首先找到PHP-FPM的主进程ID:
ps aux | grep php-fpm | grep master
- 然后跟踪这个主进程及其子进程的文件打开操作:
strace -f -p <主进程ID> -e open,openat 2>&1 | grep -E '\.(php|inc|php5|php7)$'
-f:跟踪子进程(因为PHP-FPM会fork子进程处理请求)-e open,openat:只监控文件打开相关的系统调用grep:过滤出PHP相关的文件,避免无关日志干扰访问目标URL,就能实时看到进程打开的所有PHP文件了。
4. 重写include/require函数(进阶,需runkit扩展)
如果需要精确记录每一次include/require的调用,可以用runkit扩展重写这些内置函数,不过这个方法需要服务器安装runkit扩展。
- 在
trace_loaded_files.php里添加以下代码(配合方法1的自动前置脚本):
<?php if (extension_loaded('runkit')) { function traced_include($file) { $logFile = '/var/log/php_includes.log'; $requestUrl = $_SERVER['REQUEST_URI'] ?? 'unknown'; $timestamp = date('Y-m-d H:i:s'); file_put_contents($logFile, "[{$timestamp}] {$requestUrl} -> Included: " . realpath($file) . "\n", FILE_APPEND | LOCK_EX); return original_include($file); } runkit_function_rename('include', 'original_include'); runkit_function_override('include', '$file', 'return traced_include($file);'); // 对require、include_once、require_once做同样的处理 } ?>
这些方法里,我最推荐方法1(简单无依赖)或者方法2(信息全面),根据你的服务器环境选就行!
内容的提问来源于stack exchange,提问作者Matthew Jones
相关产品推荐
相关产品推荐

