$ HTTP_RAW_POST_DATA не заполняется после обновления до PHP 5.3 - PullRequest
3 голосов
/ 17 января 2012

Мой скрипт получает сжатые данные из настольного приложения через POST, которые он извлекает и обрабатывает из $HTTP_RAW_POST_DATA.В PHP 5.2.16 (ISAPI) $HTTP_RAW_POST_DATA правильно заполняется ожидаемыми двоичными данными.После обновления до PHP 5.3.9 (FastCGI) $HTTP_RAW_POST_DATA не определяется.Как я могу получить данные?

Я использую IIS 5.1 под 32-битной Windows XP SP3.


Документы относительно $HTTP_RAW_POST_DATA утверждают, что 'недоступно с enctype = "multipart / form-data"' , но я не использую этот тип содержимого.(Вспомните, что тот же самый код отлично работает в PHP 5.2, поэтому тип контента тогда тоже был бы проблемой.)

Когда я включил директиву always_populate_raw_post_data ini , ничего не изменилось.phpinfo() сообщает, что установлено значение «Вкл.», Но переменная по-прежнему не устанавливается.

Документы также предполагают, что предпочтительным способом получения этих данных является чтение их из потока php://input.Я попытался сделать это следующим образом:

$HTTP_RAW_POST_DATA = file_get_contents('php://input');

, но сценарий просто висит на этой строке, предположительно потому, что он ожидает данные (то есть, конец файла не отправляется).Даже если я ограничу максимальную длину значением, равным одному байту, как показано ниже, он все равно зависнет.

$HTTP_RAW_POST_DATA = file_get_contents('php://input', false, null, -1, 1);

Единственный раз, когда он не зависает на этой строке, это когда я устанавливаю maxlen до 0, что означает, что он не пытается ничего читать, но также не помогает.: -)

Если $HTTP_RAW_POST_DATA не заполнится, когда я заставлю его, и я ничего не могу получить от php://input, как я могу получить данные?

тот факт, что php://input, по-видимому, пустой, указывает на разницу между ISAPI и FastCGI?Я не читал ничего, что подсказывало бы, что необработанные POST ведут себя по-другому или теряются при использовании FastCGI.


Вот некоторые соответствующие части $_SERVER.Все эти значения идентичны при запуске сценария с PHP 5.2 и PHP 5.3.

[CONTENT_LENGTH] => 4294967295
[CONTENT_TYPE] => application/client-gzip
[HTTP_HOST] => 127.0.0.1
[HTTP_CONTENT_TYPE] => application/client-gzip
[HTTP_TRANSFER_ENCODING] => chunked
[HTTP_ACCEPT_ENCODING] => gzip
[HTTP_EXPECT] => 100-continue
[REQUEST_METHOD] => POST
[SERVER_NAME] => 127.0.0.1
[SERVER_PORT] => 80
[SERVER_PROTOCOL] => HTTP/1.1

(Примечание: я знаю, что длина содержимого в 4 ГБ выглядит странно, но потому, что он использует кодированное кодирование ), CONTENT_LENGTH игнорируется.)

Поскольку заголовок CONTENT_LENGTH не используется, могу ли я проверить, что данные действительно где-то принимаются PHP, а непотерян IIS?

Так как данные отправляются из двоичной библиотеки в клиенте рабочего стола, изменение формата POST не вариант.Независимо от плюсов и минусов использования $HTTP_RAW_POST_DATA, вот так я должен это делать.Раньше это работало так, поэтому я полностью ожидаю, что это сработает сейчас.Любое понимание искренне приветствуется!


Обновление

Вот простой сценарий, иллюстрирующий мою проблему.Есть два файла:

postsend.php

<?php
$headers = array(
    "Content-Type: application/client-gzip",
    // "Transfer-Encoding: chunked",
);

$text = 'This text is superior to your text even though it is useless.';
$data = gzdeflate($text);

