【问题标题】:Why does PHP store uploaded files in a temporary location and what is the benefit?为什么 PHP 将上传的文件存储在临时位置,有什么好处?
【发布时间】:2018-07-26 22:34:25
【问题描述】:

好的,我是这个领域的新手,并且通过了一些教程,我发现在 PHP 中上传文件时,它会将它们存储在一个临时位置。

$file_temp=$_FILES['file']['tmp_name'];
$file_loc="Upload".$file_name;
move_uploaded_files($file_temp,$file_loc);

现在为什么 PHP 不允许将文件直接上传到所需的位置?为什么将它们存储在带有 .tmp 扩展名的临时位置?我们从该策略中获得什么好处?

【问题讨论】:

  • 这不会允许客户端任意上传文件,即使脚本不是用于上传的?
  • 它如何知道所需位置在哪里?
  • 查看 php.ini 中的 upload-tmp-dir 指令:php.net/manual/en/ini.core.php#ini.upload-tmp-dir。它允许设置临时文件夹的位置。使用 tmp 文件夹的一个好处是上传的文件保存在文档根目录之外的文件夹中。如果 tmp 文件夹位于文档根目录中,用户将能够下载彼此的文件

标签: php file-upload


【解决方案1】:

好问题。简短的回答是 PHP 必须处理 整个 HTTP 请求 - 用数据填写 $_POST,并根据需要填写 $_FILES - 然后再控制您的脚本。由于您的脚本直到 处理后才能获得控制权,因此无法告诉 PHP 将该文件数据放在何处。

但是为什么 PHP 会这样做呢?好吧,我们来看一个HTTP POST with file data

POST /upload?upload_progress_id=12344 HTTP/1.1
Host: localhost:3000
Content-Length: 1325
Origin: http://localhost:3000
... other headers ...
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryePkpFF7tjBAqx29L

------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="MAX_FILE_SIZE"

100000
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="uploadedfile"; filename="hello.o"
Content-Type: application/x-object

... contents of file goes here ...
------WebKitFormBoundaryePkpFF7tjBAqx29L--

请注意,请求的内容是一个多部分编码的文档,表单字段散布在文件数据中。在此特定示例中,表单字段出现在文件数据之前。但是,表单数据有可能(实际上很可能)出现在 文件数据之后。

因此,为了保证 PHP 可以为您提供所有 $_POST 数据,PHP 必须处理整个请求。所以它还不如完成$_FILES 超级全局,而它在那里。

现在,PHP 可以将此文件数据保存在内存中,但这可能真的是个坏主意。想想如果 PHP 需要存储用户上传的 100 MiB 文件会发生什么。突然,您的 Apache 进程的 RSS 增加了 100 MiB,这真的不太好 - Apache 可能会ulimited 没有那么多空间,或者 Apache 可能会被交换:让您的用户感到痛苦。所以,PHP 做了下一件最好的事情:把这个接收到的文件放在一个临时文件中。

你可能会问为什么不能告诉 PHP 把传入的文件数据放在哪个文件前面,所以你不必移动它。嗯,这是一个引导问题:PHP 还没有将控制权交给脚本,所以脚本不能告诉 PHP 把文件放在哪里。因此,PHP 尽其所能:将文件数据放入临时文件中。

现在,您可以将此文件数据保存在 RAM 磁盘中,以提高速度。如果您不介意基础设施成本(例如,维护 RAM 磁盘设置),这是一个很好的方法。但请注意,这不像 PHP 将它保存在 RAM 本身:在这种情况下,PHP 容器进程(通常是 Apache 或其他一些 Web 服务器)必须有堆来保存文件(它可能没有)。在这种情况下,RAM 磁盘由内核管理。

【讨论】:

  • 我可以更改临时位置吗?还是固定位置?
  • 是:将upload_tmp_dir 设置更改为所需的路径。
  • 非常感谢非常感谢您的努力
  • 其他框架通常解决这个问题的方法是通过为应用程序提供一个惰性可枚举的 http 部分来避免整个问题。一个更灵活的解决方案,但它也让 PHP 通常试图避免的应用程序开发人员承担更多责任。
  • @JaiShreeGanesh 如果您尝试将 upload_tmp_dir 变量更改为所需的可公开访问的目录...不要。 Somone 可以简单地将恶意文件 POST 到您的 PHP 脚本,它会在该目录中结束没有任何健全性检查
【解决方案2】:

来自What is the benefit of writing to a temp location, And then copying it to the intended destination?

  • 在大多数平台上,文件移动是原子的,但文件写入不是(尤其是如果您不能一次写入所有数据)。因此,如果您有典型的生产者/消费者模式(一个进程生成文件,另一个进程监视目录并获取它找到的所有内容),首先写入临时文件夹然后才移动到实际位置意味着消费者永远看不到未完成的文件。
  • 如果写入文件的进程在中途终止,则您的磁盘上有一个损坏的文件。如果它在一个真实的位置,你必须自己清理它,但如果它在一个临时位置,操作系统会处理它。 如果该文件恰好在备份作业运行时创建,该作业可能会拾取一个不完整的文件;临时目录通常从备份中排除,因此该文件只有在移动到最终目的地后才会被包含在内。
  • temp 目录可能位于快速但易失的文件系统(例如 ramdisk)上,这对于并行下载同一文件的多个块或对包含大量文件的文件进行就地处理等操作非常有用的寻求。此外,与读取、写入和删除频率较低的目录相比,临时目录往往会导致更多碎片,将临时目录保留在单独的分区上有助于减少其他分区的碎片。

【讨论】:

  • 请说出“文件移动是原子的”是什么意思?非常感谢您的努力
  • @JaiShreeGanesh 原子动作意味着它不会中途失败。
  • @JaiShreeGanesh 原子操作,是一种可以在不中断的情况下完成的操作(想想中断、进程调度等)。他们要么失败,要么成功。元数据更改是原子的。文件重命名就是这样的情况。
  • 原子的意思是全有或全无。
  • @JaiShreeGanesh:“原子”是计算机科学中的一个重要概念。参见例如在linearizability 上的维基百科文章进行概述。
【解决方案3】:

另外两个原因:

  1. 如果您出于某种原因决定不接受该文件,它会存储在一个临时位置,并且可能会在某个时候被自动删除。

  2. 安全。假设 PHP 被设置为上传到像 /images 这样的 Web 可访问目录。有人可以上传某种黑客文件,然后执行它。通过首先将文件放入临时目录(通常无法通过 Web 访问),PHP 让您首先检查文件。例如,通过处理图像以删除任何可能包含 PHP 代码的 cmets。

【讨论】:

    猜你喜欢
    • 2016-08-02
    • 1970-01-01
    • 2011-10-30
    • 2012-06-23
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 2021-01-20
    相关资源
    最近更新 更多