From 52b617673ca9421bee1fa8e5b78e9df76cfd6bb5 Mon Sep 17 00:00:00 2001 From: Paul Nicholls Date: Wed, 28 Aug 2013 09:18:42 +1200 Subject: [PATCH] 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 cd48848b7d4..725aac7d219 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 @@ -282,6 +282,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.