Документация PHP указывает это php://input
может только быть считан однажды.
В моем приложении я должен считать его дважды, однажды в целях аутентификации и однажды для того, чтобы на самом деле обработать содержание, и обе функции обрабатываются различными, независимыми модулями. Сумасшедшая вещь:работает.
Я могу рассчитывать на эту работу везде, или действительно ли это - счастливая случайность в моей версии PHP (5.2.10)? Единственная документация, которую я могу найти об этом, является той, которая указывает, что это не должно работать без упомянутого ограничения версии.
После догадки Dennis я сделал этот тест:
$in = fopen('php://input', 'r');
echo fread($in, 1024) . "\n";
fseek($in, 0);
echo fread($in, 1024) . "\n";
fclose($in);
echo file_get_contents('php://input') . "\n";
Завихрение:
$ curl http://localhost:8888/tests/test.php -d "This is a test"
This is a test
This is a test
По-видимому, это ограничено одним чтением на открытый дескриптор.
Немного больше рытья показало это действительно php://input
может только быть считан однажды, когда-либо, для ПОМЕЩЕННЫХ запросов. Вышеупомянутый пример использовал запрос POST.
Небольшой просмотр исходного кода дает ответы.
Во-первых, да, вы ограничены одним чтением на дескриптор, потому что базовый поток не реализует обработчик seek
:
php_stream_ops php_stream_input_ops = {
php_stream_input_write,
/* ... */
"Input",
NULL, /* seek */
/* ... */
};
Во-вторых, обработчик чтения имеет два разных поведения в зависимости от того, " Данные POST "были прочитаны и сохранены в SG (request_info) .raw_post_data
.
if (SG(request_info).raw_post_data) {
read_bytes = SG(request_info).raw_post_data_length - *position;
/* ...*/
if (read_bytes) {
memcpy(buf, SG(request_info).raw_post_data + *position, read_bytes);
}
} else if (sapi_module.read_post) {
read_bytes = sapi_module.read_post(buf, count TSRMLS_CC);
/* ... */
} else {
stream->eof = 1;
}
Таким образом, у нас есть три возможности:
SG (request_info) .raw_post_data
. В этом случае, поскольку данные сохранены, мы можем открыть и прочитать несколько дескрипторов для php: // input
. php: // input
не может нам ничего дать. php: // input
и прочитать его только один раз. ПРИМЕЧАНИЕ. Далее следует поведение по умолчанию. Различные SAPI или дополнительные расширения могут изменить это поведение.
В случае запросов POST, PHP определяет другое средство чтения POST и обработчик POST в зависимости от типа содержимого.
Случай 1. Это происходит, когда у нас есть запрос POST:
application / x-www-form-encoded
. sapi_activate
обнаруживает запрос POST с типом содержимого и вызывает sapi_read_post_data
. Это определяет тип содержимого и определяет пару POST-считыватель / обработчик. Читателем POST является sapi_read_standard_form_data
, который вызывается немедленно и просто копирует тело запроса в SG (request_info).post_data
. Затем вызывается программа чтения сообщений по умолчанию php_default_post_reader
, которая заполняет $ HTTP_RAW_POST_DATA
, если установлен ini-параметр always_populate_post_data
, а затем копирует SG (request_info) .post_data.
- SG (request_info) .raw_post_data
и очищает первый. Вызов обработчика здесь не имеет значения и откладывается до тех пор, пока суперглобальные объекты не будут построены (чего может и не произойти, если JIT активирован и суперглобальные объекты не используются). php_default_post_reader
без чтения каких-либо данных. Так как это POST-запрос и пара считыватель / обработчик отсутствует, будет вызван sapi_read_standard_form_data
. Это та же функция, что и у обработчика чтения с типом контента application / x-www-form-encoded
, поэтому все данные попадают в SG (request_info) .post_data
. Единственное отличие от этого момента состоит в том, что $ HTTP_RAW_POST_DATA
всегда заполняется (независимо от значения always_populate_post_data
) и нет обработчика для построения суперглобальных переменных. Случай 2. Это происходит, когда у нас есть запрос формы с типом содержимого "multipart / form-data". Считыватель POST имеет значение NULL
, поэтому обработчик, которым является rfc1867_post_handler
, действует как смешанный считыватель / обработчик
. На этапе sapi_activate
никакие данные не читаются.Функция sapi_handle_post
в конечном итоге вызывается на более позднем этапе, который, в свою очередь, вызывает обработчик POST. rfc1867_post_handler
считывает данные запроса, заполняет POST
и ФАЙЛЫ
, но ничего не оставляет в SG (request_info) .raw_post_data
.
Случай 3. Этот последний случай имеет место с запросами, отличными от POST (например, PUT). php_default_post_reader
вызывается напрямую. Поскольку запрос не является запросом POST, данные поглощаются sapi_read_standard_form_data
. Поскольку данные не считываются, ничего не остается.
Возможно, они означают, что fseek () или rewind () недоступны. Вы пробовали использовать одну из этих функций на открытом вводе php: //?