最直接方式是用scandir()每次请求时读取目录内容,它兼容性好、性能优;需配合is_dir()和is_readable()预检,过滤'.','..'后建议natsort()排序。

用 scandir() 获取文件夹最新内容最直接
PHP 本身没有“实时监听”文件系统变化的原生机制,所谓“动态加载”或“实时加载”,实际是指在每次请求时重新读取目录内容。最常用、最可靠的方式就是调用 scandir() ——它返回指定路径下的所有文件和子目录名(含 . 和 ..),性能好、兼容 PHP 5.0+,且不依赖扩展。
注意点:
-
scandir()不递归,只读当前层;如需遍历子目录,得自己写递归逻辑或改用RecursiveDirectoryIterator - 返回结果未排序(PHP 5.4+ 默认按字母升序,但旧版本行为不一致),建议显式用
sort()或natsort()处理 - 若目录权限不足或路径不存在,会触发警告;应配合
is_dir()和is_readable()预检
示例:
$path = '/var/www/uploads';<br>if (is_dir($path) && is_readable($path)) {<br> $files = scandir($path);<br> $files = array_diff($files, ['.', '..']); // 过滤掉当前/上级目录<br> natsort($files); // 自然排序,避免 10 排在 2 前面<br>}
用 glob() 按模式筛选更高效
当只需要加载特定类型文件(比如所有 .jpg 或 config_*.php),glob() 比先 scandir() 再 array_filter() 更简洁、底层也更快——它直接交由操作系统匹配路径模式。
立即学习“PHP免费学习笔记(深入)”;
常见用法:
-
glob('/path/*.log'):匹配同级所有 .log 文件 -
glob('/path/{*.php,*.inc}', GLOB_BRACE):匹配多种后缀(需开启GLOB_BRACE) -
glob('/path/**/*.{php,js}', GLOB_BRACE | GLOB_RECURSE):PHP 5.6+ 支持递归(注意性能开销)
注意:glob() 在路径不存在或无匹配项时返回 false,不是空数组,务必用 !== false 判断
别指望 inotify 实现真正实时——除非你控制服务端环境
Linux 下的 inotify 扩展(需 php-inotify)确实能监听文件增删改事件,但它不是“PHP 自带功能”,需要运维手动安装扩展、且只在 CLI 或常驻进程(如 php -S 配合守护脚本)中稳定工作。Web SAPI(如 Apache/mod_php、PHP-FPM)每个请求都是独立生命周期,无法维持监听句柄。
所以,如果你看到“PHP 实时监听上传目录”的方案,背后通常是:
- 前端轮询(每 2 秒发一次
GET /api/list?ts=171…) - 服务端用
inotifywait命令 + 后台进程写变更日志,PHP 请求只读日志文件 - 用 WebSocket + Node.js 做中间层转发事件(PHP 不直接参与监听)
纯 PHP Web 环境下硬上 inotify,大概率会遇到 inotify_add_watch(): No space left on device 或请求超时中断监听。
缓存策略比“实时”更重要
频繁调用 scandir() 或 glob() 查同一个目录,在高并发下会造成 I/O 压力。与其追求“毫秒级同步”,不如合理加缓存:
- 用
apcu_cache_exists()+apcu_fetch()存目录列表,设置 1–5 秒 TTL - 文件变动后,主动
apcu_delete()对应缓存键(比如上传成功后删掉'dir_list_/uploads') - 若用 Redis/Memcached,注意序列化开销;小目录直接
json_encode()存字符串即可
真正容易被忽略的是:目录里文件数量一旦超过几百个,scandir() 的耗时就从微秒级跳到毫秒级——这时候再谈“实时”已无意义,该考虑分库(按日期建子目录)、前端分页,或者换用数据库索引文件元信息。











