php无法直接用unlink()实现回收站功能,因其会永久删除文件且不可恢复;安全做法是用rename()将文件移至trash目录并记录original_path、deleted_at等元数据,跨分区时降级为copy()+unlink()并加锁,同时校验路径、权限与磁盘空间。

为什么不能直接用 unlink() 删除文件
直接删掉文件就彻底没了,用户误操作后没法恢复。PHP 没内置回收站机制,得靠“挪位置 + 记录元数据”来模拟。核心思路是:不删文件,而是把文件移到一个专用目录(比如 trash/),同时保存原始路径、删除时间、操作用户等信息到数据库或 JSON 文件里。
怎么安全地移动文件到回收站目录
用 rename() 是最稳妥的方式——它在同分区下是原子操作,不会出现“复制成功但原文件没删”的中间态。如果跨分区,rename() 会失败,这时得 fallback 到 copy() + unlink() 组合,并加锁防止并发冲突。
- 回收站目录必须提前创建且 PHP 进程有写权限,比如
mkdir('trash', 0755, true) - 目标路径要防路径遍历:用
basename($original_path)提取文件名,不要直接拼接原始路径 - 建议加上时间戳和随机字符串避免重名,例如
date('YmdHis') . '_' . uniqid() . '_' . basename($file) - 移动前检查磁盘空间,
disk_free_space('trash/')避免回收站塞爆
删除记录该存哪些字段才够用
只记文件名远远不够。恢复时得知道它原本在哪儿、谁删的、能不能恢复(比如某些临时文件可能不该放回收站)。
- 必存字段:
original_path(绝对路径)、trash_path(回收站内路径)、deleted_at(时间戳)、user_id(操作者标识) - 可选但实用:
size(字节大小,用于回收站容量统计)、is_restorable(布尔值,标记是否允许恢复,比如日志文件设为 false) - 存储方式:小项目用 JSON 文件(
file_put_contents('trash/log.json', json_encode($entry)))够用;中大型项目务必进数据库,否则并发写入会丢记录
恢复文件时容易忽略的权限和路径问题
从回收站移回原路径,不是简单 rename() 就完事。原目录可能已被删,父级路径权限可能变了,甚至原路径是软链接目标。
- 恢复前先用
dirname($original_path)检查并递归创建父目录:mkdir(dirname($original_path), 0755, true) - 恢复后调用
chmod($original_path, fileperms($trash_path))尽量还原权限(注意:Windows 下无效) - 如果原路径存在同名文件,不能粗暴覆盖——至少得加
if (file_exists($original_path)) { /* 提示冲突 */ } - 千万别用
exec('mv ...'),shell 命令绕过 PHP 权限控制,且无法可靠捕获错误
回收站功能真正的复杂点不在移动文件,而在元数据的一致性维护:删了文件但忘了删记录,或恢复时路径拼错导致文件“消失”,这类问题线上很难排查。每次操作后建议加一句日志写入,哪怕只是 error_log("RESTORE: {$original_path} -> {$trash_path}")。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











