From 85b82a9c2fd12f4d997261302a823d2fd9f96097 Mon Sep 17 00:00:00 2001 From: Paul Nicholls Date: Wed, 28 Aug 2013 09:18:42 +1200 Subject: [PATCH 1/2] MDL-41451 - Large forms are truncated by max_input_vars By parsing php://input in chunks, we can bypass max_input_vars for forms which do not use the "multipart/form-data" enctype. This can be (and is) safely skipped if there are fewer than max_input_vars fields submitted as part of $_POST. --- lib/formslib.php | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/lib/formslib.php b/lib/formslib.php index a0db43a4174..8e9369d738a 100644 --- a/lib/formslib.php +++ b/lib/formslib.php @@ -261,10 +261,10 @@ abstract class moodleform { $submission = array(); if ($method == 'post') { if (!empty($_POST)) { - $submission = $_POST; + $submission = $this->_get_post_params(); } } else { - $submission = array_merge_recursive($_GET, $_POST); // emulate handling of parameters in xxxx_param() + $submission = array_merge_recursive($_GET, $this->_get_post_params()); // Emulate handling of parameters in xxxx_param(). } // following trick is needed to enable proper sesskey checks when using GET forms @@ -283,6 +283,38 @@ abstract class moodleform { $this->_form->updateSubmission($submission, $files); } + /** + * Internal method. Gets all POST variables, bypassing max_input_vars limit if needed. + * + * @return array All POST variables as an array, in the same format as $_POST. + */ + protected function _get_post_params() { + $enctype = $this->_form->getAttribute('enctype'); + $max = (int)ini_get('max_input_vars'); + + if (empty($max) || count($_POST, COUNT_RECURSIVE) < $max || (!empty($enctype) && $enctype == 'multipart/form-data')) { + return $_POST; + } + + // Large POST request with enctype supported by php://input. + // Parse php://input in chunks to bypass max_input_vars limit, which also applies to parse_str(). + $allvalues = array(); + $values = array(); + $str = file_get_contents("php://input"); + $delim = '&'; + + $chunks = array_map(function($p) use ($delim) { + return implode($delim, $p); + }, array_chunk(explode($delim, $str), $max)); + + foreach ($chunks as $chunk) { + parse_str($chunk, $values); + $allvalues = array_merge_recursive($allvalues, $values); + } + + return $allvalues; + } + /** * Internal method. Validates all old-style deprecated uploaded files. * The new way is to upload files via repository api. From 59de73509506d25c4f949afe714db92f32c0d124 Mon Sep 17 00:00:00 2001 From: Paul Nicholls Date: Mon, 9 Sep 2013 11:21:33 +1200 Subject: [PATCH 2/2] MDL-41451 - formslib: use create_function instead of inline function As per MDL-39432, closure-style inline functions can result in fatal errors when using eAccelerator and thus should be avoided. --- lib/formslib.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/formslib.php b/lib/formslib.php index 8e9369d738a..f282a3c8c3f 100644 --- a/lib/formslib.php +++ b/lib/formslib.php @@ -303,9 +303,8 @@ abstract class moodleform { $str = file_get_contents("php://input"); $delim = '&'; - $chunks = array_map(function($p) use ($delim) { - return implode($delim, $p); - }, array_chunk(explode($delim, $str), $max)); + $fun = create_function('$p', 'return implode("'.$delim.'", $p);'); + $chunks = array_map($fun, array_chunk(explode($delim, $str), $max)); foreach ($chunks as $chunk) { parse_str($chunk, $values);