PHP缺少一些$ _POST值但存在于php:// input中

时间:2011-02-22 12:14:53

标签: php post

我有一个非常大的html表单(包含行的表,其中包含多个输入),我需要通过POST请求提交给PHP脚本。 问题是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
但根据php文档,如果请求的大于post_max_size,则$ _POST不应包含任何值。

由于表单和请求的大小我不能在这里发布,但我可以发布用于调试问题的php脚本:


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

可以enyone解释这种奇怪的PHP行为的原因,我该怎么做(更改php设置,代码?)在处理表单时使用$ _POST数组?

编辑:要明确:不仅缺少值。 $ _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在post中,但它没有198这样的密钥,并且$ _POST中没有n_wartosc这样的密钥)

14 个答案:

答案 0 :(得分:30)

我刚刚在PHP配置文件中为max_input_vars添加了一个值来解决这个问题。根据{{​​3}}。它是在5.3.9中引入的,但经过一些软件包升级后,我在5.3.2中遇到了这个问题。

max_input_vars的默认值是1000,这对我的表单来说太小了。

答案 1 :(得分:29)

PHP修改包含字符space,dot,open square bracket等的字段以与不推荐使用的register_globals

兼容

您可以在这里的评论中找到很多解决方法: PHP: Variables From External Sources

例如(POSTer评论):

<?php
//Function to fix up PHP's 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 :(得分:10)

有许多不同的事情可能导致这种情况。最好检查您的错误日志。导致此症状的许多事情都会将消息放入错误日志中,但不会在PHP应用程序中显示错误。

一些可能的原因:

了Suhosin

Suhosin是PHP的扩展,旨在保护服务器和用户免受PHP应用程序和PHP核心中的已知和未知缺陷的影响。它所做的一件事是限制$ _POST,$ _GET,$ _REQUEST和$ _COOKIE的大小。如果您的问题是Suhosin,您的日志中会出现错误,例如

警报 - 超出配置的POST变量限制 - 删除变量'foo'

解决方案很简单,只需增加php.ini中允许的最大变量数。如果你没有suhosin部分,只需创建一个。像这样:

[suhosin]
suhosin.request.max_vars = 1000 # Default is 200
suhosin.post.max_vars = 1000 # Default is 200

还有其他的suhosin设置会导致这种情况,但这些设置最有可能。

表单字段名称无效

回到过去,PHP有一个名为register_globals(现在是depricated)的设置,它自动将GET和POST变量转换为PHP变量。因此,如果您的表单包含字段'foo'和'bar',则在提交该表单时,将自动创建变量$ foo和$ bar。但是,有几个字符在PHP变量名称(空格,点,空方括号等)中无效。根据您使用的字符,变量可能会删除无效字符,丢失其值或取消设置。尽管不再使用register_globals,但在构建$ _POST,$ _GET,$ _REQUEST和$ _COOKIE时,PHP仍然会删除这些字符。如果您无法修复表单字段的值,可以尝试以下操作:

<?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;
}
?>

答案 3 :(得分:6)

如何使用“parse_str”将查询字符串转换为php结构?这个函数与http_build_query相反。

    $b = array();
    parse_str(file_get_contents("php://input"), $b);

答案 4 :(得分:1)

我通过搜索找到了这个答案,觉得我应该提供另一个问题。在我的情况下,我的帖子不是太大,但我在字段中提交的值没有显示在$ _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']将显示最后一个字段的值你形成的元素是空的。

<强> TLDR:

请务必检查表单中的重复字段名称!

答案 5 :(得分:1)

供将来参考: 在一个Ubuntu盒子里,我一直在努力解决这个问题,因为相对较长的时间,并且习惯采用与上述类似的解决方法来节省一天。 我现在在我的php.ini中跟踪了这个问题,最后发现它符合 max_input_nesting_level = 0 我评论了上面的一行,重新启动了apache并修复了所有内容。

答案 6 :(得分:1)

我发布了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_memorymax_input_vars,但它似乎没有解决我的问题。我还花了一段时间追逐一只红鲱鱼,因为我正在使用我的错误日志来打印原始数据,我忘了error_log限制它将打印多少个字符,除非你记得增加它。

无论如何,希望这有助于任何发现自己在与这个问题作斗争的人。

答案 7 :(得分:1)

我遇到了同样的问题,结果发现我正在使用AJAX根据表单中的其他输入动态修改输入字段。 ajax函数重新创建了输入,但未包含输入名称。

答案 8 :(得分:1)

遇到这个(不可否认的老)帖子,同时试图找到修复Javascript对象键的错误,包括名字中的方括号,然后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;
}

答案 9 :(得分:1)

我遇到了同样的问题。我的表单是在循环中创建输入元素。最多发布了1000个输入元素,print_r($_POST);显示了所有发布的值。

当输入元素的编号高于1000时,print_r($_POST)就消失了。好像表单根本没有发布。我通过谷歌搜索到达了 stackoverflow.com 页面。

是增加post_max_sizememory_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类型。这意味着我无法使用ini_set(&#39; max_input_vars&#39;,10000)更改我需要更高值的个人php页面的值;

答案 10 :(得分:0)

我面临同样的问题,我发现了一个非常有价值的解决方案,但没有增加.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>

希望理解。

答案 11 :(得分:0)

使用此功能获取真实数据

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;
}

答案 12 :(得分:0)

我遇到了类似的问题,并修改了MAX_INPUT_VARS以解决此问题。

值得检查您发送的内容和收到的内容。就我而言,AJAX调用包含除VAR_DUMP($ this-> input-> post())之外的所有值的格式化数组;显示缺失的值。

因此,最明显的答案是有人在这里说-max_input_vars。

答案 13 :(得分:0)

您需要更改php.ini文件的max_input_vars值

步骤1:找到php.ini文件
步骤1(a):打印php信息值以找出所有PHP预定义配置。

echo phpinfo(); //will print the php info values

步骤1(b):记录下一步中打印的phpinfo值中的php.ini文件位置,如下图所示 enter image description here

步骤2:。编辑php.ini文件。
步骤2(a):找到变量max_input_vars并删除其前的分号,然后将值设置为10000,如下所示:

max_input_vars = 10000

第3步:重新启动apache

sudo service apache2 restart