如何使用PHP通过HTTP PUT接收文件 [英] How to receive a file via HTTP PUT with PHP

查看:129
本文介绍了如何使用PHP通过HTTP PUT接收文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这一直困扰着我一段时间..我正在构建一个RESTful API,必须在某些情况下接收文件。



使用时 HTTP POST ,我们可以从$ _FOST <$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ code> c c $ c>。



使用 HTTP GET 时,我们可以从$读取数据来自$ _FILES 的_GET 和文件。



然而,当使用<$ c $时c> HTTP PUT ,AFAIK读取数据的唯一方法是使用 php://输入流



一切都很好,直到我想通过HTTP PUT发送文件。现在php://输入流不再按预期工作,因为它也有一个文件。



这是我目前在PUT上读取数据的方式请求:



(只要没有发布文件,效果很好)

  $ handle = fopen('php:// input','r'); 
$ rawData ='';
while($ chunk = fread($ handle,1024)){
$ rawData。= $ chunk;
}

parse_str($ rawData,$ data);

当我输出rawData时,显示

  ----- ZENDHTTPCLIENT-44cf242ea3173cfa0b97f80c68608c4c 
Content-Disposition:form-data; NAME = image_01; filename =lorem-ipsum.png
内容类型:image / png; charset =二进制
$ b $b PNG
......等等...... $ b $b ,
----- ZENDHTTPCLIENT-8e4c65a6678d3ef287a07eb1da6a5380
Content-Disposition:form-data; name =testkey

testvalue
----- ZENDHTTPCLIENT-8e4c65a6678d3ef287a07eb1da6a5380
Content-Disposition:form-data; name =otherkey

其他值

有谁知道如何正确接收HTTP PUT上的文件,或者如何解析php://输入流中的文件?



===== UPDATE#1 ==== =



我只尝试过上述方法,并不知道我能做些什么。



我使用这种方法没有错误,除了我没有得到所发布的数据和文件的预期结果。



===== UPDATE#2 =====



我正在使用Zend_Http_Client发送此测试请求,如下所示:
(到目前为止Zend_Http_Client没有任何问题)

  $ client = new Zend_Http_Client(); 
$ client-> setConfig(array(
'tright'=> false,
'maxredirects'=> 0,
'timeout'=> 30)
);
$ client-> setUri('http:// ...');
$ client-> setMethod(Zend_Http_Client :: PUT);
$ client-> setFileUpload(dirname(__ FILE__)。'/ files /lorem -ipsum.png','image_01');
$ client-> setParameterPost(array('testkey'=>'testvalue','otherkey'=>'othervalue');
$ client-> setHeaders(array($ b $) b'api_key'=>'...',
'identity'=>'...',
'凭证'=>'...'
)) ;

=====解决方案=====



结果我做了一些错误的假设,主要是HTTP PUT与HTTP POST类似。正如你在下面读到的那样,DaveRandom向我解释说HTTP PUT不适合转移同一请求中的多个文件。



我现在已经将formdata从body传输到url querystring。正文现在保存了单个文件的内容。



有关更多信息,请阅读DaveRandom的答案。这是史诗般的。

解决方案

你显示的数据并没有描述一个有效的PUT请求体(好吧,可以,但我非常怀疑它。)它是什么shows是一个 multipart / form-data 请求体 - 通过HTTP表单通过HTML表单上传文件时使用的MIME类型。



PUT请求应该完全赞美对GET请求的响应 - 它们会向您发送消息正文中的文件内容,而不是其他内容。



基本上我是什么我说是接收错误的文件不是你的代码,它是发出请求的代码 - 客户端代码不正确,而不是你在这里显示的代码(尽管 parse_str( )调用是一项毫无意义的练习。)



如果你解释一下客户端是什么(浏览器,其他服务器上的脚本等)那么我可以帮助你进一步。事实上,您描述的请求正文的适当请求方法是POST,而不是PUT。






让我们来看看从问题中退一步,并查看一般的HTTP协议 - 特别是客户端请求方 - 希望这将有助于您了解所有这些应该如何工作。首先,一点历史(如果您对此不感兴趣,请跳过此部分)。



历史



HTTP最初设计为从远程服务器检索HTML文档的机制。起初它只有效地支持GET方法,客户端会按名称请求文档,服务器会将其返回给客户端。 HTTP的第一个公共规范,标记为HTTP 0.9,出现在1991年 - 如果您有兴趣,可以阅读这里



