How to check for incomplete POST request in PHP

2019-06-16 20:04发布

I am facing a problem when a remote web client with slow connection fails to send complete POST request with multipart/form-data content but PHP still uses partially received data to populate $_POST array. As a result one value in $_POST array can be incomplete and more values can be missing. I tried to ask same question in Apache list first and got an answer that Apache doesn't buffer the request body and passes it to PHP module as a giant blob.

Here is my sample POST request:

POST /test.php HTTP/1.0
Connection: close
Content-Length: 10000
Content-Type: multipart/form-data; boundary=ABCDEF

--ABCDEF
Content-Disposition: form-data; name="a"

A
--ABCDEF

You can see that Content-Length is 10000 bytes, but I send just one var a=A.

The PHP script is:

<?php print_r($_REQUEST); ?>

Web server waits for about 10 seconds for the rest of my request (but I don't send anything) and then returns this response:

HTTP/1.1 200 OK
Date: Wed, 27 Nov 2013 19:42:20 GMT
Server: Apache/2.2.22 (Debian)
X-Powered-By: PHP/5.4.4-14+deb7u3
Vary: Accept-Encoding
Content-Length: 23
Connection: close
Content-Type: text/html

Array
(
     [a] => A
)

So here is my question: How can I verify in PHP that the post request was received completely? $_SERVER['CONTENT_LENGTH'] would show 10000 from the request header, but is there a way to check the real content length received?

12条回答
ら.Afraid
2楼-- · 2019-06-16 20:17

They probably get cutoff by limits in Apache or PHP. I believe Apache also has a config variable for this.

Here are the PHP settings;

php.ini

post_max_size=20M
upload_max_filesize=20M

.htaccess

php_value post_max_size 20M
php_value upload_max_filesize 20M
查看更多
成全新的幸福
3楼-- · 2019-06-16 20:18

maybe you can check with a valid variable, but not length, eg:

// client
$clientVars = array('var1' => 'val1', 'otherVar' => 'some value');
ksort($clientVars);  // dictionary sorted
$validVar = md5(implode('', $clientVars));
$values = 'var1=val1&otherVar=some value&validVar=' . $validVar;
httpRequest($url, values);

// server
$validVar = $_POST['validVar'];
unset($_POST['validVar']);
ksort($_POST);  // dictionary sorted
if (md5(implode('', $_POST)) == $validVar) {
    // completed POST, do something
} else {
    // not completed POST, log error and do something
}
查看更多
贼婆χ
4楼-- · 2019-06-16 20:24

I guess that the remote client is actually a browser with HTML page. otherwise, let me know and i'll try to adapt my solution.

You can add field <input type="hidden" name="complete"> (for example) as the last parameter. in PHP check firstly whether this parameter was sent from client. if this parameter sent - you can be sure that you got the entire data.

Now, i'm not sure that the order of parameters must be preserved according the RFC (of both, HTML and HTTP). but i've tried some variations and i saw that the order kept indeed.

Better solution will be, calculate (on client side) hash of the parameters and send him as another parameter. so you can be absolutely sure that you got the entire data. But this is starting to sound complicated...

查看更多
霸刀☆藐视天下
5楼-- · 2019-06-16 20:25

I think what you are looking for is $HTTP_RAW_POST_DATA, this will give you the real POST length and then you can compare it to $_SERVER['CONTENT_LENGTH'].

查看更多
Fickle 薄情
6楼-- · 2019-06-16 20:26

This is a known bug in PHP and needs to be fixed there - https://bugs.php.net/bug.php?id=61471

查看更多
闹够了就滚
7楼-- · 2019-06-16 20:27

If you can change the enctype to

multipart/form-data-alternate

the you can check

strlen(file_get_contents('php://input'))

vs.

$_SERVER['CONTENT_LENGTH']
查看更多
登录 后发表回答