Небольшая проверка исходного кода дает ответы.
Во-первых, да, вы ограничены одним чтением на дескриптор, поскольку базовый поток не реализует обработчик 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 активирован и суперглобальные элементы не используются).
- С нераспознанным или несуществующим типом контента . В этом случае нет определенного считывателя и обработчика POST. Оба случая заканчиваются на
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
действует как смешанный reader/handler
. В фазе sapi_activate
данные вообще не читаются. Функция sapi_handle_post
в конечном итоге вызывается на более позднем этапе, который, в свою очередь, вызывает обработчик POST. rfc1867_post_handler
читает данные запроса, заполняет POST
и FILES
, но ничего не оставляет в SG(request_info).raw_post_data
.
Случай 3. Этот последний случай имеет место с запросами, отличными от POST (например, PUT). php_default_post_reader
называется напрямую. Поскольку запрос не является запросом POST, данные поглощаются sapi_read_standard_form_data
. Поскольку данные не читаются, ничего не остается сделать.