PHP无法真正恢复已删除文件,只能通过软删除(移入回收站+日志记录)实现可逆操作,核心是避免unlink()、用rename()或copy()+unlink()转移文件,并确保日志与文件状态一致。

PHP 本身没有内置的“文件恢复”能力——它不能从磁盘底层找回已被删除的文件。所谓“PHP 实现文件恢复”,实际是指在应用层做防御性设计,让误删操作可逆。核心思路是:不真删,只改名或挪位置,并保留元信息以便回溯。
用 rename() 替代 unlink() 做软删除
直接调用 unlink() 后文件不可逆丢失。更安全的做法是把文件移到一个统一的回收站目录,并记录原始路径和删除时间。
- 回收站目录建议设为 Web 不可访问路径,例如
/var/www/app/storage/trash/(避免通过 URL 直接下载) - 重命名时加入时间戳和哈希,防止同名冲突:
md5($original_path) . '_' . time() . '_' . basename($original_path) - 必须同时写入日志文件(如 JSON 格式),记录
original_path、trash_path、deleted_at、operator_id - 注意
rename()跨文件系统会失败,此时需改用copy()+unlink()组合,并检查返回值
从日志中还原文件要用 file_get_contents() + file_put_contents()
不能直接用 rename() 回退——因为回收站里的文件名已变,且原始目录结构可能已不存在。稳妥做法是读取内容再写回原路径。
- 先验证日志中的
original_path是否合法(用realpath()和is_dir()检查父目录是否存在) - 用
file_get_contents($trash_path)读取,避免大文件内存溢出;超 2MB 建议用fopen()流式复制 - 写入前确保目标目录可写:
is_writable(dirname($original_path)),否则创建目录链(mkdir(..., 0755, true)) - 还原后应更新日志状态字段(如加
"restored": true),避免重复还原
用 scandir() 扫描回收站时要注意排序和权限
列出可恢复项时,不能简单 scandir() 就完事。用户需要看到“原始路径”和“删除时间”,这些信息只存在日志里,不在文件名中。
立即学习“PHP免费学习笔记(深入)”;
- 回收站目录下不应存裸文件,而应按日期分目录(如
/trash/2024/06/15/),便于清理过期项 -
scandir()返回结果包含.和..,必须过滤:array_diff($files, ['.', '..']) - 如果日志是单个 JSON 文件,需用
json_decode(file_get_contents($log_path), true)加载并按deleted_at降序排列 - 别忽略时区问题:
date('Y-m-d H:i:s', $timestamp)前确认date_default_timezone_set()已设对
真正的难点不在代码行数,而在于日志一致性——比如还原过程中服务崩溃,导致文件已写回但日志没更新。这类场景需要引入原子操作(如先写日志再移动文件)或补偿任务(后台扫描日志与文件实际状态差异)。没做这层设计,“恢复”就只是个心理安慰。



