echo "text: $text<br />gzip: $data<br />";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,            "http://localhost/server/postreceive.php");
curl_setopt($ch, CURLOPT_USERPWD,        "user:pass");
curl_setopt($ch, CURLOPT_HTTPAUTH,       CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST,           1);
curl_setopt($ch, CURLOPT_POSTFIELDS,     $data); 
curl_setopt($ch, CURLOPT_HTTPHEADER,     $headers); 

$result = curl_exec($ch);
echo $result;

postreceive.php

<?php
if (!empty($HTTP_RAW_POST_DATA)) {
    printf(
        'HTTP_RAW_POST_DATA set!<br />gzip:%s<br />text: %s',
        $HTTP_RAW_POST_DATA,
        gzinflate($HTTP_RAW_POST_DATA)
    );
} else {
    echo 'No raw data. :-(';
}

В PHP 5.3 (FastCGI) это работает, когда я запускаю postsend.phpи вывод:

text: This text is superior to your text even though it is useless.
gzip: ÉÈ,V(I­(QÒÅ¥©E™ùE %ù •ù¥E‰Ô²Ô<…’ŒüÒô …L°ºÒâÔœÔâb=
HTTP_RAW_POST_DATA set!
gzip: ÉÈ,V(I­(QÒÅ¥©E™ùE %ù •ù¥E‰Ô²Ô<…’ŒüÒô …L°ºÒâÔœÔâb=
text: This text is superior to your text even though it is useless.

Однако, если я раскомментирую строку с заголовком Transfer-Encoding, все будет зависать при запуске postsend.php.Итак, получение chunked-кодировки, похоже, нарушает его.

Есть ли какая-то конфигурация IIS или FastCGI, которая мне не хватает, которая позволила бы этому работать при получении chunked-кодировки?(Если да, то теперь это более уместно в качестве вопроса ServerFault?) Я видел настройки, которые позволяют отправлять чанкованное кодирование, но не принимать чанкованное кодирование.

Ответы [ 4 ]

1 голос
/ 02 сентября 2012

Как в конечном итоге определено в отчете об ошибке # 60826 , эта проблема вызвана не только PHP в веб-стеке.
Это недостаток того, как FastCGI реализован на различных веб-серверах.

1 голос
/ 17 января 2012

Наличие $_SERVER['HTTP_EXPECT'] подсказывает мне, что, возможно, этот запрос не имеет данных, и вам нужно ответить с помощью HTTP/1.1 100 Continue, прежде чем клиент ответит данными.См. http-спецификацию по использованию Expect и 100 Continue.Однако я не знаю, почему file_get_contents('php://input') не сразу возвращает пустую строку.

Кроме того, я не уверен, что IIS + FastCGI поддерживает фрагментированные кодировки передачи без буферизации.Есть настройка transferMode IIS, которая может быть полезна для изучения.

Наконец, если вы все же заработаете, будьте осторожны, что вам может понадобиться "декунтировать" (декодировать тело transfer-encoding: chunked) ввод запроса дажехотя ты не должен был делать это раньше.Вы можете использовать это так:

$fp = fopen('php://input', 'rb');
stream_filter_append($fp, 'dechunk', STREAM_FILTER_READ);
$HTTP_RAW_POST_DATA = stream_get_contents($fp);

Если вам нужно сделать это на PHP <5.3, я написал <a href="http://dancingmammoth.com/2009/08/29/php-stream-filters-unchunking-http-streams/" rel="nofollow">http_unchunk_filter потоковый фильтр , который делает то же самое.

1 голос
/ 08 марта 2012

У меня была та же проблема.

Обычный fopen без каких-либо модификаторов: fopen("php://input") дал мне «ложь». fopen("php://input","rb") работал.

0 голосов
/ 17 января 2012

эта запись об ошибке предполагает, что она не работает как в версии 5.1 php, так и в версии 5.2. Я не был бы удивлен, если бы они сломали это также для версии 5.3, поэтому я предлагаю открыть ошибку там. 5.3.9 был выпущен неделю назад, так что это также наводит на мысль, что там могут быть ошибки, которые еще не были найдены.

То, что вы также можете попробовать, это проверить, помогает ли понижение рейтинга.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...