【发布时间】:2012-06-30 06:35:18
【问题描述】:
我正在使用 php 编写一个 API 来包装网站功能并返回 json\xml 中的所有内容。我一直在使用 curl,到目前为止效果很好。 该网站有一个标准的文件上传 Post,可接受最大 1GB 的文件。
那么问题是如何将文件上传流重定向到对应的网站?
我可以下载文件然后上传,但我的服务器限制为只有 20MG。而且这似乎是一个糟糕的解决方案。
甚至可以控制流并将其直接重定向到网站吗?
【问题讨论】:
我正在使用 php 编写一个 API 来包装网站功能并返回 json\xml 中的所有内容。我一直在使用 curl,到目前为止效果很好。 该网站有一个标准的文件上传 Post,可接受最大 1GB 的文件。
那么问题是如何将文件上传流重定向到对应的网站?
我可以下载文件然后上传,但我的服务器限制为只有 20MG。而且这似乎是一个糟糕的解决方案。
甚至可以控制流并将其直接重定向到网站吗?
【问题讨论】:
我将原创保留在底部以供后代使用,但事实证明,有办法做到这一点
您需要使用 HTTP put 方法(遗憾的是在本机浏览器表单中不可用)、PHP php://input 包装器和流式 php 套接字的组合。这绕过了几个限制 - PHP 不允许 php://input 用于发布数据,但它对 PUT 文件数据没有任何作用 - 聪明!
如果你打算用 apache 来尝试这个,你需要安装一个激活的mod_actions。您还需要在 virtualhost/.htaccess 中使用 Script 指令指定 PUT 脚本。
http://blog.haraldkraft.de/2009/08/invalid-command-script-in-apache-configuration/
这仅允许一个 url 端点的 put 方法。这是将打开套接字并将其数据转发到其他地方的文件。在下面的示例中,这只是index.php
我已经准备了一个样板示例,使用 python requests 模块作为客户端发送带有图像文件的 put 请求。如果您运行remote_server.py,它将打开一个服务,该服务仅侦听端口并等待来自 php 的转发消息。 put.py 将实际的 put 请求发送到 PHP。您需要将主机 put.py 和 index.php 设置为您在虚拟主机中定义的主机,具体取决于您的设置。
运行put.py 将打开包含的图像文件,将其发送到您的 php 虚拟主机,然后它会打开一个套接字并将接收到的数据流式传输到 python 伪服务并将其打印到终端中的标准输出.流式 PHP 转发器!
没有什么能阻止您使用任何远程服务,该服务以相同的方式侦听 TCP 端口,完全采用另一种语言。客户端可以用同样的方式重写,只要它可以发送 PUT 请求。
完整的例子在这里:
https://github.com/DeaconDesperado/php-streamer
我实际上对这个问题很感兴趣。请告诉我它是如何工作的,我们可以一起修补它。
开始原始答案
在 php 中没有本地方法可以异步传递文件,因为它与请求正文一起出现,而不以某种方式将其状态保存到磁盘。这意味着您受到服务器上的内存限制 (20MB) 的严格限制。在收到请求后初始化 $_FILES 超全局的方式取决于此,因为它将尝试将 multipart 数据迁移到 tmp 目录。
使用套接字可以达到类似的效果,因为这至少会绕过 HTTP 协议,但如果文件在 HTTP 请求中传递,php 仍然会尝试在它之前将其有状态地保存在内存中什么都可以。您将设置流程的尾端,而没有任何实际的方法可以做到这一点。
Stream 库接近了,但仍然依赖于从服务器端读取内存不足的文件 - 它必须已经存在 。
您所描述的内容有点超出 HTTP 协议,特别是因为请求正文如此之大。 HTTP 是一种基于请求/响应的机制,一个依赖于另一个......在中间点完成就地流式上传非常困难,因为这意味着某些协议会在比特流式传输时上传在。
有人可能会争辩说,这更多是 HTTP 的限制,而不是 PHP,而且由于 PHP 在设计时明确考虑了 HTTP 协议,因此您正在走出它的舒适区。
使用其他脚本语言经常尝试这样的部署并取得巨大成功(例如,在 Python 中扭曲,很多人正在使用 NodeJS 的并发设计模式,在 Ruby 或 Java 中有一些我不太了解的替代方案.)
【讨论】:
php://temp 看起来很有希望,如果它让逻辑在超全局初始化之前执行。或许可以将其与exec() 结合起来以完成这项工作。我现在要做一个概念验证。
php://input 似乎不适用于 enctype multipart/form-data。也许temp 是?