Подтвердить что ты не робот

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)

4b9b3361

Ответ 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"]);

Я надеюсь, что это сработает.