1

我正在开发carddav客户端。作为服务器,我使用 davical v. 0.9.9.6。我不明白为什么当 http 标头包含正确的值时我会收到无效的内容类型错误。我查看了源代码并发现了这种情况:

if ( isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 7) {...

经过一番研究,我发现 php$_SERVER['CONTENT_LENGTH']只设置了 POST 方法和上传文件。有什么方法可以将 php 配置为始终设置$_SERVER['CONTENT_LENGTH']?我问的是一般情况,不仅针对这种情况...

//编辑我正在向 davical 服务器发出 HTTP PUT 请求(使用 php curl)。

PUT /caldav.php/testuser/contacts/newc.vcf HTTP/1.1
Host: davical  
Content-Type: text/vcard;

BEGIN:VCARD
VERSION:3.0
FN:ME
...

在 davical 方面是条件测试 CONTENT_LENGTH 未设置。所以这是一个davical bug?

//编辑2

最后我想通了!带有回调 readfunc 的 PUT 请求需要通过 curl_setopt(...) 设置 INFILE_SIZE 没有自动值,并且手动将 Content-Length 字段放入标头中也是错误的。示例(不正确):

// PUT REQUEST
curl_setopt($ch,CURLOPT_HTTPHEADER,"Content-Length: $length");  //mistake
curl_setopt($ch,CURLOPT_PUT,true);
curl_setopt($ch,CURLOPT_READFUNCTION,array($this,'readfunc'));
....
--------------------------------------------------------------
// WIRESHARK TCP STREAM DUMP
PUT /caldav.php/testuser/contacts/novy.vcf HTTP/1.1
Authorization: Basic xxxxxxxxxxxxxxx
Host: davical
Accept: */*
Content-Type: text/vcard
Content-Length: xxx
Expect: 100-continue

HTTP/1.1 100 Continue

155
BEGIN:VCARD
VERSION:3.0
...
END:VCARD

0

HTTP/1.1 200 OK
----------------------------------------------------------------
// On server side
isset($_SERVER['CONTENT_LENGTH'])==false

第二个(正确)示例

// PUT REQUEST
curl_setopt($ch,CURLOPT_INFILESIZE,$length);
curl_setopt($ch,CURLOPT_PUT,true);
curl_setopt($ch,CURLOPT_READFUNCTION,array($this,'readfunc'));
....
--------------------------------------------------------------
// WIRESHARK TCP STREAM DUMP
PUT /caldav.php/testuser/contacts/novy.vcf HTTP/1.1
Authorization: Basic xxxxxxxxxxxxxxx
Host: davical
Accept: */*
Content-Type: text/vcard
Content-Length: xxx
Expect: 100-continue

HTTP/1.1 100 Continue

BEGIN:VCARD
VERSION:3.0
...
END:VCARD
HTTP/1.1 200 OK
----------------------------------------------------------------
// On server side
isset($_SERVER['CONTENT_LENGTH'])==true
4

3 回答 3

1

虽然我从未使用过 CONTENT_LENGHT,但我可以告诉你为什么会发生这种情况:

在请求中,您不必设置 Content-Lenght 标头...这不是强制性的。特殊情况除外。如果您发布的内容属于“multipart/form-data”类型,则有必要对每个部分使用 content-lenght,因为每个部分都由边界分隔,并且每个部分都有自己的标题...

例如:

Content-Type: MultiPart/Form-Data
Boundary: @FGJ4823024562DGGRT3455

MyData=1&Username=Blabla&Password=Blue


@FGJ4823024562DGGRT3455==
Content-Type: image/jpef:base64
Content-Lenght: 256

HNSIFRTGNOHVDFNSIAH$5346twSADVni56hntgsIGHFNR$Iasdf==

所以这是一个多部分请求工作原理的粗略示例,您会看到第二部分具有内容长度。这就是为什么有时设置内容长度有时不设置的原因,因为您需要在找到另一个边界之前读取 X 个字节并提取正确的数据。

这并不意味着您的服务器在其他情况下永远不会发送它,但我的 2 美分现在就是这种情况。这是因为您不是在 POST 中,而是在其他一些模式中。

于 2011-10-01T11:00:42.170 回答
1

只有具有请求主体的请求才具有内容长度请求标头(或至少只有这样才有意义),因此$_SERVER设置了变量。

如果您需要始终设置它(我认为这是虚假的),您可以在脚本的最开始自己执行此操作:

isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] = 0;

假设如果没有设置,它的长度为零。另请参阅PHP 中对 HTTP 请求的改进处理

于 2011-10-01T11:00:48.537 回答
0

您可能可以自己设置它们。为什么需要设置这些值?他们应该设置什么?

也许您像我一样缺少有关 $_SERVER['CONTENT_TYPE'] 或 $_SERVER['CONTENT_LENGTH'] 的信息。在 POST 请求中,除了上面列出的那些之外,这些都是可用的。

-> http://www.php.net/manual/en/reserved.variables.server.php#86495

于 2011-10-01T10:57:14.603 回答