首页 文章

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

提问于
浏览
45

我有一个非常大的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数组?

编辑:要明确:不仅缺少 Value 观 . $ _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.缺少其余参数(e.x. t_dodparam2在post中,但它没有198这样的密钥,并且$ _POST中没有n_wartosc这样的密钥)

14 回答

  • 0

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

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

  • 29

    PHP修改包含字符空格,点,开方括号等的字段以与不推荐使用的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;
    }
    ?>
    
  • 0

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

    一些可能的原因:

    Suhosin

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

    ALERT - 超出配置的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(现在已被删除)的设置,它自动将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;
    }
    ?>
    
  • 10

    使用 "parse_str" 将查询字符串转换为php结构怎么样?这个函数与http_build_query相反 .

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

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

  • 0

    我发布了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 限制了它将打印多少个字符,除非你记得增加它 .

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

  • 1

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

  • 1

    遇到这个(不可否认的老)帖子,同时试图找到一个修复Javascript对象键的错误,包括名字中的方括号,然后PHP变得困惑,表现得像一个嵌套数组,也没有将值类型转换为布尔值/数字 - 因此我的版本(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;
    }
    
  • 0

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

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

    是增加 post_max_sizememory_limit 等没有解决任何问题 . 我有实际经验,增加 memory_limit 也可能是危险的 . 一旦我们的实时Apache托管服务器挂断了 . 我是实验者:-)

    max_input_vars 是唯一的限制因素 .

    echo ini_get('max_input_vars');
    

    显示它默认为1000 . 奇怪的是 max_input_varsphp.ini 中没有出现 . 无论如何,我补充道

    max_input_vars=10000
    

    在我的 php.ini 并重新启动Apache .

    现在 echo ini_get('max_input_vars'); 显示它已增加到 10000 并且我的大表格数据可能会在发布后被困 . 问题解决了 .

    我看到max_input_vars是PHP_INI_PERDIR类型 . 这意味着我无法使用ini_set('max_input_vars',10000)更改我需要更高值的个人php页面的值;

  • -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']将显示最后一个元素的值你形成的是空的 .

    TLDR:

    Make sure to check for duplicate field names in your form!

  • 29

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

    希望了解 .

  • 6

    使用此函数获取真实数据

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

    我有一个类似的问题,并修改MAX_INPUT_VARS修复它 .

    值得检查您发送的内容以及收到的内容 . 在我的例子中,AJAX调用包含所有值的格式化数组,但VAR_DUMP($ this-> input-> post());透露缺失值 .

    所以,显而易见的答案是有人在这里说 - max_input_vars .

  • 1

    htmlspecialchars 与$ _POST一起使用 . 例如:

    $day1=htmlspecialchars($_POST["day"]);
    

    我希望这会奏效 .

相关问题