HTTP 1.0规范(1996年正式化, RFC 1945 )大大扩展了协议的功能,添加了HEAD和POST方法。它没有向后兼容HTTP 0.9,因为响应格式发生了变化 - 添加了响应代码,并且能够以MIME格式标题的形式包含返回文档的元数据 - 键/值数据对。 HTTP 1.0还从HTML中抽象出协议,允许以其他格式传输文件和数据。



HTTP 1.1,几乎全部使用的协议形式今天建立在HTTP 1.0之上,旨在向后兼容HTTP 1.0实现。它于1999年通过 RFC 2616 进行了标准化。如果您是使用HTTP的开发人员,请了解此文档 - 这是您的圣经。完全理解它会比没有完全理解它的同行更具优势。



已经达到目的



HTTP在请求 - 响应架构上工作 - 客户端向服务器发送请求消息,服务器向客户端返回响应消息。



请求消息包括METHOD,URI和可选的多个HEADERS。请求METHOD是这个问题所涉及的,所以我将在这里深入讨论 - 但首先,在我们讨论请求URI时,确切了解我们的意思非常重要。



URI是我们请求的资源的服务器上的位置。通常,它由路径组件和可选的查询字符串组成。在某些情况下,其他组件也可能存在,但为了简单起见,我们暂时忽略它们。



让我们假设您键入 http://server.domain.tld/path/to/document.ext?key = value 进入浏览器的地址栏。浏览器会解除此字符串,并确定它需要连接到 server.domain.tld 的HTTP服务器,并在 /上请求文档path / to / document.ext?key = value



生成的HTTP 1.1请求将(至少)看起来像这样:

  GET /path/to/document.ext?key=value HTTP / 1.1 
主持人:server.domain.tld

请求的第一部分是单词 GET - 这是请求METHOD。下一部分是我们请求的文件的路径 - 这是请求URI。在该第一行的末尾是指示正在使用的协议版本的标识符。在以下行中,您可以看到MIME格式的标题,名为 Host 。 HTTP 1.1要求每个请求都包含主机:标头。这是唯一的标题。



请求URI分为两部分 - 问号左侧的所有内容? 路径,右边的所有内容都是查询字符串



请求方法



RFC 2616(HTTP / 1.1)定义 8种请求方法



选项



很少使用OPTIONS方法。它旨在作为一种机制,用于在尝试使用服务器可能提供的服务之前确定服务器支持哪种功能。



在我的头顶,唯一的我可以想到使用它的相当常见的用法是在Microsoft Office中直接通过HTTP从Internet Explorer打开文档时 - Office会向服务器发送OPTIONS请求以确定它是否支持特定URI的PUT方法,如果是这样,它将以允许用户将对文档的更改直接保存回远程服务器的方式打开文档。此功能与这些特定的Microsoft应用程序紧密集成。



GET



这是迄今为止每天使用中最常用的方法。每次在Web浏览器中加载常规文档时,它都是GET请求。



GET方法请求服务器返回特定文档。应该传输到服务器的唯一数据是服务器确定应返回哪个文档所需的信息。这可以包括服务器可以用来动态生成文档的信息,该信息以请求URI中的头和/或查询字符串的形式发送。当我们讨论主题时 - Cookie会在请求标头中发送。



HEAD



此方法与GET方法相同,但有一点不同 - 服务器不会返回请求的文档,如果只返回响应中包含的标题。例如,这对于确定是否存在特定文档而不必传输和处理整个文档非常有用。



POST



这是第二种最常用的方法,可以说是最复杂的方法。 POST方法请求几乎专门用于调用可能改变其状态的服务器上的某些操作。



与GET和HEAD不同,POST请求可以(并且通常会)在请求消息的正文中包含一些数据。此数据可以是任何格式,但最常见的是查询字符串(格式与请求URI中显示的格式相同)或多部分消息,可以与文件附件一起传递键/值对。



许多HTML表单使用POST方法。为了从浏览器上传文件,您需要为表单使用POST方法。



POST方法在语义上与RESTful API不兼容,因为它不是< a href =http://en.wikipedia.org/wiki/Idempotence =noreferrer>幂等。也就是说,第二个相同的POST请求可能导致对服务器状态的进一步改变。这与REST的无国籍约束相矛盾。



PUT



这直接补充了GET。如果GET请求指示服务器应该在响应主体中的请求URI指定的位置返回文档,则PUT方法指示服务器应该将数据存储在请求URI指定的位置的请求主体中。 / p>

DELETE



这表明服务器应该销毁请求URI指示的位置处的文档。很少有面向互联网的HTTP服务器实现在收到DELETE请求时会执行任何操作,原因相当明显。



