php - 为什么 `rename`删除源文件失败,而 `unlink`有效

标签 php file-upload file-permissions

我有一个 PHP 脚本,使用函数 rename 移动文件,但部分失败。调用rename会发出“权限被拒绝”警告。该文件似乎已复制到目标目录(我看到它没问题),但在重命名后它仍然存在于源目录中。

file_exists 确认旧文件仍然存在。 然后,unlink 可以成功删除该文件 - 它返回 true 并且 file_exists 确认该文件现已消失。

该文件通过 HTTP 请求上传到 /tmp 目录(我使用 is_uploaded_file 来满足安全考虑 - 这不是这里的问题) 。该文件确实具有 Web 服务用户 (www-data) 的 rw 权限。 move_uploaded_file 也可以正常工作,不会出现错误。

目标目录位于已安装的 CIFS 目录中。

Linux Ubuntu,PHP 版本 7.2.24。

最佳答案

(更新: OP 表示目标目录是 CIFS 挂载。CIFS 挂载的权限可能比较难以理解 - 请参阅 https://linux.die.net/man/8/mount.cifs 部分“文件和目录所有权和权限")

rename 不是单个原子操作(在 PHP 中)。它实际上调用(对于普通文件按此顺序):

  • 复制(创建文件的新副本)
  • chown(设置新副本的所有权)
  • chmod(设置新副本的权限)
  • 取消链接(删除原来的)

(源代码为available on GitHub。)

如果这些步骤中的任何一个失败,它将中止并显示错误代码,并且不会回滚(这与您所看到的症状一致)。

旁注:这实际上在源代码中记录为可能的行为:

 /*
  * Try to set user and permission info on the target.
  * If we're not root, then some of these may fail.
  * We try chown first, to set proper group info, relying
  * on the system environment to have proper umask to not allow                
  * access to the file in the meantime.
  */

我预计目标(您将复制到)中的父目录的权限会阻止chmodchown 停止工作。

(注意:这不适用于 CIFS 安装...请参阅答案顶部的链接。)作为一个 super 丑陋的黑客,您可以尝试将目标目录的权限设置为777 (chmod 777/my/target/directory/),这是不好的做法,但可以证明这一理论。

关于php - 为什么 `rename`删除源文件失败,而 `unlink`有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59859877/

相关文章:

php - 打印包含一些 MySQL 记录的数组

android - 从 Android 应用程序将视频上​​传到 S3 AWS 会生成一个 0Kb 文件

java - 没有Spring引导的带有Java配置的Spring rest MultiPart文件上传

java.security.AccessControlException : Access denied (java. io.FilePermission

python - 确保测试用例可以删除它创建的临时目录

php - 使用什么样的 ID 以及如何将其存储在数据库中?

php - 建立一个一周的日历/时间表

python - 确定是否继承 ntfs 权限的可靠方法

php - 在 Laravel 中使用 ->paginate() 时出错

angularjs - 平均堆栈 : How to bind uploads to a mongoose model?