Запрос POST для PHP7 с закодированным кодированием неправильно возвращает результат
Я отправляю запрос POST от клиента (тестируется с помощью curl
и custom nodejs script) и не возвращает ответ правильно. Все это отлично работает с PHP 5.6.
Окружающая среда
Все это сокращается как можно больше:
- все работает внутри Vagrant VM Ubuntu 14.04 LTS
- nginx 1.9.7 из http://nginx.org/packages/ubuntu/
- PHP7 FPM, составленный из официальных источников с помощью
--disable-all --enable-fpm
Минимальная конфигурация сайта nginx, которую я использую:
server {
listen 80;
server_name localhost;
location / {
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_pass unix:/var/run/php/php7.0-fpm-api.sock;
fastcgi_param SCRIPT_FILENAME /vagrant/index.php;
}
}
Пример PHP script from /vagrant/index.php
:
<?php
echo str_repeat('.', 512);
flush(); // not necessary, only due testing
curl call, который я использую: curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
NodeJS script Я использую:
'use strict';
var http = require('http');
var url = require('url');
var uri = url.parse(process.env.URL);
var options = {
method: 'POST', protocol: uri.protocol, hostname: uri.hostname,
port: uri.port, path: uri.path,
};
var data = '';
var httpRequest = http.request(options, function(res) {
res.on('data', function(chunk) {
console.log('received data', chunk.length);
data += chunk;
});
res.on('end', function() { console.log('final size', data.length); });
})
.on('error', function(err) { console.log(err); });
httpRequest.write('');
httpRequest.end();
Отправка моих тестовых запросов на PHP 5.6
$ curl http://localhost/
..........[cut off]
$ curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
..........[cut off]
$ URL=http://localhost/ node php7test.js
received data 512
final size 512
Отправка моих тестовых запросов на PHP 7.0
$ curl http://localhost/
..........[cut off]
$ URL=http://localhost/ node php7test.js
final size 0
$ curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
curl: (18) transfer closed with outstanding read data remaining
Почему я обманываю с кодировкой chunked?
Нет никаких оснований для этого, однако я использовал очень похожий код NodeJS, который по умолчанию использует закодированную кодировку, которая неожиданно перестала работать при переключении на PHP7.
Я нашел следующее для работы со стороны nodejs: явная установка заголовка Content-Length
удаляет неявный заголовок Transfer-Encoding: chunked
, отправленный NodeJS, и поэтому работает с обеими версиями PHP.
Однако я хотел бы понять, почему PHP7 ведет себя по-другому здесь и есть ли я в ошибке или что действительно происходит здесь.
Обновление 1:
- Я сравнивал источники
sapi/fpm/
между 5.6 и 7.0, и почти не было различий, которые я мог обнаружить, кроме изменений из-за внутренних изменений PHP.
- Не влияет на встроенный сервер (
php -S
), все тесты
Обновление 2:
Я делят пополам источники PHP и смог определить, когда изменилось поведение:
В промежутке, вывод из git bisect
, я не могу скомпилировать:
$ git bisect skip
There are only 'skip'ped commits left to test.
The first bad commit could be any of:
ba5ecf355fe792a5a2a8e6582d5e081d02b16fbf
e383cb4493031a7cd952cfcaed3297e583149c07
fef18f4bea1980a59a9283c2197bd090aaf500cb
18cf4e0a8a574034f60f4d123407c173e57e54ec
We cannot bisect more!
Имея чувство, что это может быть ошибкой, я написал это внутренним, возможно, у них есть некоторые идеи: https://marc.info/?l=php-internals&m=145090900217798&w=2
Ответы
Ответ 1
Это/была ошибкой в PHP7, которая была исправлена совсем недавно с https://github.com/php/php-src/pull/1745. Это еще не в официальном выпуске, но в конечном итоге закончится там некоторое время.
До вышеприведенного PR была также отмечена ошибка, описывающая аналогичную проблему: https://bugs.php.net/bug.php?id=71466
Ответ 2
Из вашего сообщения я предполагаю, что вы используете PHP7.0.0. Если моя догадка (bool) ИСТИНА, я предлагаю вам перейти на PHP7.0.1.
PHP7.0.0 имеет примерно 27 ошибок, которые были сжаты в PHP7.0.1; среди других фиксированных элементов.
Источник: PHP.ru changelog.
Я также посмотрел ваш PHP-код выше (с моими очками в google), но это смехотворно просто. Я сомневаюсь, что с ним что-то может быть не так. Хотя я предполагаю, что это связано с тем, как PHP7 обрабатывает flush() и выводит.
Далее:
Отмечаем ваши обновления (особенно Обновление 1 и Обновление 2); Я действительно заслужил вас! ЧТО ОЧЕНЬ ВПЕЧАТЛЯЕТ.
Обязательно проверьте эту исправленную ошибку # 61751. Если бы я был прав относительно вашей версии PHP, то эта исправленная ошибка могла решить вашу проблему; вам просто нужно перейти на PHP7.0.1.
ПРИМЕЧАНИЕ: Я знаю, что я должен проверить внутренности исправленной ошибки, но...