TRACE



这提供了一个应用程序层级机制,允许客户端在到达目标服务器时检查它发送的请求。这对于确定客户端和目标服务器之间的任何代理服务器对请求消息的影响非常有用。



CONNECT



HTTP 1.1保留CONNECT方法的名称,但不定义其用法,甚至用途。一些代理服务器实现后来使用CONNECT方法来促进HTTP隧道。


This is something that has been bugging me for a while.. I'm building of a RESTful API that has to receive files on some occasions.

When using HTTP POST, we can read data from $_POST and files from $_FILES.

When using HTTP GET, we can read data from $_GET and files from $_FILES.

However, when using HTTP PUT, AFAIK the only way to read data is to use the php://input stream.

All good and well, untill I want to send a file over HTTP PUT. Now the php://input stream doesn't work as expected anymore, since it has a file in there as well.

Here's how I currently read data on a PUT request:

(which works great as long as there are no files posted)

$handle  = fopen('php://input', 'r');
$rawData = '';
while ($chunk = fread($handle, 1024)) {
    $rawData .= $chunk;
}

parse_str($rawData, $data);

When I then output rawData, it shows

-----ZENDHTTPCLIENT-44cf242ea3173cfa0b97f80c68608c4c
Content-Disposition: form-data; name="image_01"; filename="lorem-ipsum.png"
Content-Type: image/png; charset=binary

�PNG
���...etc etc...
���,
-----ZENDHTTPCLIENT-8e4c65a6678d3ef287a07eb1da6a5380
Content-Disposition: form-data; name="testkey"

testvalue
-----ZENDHTTPCLIENT-8e4c65a6678d3ef287a07eb1da6a5380
Content-Disposition: form-data; name="otherkey"

othervalue

Does anyone know how to properly receive files over HTTP PUT, or how to parse files out of the php://input stream?

===== UPDATE #1 =====

I have tried only the above method, don't really have a clue as to what I can do else.

I have gotten no errors using this method, besides that I don't get the desired result of the posted data and files.

===== UPDATE #2 =====

I'm sending this test request using Zend_Http_Client, as follows: (haven't had any problems with Zend_Http_Client so far)

$client = new Zend_Http_Client();
$client->setConfig(array(
    'strict'       => false,
    'maxredirects' => 0,
    'timeout'      => 30)
);
$client->setUri( 'http://...' );
$client->setMethod(Zend_Http_Client::PUT);
$client->setFileUpload( dirname(__FILE__) . '/files/lorem-ipsum.png', 'image_01');
$client->setParameterPost(array('testkey' => 'testvalue', 'otherkey' => 'othervalue');
$client->setHeaders(array(
    'api_key'    => '...',
    'identity'   => '...',
    'credential' => '...'
));

===== SOLUTION =====

Turns out I made some wrong assumptions, mainly that HTTP PUT would be similar to HTTP POST. As you can read below, DaveRandom explained to me that HTTP PUT is not meant for transferring multiple files on the same request.

I have now moved the transferring of formdata from the body to url querystring. The body now holds the contents of a single file.

For more information, read DaveRandom's answer. It's epic.

解决方案

The data you show does not depict a valid PUT request body (well, it could, but I highly doubt it). What it shows is a multipart/form-data request body - the MIME type used when uploading files via HTTP POST through an HTML form.

PUT requests should exactly compliment the response to a GET request - they send you the file contents in the message body, and nothing else.

Essentially what I'm saying is that it is not your code to receive the file that is wrong, it is the code that is making the request - the client code is incorrect, not the code you show here (although the parse_str() call is a pointless exercise).

If you explain what the client is (a browser, script on other server, etc) then I can help you take this further. As it is, the appropriate request method for the request body that you depict is POST, not PUT.


Let's take a step back from the problem, and look at the HTTP protocol in general - specifically the client request side - hopefully this will help you understand how all of this is supposed to work. First, a little history (if you're not interested in this, feel free to skip this section).

History

HTTP was originally designed as a mechanism for retrieving HTML documents from remote servers. At first it effectively supported only the GET method, whereby the client would request a document by name and the server would return it to the client. The first public specification for HTTP, labelled as HTTP 0.9, appeared in 1991 - and if you're interested, you can read it here.

The HTTP 1.0 specification (formalised in 1996 with RFC 1945) expanded the capabilities of the protocol considerably, adding the HEAD and POST methods. It was not backwards compatible with HTTP 0.9, due to a change in the format of the response - a response code was added, as well as the ability to include metadata for the returned document in the form of MIME format headers - key/value data pairs. HTTP 1.0 also abstracted the protocol from HTML, allowing for the transfer of files and data in other formats.

