PHP некоторые значения $_POST отсутствуют, но присутствуют в php://input
У меня очень большая форма html (содержащая таблицу со строками, содержащую несколько входов), которую мне нужно отправить на PHP скрипт через запрос POST.
Проблема в том, что некоторые значения не проходят и отсутствуют в PHP $_POST суперглобальной.
Я проверил (используя расширение Firebug), что значения фактически отправляются на сервер браузером.
$_ POST заселяется, но некоторые значения просто отсутствуют.
Я проверил, что является сырым запросом, используя:
$raw_post = file_get_contents('php://input');
а возвращаемая строка имеет значения. Они просто не анализируются в массив $_POST. Странная вещь, которую я заметил, кажется, что входные значения php://сокращаются после некоторой длины, а остальная часть строки не переходит в $_POST.
Я подумал о post_max_size и memory_limit и установил их в большие значения:
memory_limit = 256M
post_max_size = 150M
but according to php documentation $_POST should not contain any values if request made is bigger than post_max_size.
Из-за большого размера формы и запроса я не могу опубликовать ее здесь, но я могу отправить php script, я использовал для отладки проблемы:
var_dump($file = file_get_contents('php://input'));
var_dump($_POST);
//... then i parsed the $file
Версия сервера: Apache/2.2.9 (Debian)
PHP-версия: PHP 5.3.2-0.dotdeb.2
Можно объяснить причину такого странного поведения PHP, и что мне делать (изменить настройки php, код?), чтобы использовать массив $_POST при обработке формы?
EDIT: чтобы быть ясным: не только значения отсутствуют. $_POST также не содержит эти ключи.
e.x. фрагмент исходного сообщения:
t_dodparam%5B198%5D=&t_dodparam2%5B198%5D=&t_kolejnosc%5B198%5D=199&n_indeks=201&n_wartosc=testtesttest
Ключ "t_dodparam" находится в столбце и имеет ключ 198. Остальные параметры отсутствуют (ex t_dodparam2 находится в сообщении, но у него нет такого ключа, как 198, и нет такого ключа, как n_wartosc в $_POST)
Ответы
Ответ 1
PHP изменяет поля, содержащие пробелы символов, точку, открытую квадратную скобку и другие, совместимые с устаревшими register_globals
вы можете найти много обходных путей в комментариях здесь:
PHP: переменные из внешних источников
Для примера (комментарий POSTER):
<?php
//Function to fix up PHP messing up POST input containing dots, etc.
function getRealPOST() {
$pairs = explode("&", file_get_contents("php://input"));
$vars = array();
foreach ($pairs as $pair) {
$nv = explode("=", $pair);
$name = urldecode($nv[0]);
$value = urldecode($nv[1]);
$vars[$name] = $value;
}
return $vars;
}
?>
Ответ 2
Я просто исправил эту проблему, добавив значение в max_input_vars в свой файл конфигурации PHP. В соответствии с этим. он был введен в 5.3.9, но после некоторых обновлений пакетов я столкнулся с проблемой в 5.3.2.
Значение по умолчанию для max_input_vars равно 1000, что слишком мало для моей формы.
Ответ 3
Есть много разных вещей, которые могут быть причиной этого. Лучше всего проверить журнал ошибок. Многие из вещей, которые вызывают этот симптом, помещают сообщения в журнал ошибок, но не отображают ошибки в вашем приложении PHP.
Некоторые из возможных причин:
Suhosin
Suhosin - это расширение для PHP, предназначенное для защиты серверов и пользователей от известных и неизвестных недостатков в PHP-приложениях и ядре PHP. Одной из вещей, которые он делает, является ограничение размера $_POST, $_GET, $_REQUEST и $_COOKIE. Если ваша проблема - Suhosin, вы получите сообщение об ошибке в вашем журнале, например
ALERT - превышен предел переменной POST - сброшенная переменная 'foo'
Решение простое, просто увеличьте максимальное количество разрешенных переменных в php.ini. Если у вас нет секции сухозина, просто создайте ее. Например:
[suhosin]
suhosin.request.max_vars = 1000 # Default is 200
suhosin.post.max_vars = 1000 # Default is 200
Существуют другие настройки сухозина, которые могут вызвать это, но это наиболее вероятные кандидаты.
Неверные имена полей формы
В прежние времена PHP имел параметр, называемый register_globals (теперь лишенный), который автоматически преобразовывал переменные GET и POST в переменные PHP. Поэтому, если в вашей форме были поля "foo" и "bar", при отправке этой формы автоматически создаются переменные $foo и $bar. Однако существует несколько символов, которые недопустимы для использования в именах переменных PHP (пробел, точка, открытая квадратная скобка и другие). В зависимости от того, какие символы вы использовали, переменная может иметь недопустимые символы, лишенные ее значения, или быть отмененными. Несмотря на то, что register_globals больше не используется, PHP по-прежнему разделяет эти символы при построении $_POST, $_GET, $_REQUEST и $_COOKIE. Если вы не можете исправить значения полей формы, вы можете попробовать что-то вроде:
<?php
/**
* Converts raw POST data into an array.
*
* Does not work for hierarchical POST data.
*
* @return array
*/
function real_post() {
static $post;
if (!isset($post)) {
$pairs = explode("&", file_get_contents("php://input"));
$post = array();
foreach ($pairs as $pair) {
$x = explode("=", $pair);
$post[rawurldecode($x[0])] = rawurldecode($x[1]);
}
}
return $post;
}
?>
Ответ 4
Как насчет использования "parse_str" для преобразования строки запроса в php-структуры? Эта функция является инверсией http_build_query.
$b = array();
parse_str(file_get_contents("php://input"), $b);
Ответ 5
Я нашел этот ответ через поиск и почувствовал, что должен предложить альтернативный вопрос. В моем случае мой пост был не слишком большим, и все же значение, которое я подавал в поле, не отображалось в массиве $_POST. Как оказалось, у меня случайно было другое поле в моей форме с тем же именем. Итак:
<form>
<input type="text" name="field1">
<input type="text" name="field2">
<input type="text" name="field3">
<input type="text" name="field1">
<input type="submit">
</form>
Когда переменная $_POST
заполняется данными из этой формы, значение в вашем первом поле будет перезаписано значением в этом последнем поле с тем же именем. Если требуется первое поле, и вы заполните значение, но последнее поле не требуется и будет отправлено пустым, вы увидите похожие симптомы, как этот вопрос, потому что значение $_POST ['field1'] покажет значение последнего элемент в форме, который пуст.
TL;DR:
Обязательно проверьте наличие повторяющихся имен полей в вашей форме!
Ответ 6
Для справок в будущем:
В ящике Ubuntu я долгое время боролся с этой проблемой и использовал метод обхода, аналогичный описанному выше, чтобы сохранить день.
Теперь я отслеживал проблему на своем php.ini и, наконец, нашел ее в соответствии с
max_input_nesting_level = 0
Я прокомментировал строку выше, перезапустил apache и все исправил.
Ответ 7
Я отправляю функцию JQuery.ajax(). Я пытался извлечь мои данные из $_POST
, но был неполным. Затем я нашел этот пост, который поставил меня на правильный путь. Однако метод getRealPOST(), описанный выше, не работал у меня - он не может обрабатывать многомерные и вложенные массивы очень хорошо. Вместо этого я использовал метод PHP parse_str()
, который сделал трюк и был немного чище:
$rawdata = file_get_contents('php://input');
$urldecoded = urldecode($rawdata);
parse_str($urldecoded, $parsed);
$data = $parsed['data'];
(В моем JS я отправляю объект, где полезная нагрузка находится в свойстве data
. Вероятно, вы будете отличаться.)
Я также зашел в свой php.ini и сработал max_memory
и max_input_vars
, но, похоже, это не решило мою проблему. Я также провел некоторое время, преследуя красную селедку, потому что я использовал свой журнал ошибок для печати необработанных данных, и я забыл, что error_log
имеет ограничение на количество символов, которые он будет печатать, если вы не забудете его увеличить.
В любом случае, надеюсь, что это поможет любому, кто сталкивается с этой проблемой.
Ответ 8
У меня была эта же проблема, и оказалось, что я использовал AJAX для динамического изменения поля ввода на основе других входных данных в форме. Функция ajax повторно создала вход и не включила имя ввода.
Ответ 9
Пришел к этому (по общему признанию, старому) сообщению, пытаясь найти исправление ошибки Javascript Object, включая квадратные скобки в своих именах, а затем PHP запутался и действовал так, как будто он даже не слышал о гнездовании. @Dalin имеет хороший базовый ответ, но он не создает вложенный массив и не преобразовывает типы значений в boolean/number - следовательно, моя версия (get_real_post ( ) также находится на GitHub).
Несмотря на имя, это должно работать тождественно для _GET (т.е. что-либо, что захватывает php://input
).
/**
* Gets the _POST data with correct handling of nested brackets:
* "path[to][data[nested]]=value"
* "path"
* -> "to"
* -> "data[nested]" = value
* @return array
*/
function get_real_post() {
function set_nested_value(&$arr, &$keys, &$value) {
$key = array_shift($keys);
if (count($keys)) {
// Got deeper to go
if (!array_key_exists($key, $arr)) {
// Make sure we can get deeper if we've not hit this key before
$arr[$key] = array();
} elseif (!is_array($arr[$key])) {
// This should never be relevant for well formed input data
throw new Exception("Setting a value and an array with the same key: $key");
}
set_nested_value($arr[$key], $keys, $value);
} elseif (empty($key)) {
// Setting an Array
$arr[] = $value;
} else {
// Setting an Object
$arr[$key] = $value;
}
}
$input = array();
$parts = array();
$pairs = explode("&", file_get_contents("php://input"));
foreach ($pairs as $pair) {
$key_value = explode("=", $pair, 2);
preg_match_all("/([a-zA-Z0-9]*)(?:\[([^\[\]]*(?:(?R)[^\[\]]*)*)\])?/", urldecode($key_value[0]), $parts);
$keys = array($parts[1][0]);
if (!empty($parts[2][0])) {
array_pop($parts[2]); // Remove the blank one on the end
$keys = array_merge($keys, $parts[2]);
}
$value = urldecode($key_value[1]);
if ($value == "true") {
$value = true;
} else if ($value == "false") {
$value = false;
} else if (is_numeric($value)) {
if (strpos($value, ".") !== false) {
$num = floatval($value);
} else {
$num = intval($value);
}
if (strval($num) === $value) {
$value = $num;
}
}
set_nested_value($input, $keys, $value);
}
return $input;
}
Ответ 10
Я столкнулся с той же проблемой. Моя форма создавала входные элементы в цикле. Было отправлено до 1000 элементов ввода, и print_r($_POST);
показал все опубликованные значения.
Когда элементы ввода в форме пронумерованы выше 1000, print_r($_POST)
просто исчез. Как будто форма не была опубликована вообще. Я попал на вашу страницу stackoverflow.com с помощью поиска Google.
Да, увеличение post_max_size
, memory_limit
и т.д. Ничего не решило. У меня есть практический опыт, что увеличение memory_limit
после 128M
также может быть опасным. Однажды наш живой сервер хостинга Apache завис. Я был экспериментатором :-)
max_input_vars
был единственным ограничивающим фактором.
echo ini_get('max_input_vars');
показал, что это было 1000 по умолчанию.
Странно max_input_vars
отсутствовал в php.ini.
В любом случае я добавил
max_input_vars=10000
в моем php.ini и перезапустил Apache.
Теперь echo ini_get('max_input_vars');
показал, что он увеличился до 10000
и мои большие данные формы могут быть перехвачены после публикации. Проблема решена.
Я вижу, что max_input_vars имеет тип PHP_INI_PERDIR. Это означает, что я не могу изменить его значение для отдельной php-страницы, где мне нужно более высокое значение, используя ini_set ('max_input_vars', 10000);
Ответ 11
У меня возникла такая же проблема, и я нашел очень ценное решение без увеличения каких-либо ограничений или размеров в .ini.
Мы знаем, что max_input_vars = 1000 по умолчанию, и это префект.
Просто сделайте одну вещь, чтобы объединить значения массива и попытаться точно определить количество переменных ниже 1000.
Каждое имя переменной считается одним из них.
Например:
<code>
$i = 10; //counts 1
$i = array(1,2,3,4,5); //counts 5
</code>
Вы можете сделать это:
<code>
$i = 1_2_3_4_5; // counts 1
</code>
Надеемся на понимание.
Ответ 12
используйте эту функцию для получения достоверных данных
function get_real_post() {
function set_nested_value(&$arr, &$keys, &$value) {
$key = array_shift($keys);
if (count($keys)) {
// Got deeper to go
if (!array_key_exists($key, $arr)) {
// Make sure we can get deeper if we've not hit this key before
$arr[$key] = array();
} elseif (!is_array($arr[$key])) {
// This should never be relevant for well formed input data
throw new Exception("Setting a value and an array with the same key: $key");
}
set_nested_value($arr[$key], $keys, $value);
} elseif (empty($key)) {
// Setting an Array
$arr[] = $value;
} else {
// Setting an Object
$arr[$key] = $value;
}
}
$input = array();
$parts = array();
$rawdata=file_get_contents("php://input");
$rawdata=urldecode($rawdata);
$pairs = explode("&", $rawdata);
foreach ($pairs as $pair) {
$key_value = explode("=", $pair, 2);
preg_match_all("/([a-zA-Z0-9_]*)(?:\[([^\[\]]*(?:(?R)[^\[\]]*)*)\])?/", urldecode($key_value[0]), $parts);
$keys = array($parts[1][0]);
if (isset($parts[2][0])&&$parts[2][0]!="") {
array_pop($parts[2]); // Remove the blank one on the end
$keys = array_merge($keys, $parts[2]);
}
$value = urldecode($key_value[1]);
if ($value == "true") {
$value = true;
} else if ($value == "false") {
$value = false;
} else if (is_numeric($value)) {
if (strpos($value, ".") !== false) {
$num = floatval($value);
} else {
$num = intval($value);
}
if (strval($num) === $value) {
$value = $num;
}
}
set_nested_value($input, $keys, $value);
}
return $input;
}
Ответ 13
У меня была похожая проблема, и изменение MAX_INPUT_VARS устранило ее.
Стоит проверить, что вы отправляете, а что получаете. В моем случае вызов AJAX содержал отформатированный массив всех значений, кроме VAR_DUMP ($this-> input-> post()); выявлены пропущенные значения.
Итак, очевидный ответ был, как кто-то здесь сказал, - max_input_vars.
Ответ 14
Вам нужно изменить значение max_input_vars в файле php.ini
Шаг 1: Найдите файл php.ini
Шаг 1 (а): Распечатайте значения php-информации, чтобы узнать все предопределенные конфигурации PHP.
echo phpinfo(); //will print the php info values
шаг 1 (b): запишите местоположение файла php.ini из значений phpinfo, напечатанных на предыдущем шаге, как показано на рисунке ниже
![enter image description here]()
Шаг 2. Отредактируйте файл php.ini.
Шаг 2 (а): Найдите переменную max_input_vars, удалите точку с запятой перед ней и установите значение 10000, как показано ниже
max_input_vars = 10000
шаг 3: перезапустите apache
sudo service apache2 restart
Ответ 15
Используйте htmlspecialchars
с вашим $_POST. Например:
$day1=htmlspecialchars($_POST["day"]);
Я надеюсь, что это сработает.