HTTP 1.1, the form of the protocol that is almost exclusively in use today is built on top of HTTP 1.0 and was designed to be backwards compatible with HTTP 1.0 implementations. It was standardised in 1999 with RFC 2616. If you are a developer working with HTTP, get to know this document - it is your bible. Understanding it fully will give you a considerable advantage over your peers who do not.

Get to the point already

HTTP works on a request-response architecture - the client sends a request message to the server, the server returns a response message to the client.

A request message includes a METHOD, a URI and optionally, a number of HEADERS. The request METHOD is what this question relates to, so it is what I will cover in the most depth here - but first it is important to understand exactly what we mean when we talk about the request URI.

The URI is the location on the server of the resource we are requesting. In general, this consists of a path component, and optionally a query string. There are circumstances where other components may be present as well, but for the purposes of simplicity we shall ignore them for now.

Let's imagine you type http://server.domain.tld/path/to/document.ext?key=value into the address bar of your browser. The browser dismantles this string, and determines that it needs to connect to an HTTP server at server.domain.tld, and ask for the document at /path/to/document.ext?key=value.

The generated HTTP 1.1 request will look (at a minimum) like this:

GET /path/to/document.ext?key=value HTTP/1.1
Host: server.domain.tld

The first part of the request is the word GET - this is the request METHOD. The next part is the path to the file we are requesting - this is the request URI. At the end of this first line is an identifier indicating the protocol version in use. On the following line you can see a header in MIME format, called Host. HTTP 1.1 mandates that the Host: header be included with every request. This is the only header of which this is true.

The request URI is broken into two parts - everything to the left of the question mark ? is the path, everything to the right of it is the query string.

Request Methods

RFC 2616 (HTTP/1.1) defines 8 request methods.

OPTIONS

The OPTIONS method is rarely used. It is intended as a mechanism for determining what kind of functionality the server supports before attempting to consume a service the server may provide.

Off the top of my head, the only place in fairly common usage that I can think of where this is used is when opening documents in Microsoft office directly over HTTP from Internet Explorer - Office will send an OPTIONS request to the server to determine if it supports the PUT method for the specific URI, and if it does it will open the document in a way that allows the user to save their changes to the document directly back to the remote server. This functionality is tightly integrated within these specific Microsoft applications.

GET

This is by far and away the most common method in every day usage. Every time you load a regular document in your web browser it will be a GET request.

The GET method requests that the server return a specific document. The only data that should be transmitted to the server is information that the server requires to determine which document should be returned. This can include information that the server can use to dynamically generate the document, which is sent in the form of headers and/or query string in the request URI. While we're on the subject - Cookies are sent in the request headers.

HEAD

This method is identical to the GET method, with one difference - the server will not return the requested document, if will only return the headers that would be included in the response. This is useful for determining, for example, if a particular document exists without having to transfer and process the entire document.

POST

This is the second most commonly used method, and arguably the most complex. POST method requests are almost exclusively used to invoke some actions on the server that may change its state.

A POST request, unlike GET and HEAD, can (and usually does) include some data in the body of the request message. This data can be in any format, but most commonly it is a query string (in the same format as it would appear in the request URI) or a multipart message that can communicate key/value pairs along with file attachments.

Many HTML forms use the POST method. In order to upload files from a browser, you would need to use the POST method for your form.

The POST method is semantically incompatible with RESTful APIs because it is not idempotent. That is to say, a second identical POST request may result in a further change to the state of the server. This contradicts the "stateless" constraint of REST.

PUT

This directly complements GET. Where a GET requests indicates that the server should return the document at the location specified by the request URI in the response body, the PUT method indicates that the server should store the data in the request body at the location specified by the request URI.

DELETE

This indicates that the server should destroy the document at the location indicated by the request URI. Very few internet facing HTTP server implementations will perform any action when they receive a DELETE request, for fairly obvious reasons.

TRACE

This provides an application-layer level mechanism to allow clients to inspect the request it has sent as it looks by the time it reaches the destination server. This is mostly useful for determining the effect that any proxy servers between the client and the destination server may be having on the request message.

CONNECT

HTTP 1.1 reserves the name for a CONNECT method, but does not define its usage, or even its purpose. Some proxy server implementations have since used the CONNECT method to facilitate HTTP tunnelling.

这篇关于如何使用PHP通过HTTP PUT接收文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