From a74db1ddbb68d83f965a976b13ce69d71d8b4420 Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Sat, 17 Sep 2016 20:09:04 +0200 Subject: [PATCH] Add Pico::filterVariable() method This method can be used to validate and filter input data and can be called via `Pico::getUrlParameter()` (URL GET parameters) and `Pico::getFormParameter()` (HTTP POST parameters). `Pico::filterVariable()` is basically a wrapper for PHP's `filter_var()` function with various compatibility extensions to allow theme developers to use its functionality in Twig templates. Therefore Pico 1.1 adds the `url_param` (`Pico::getUrlParameter()`) and `form_param` (`Pico::getFormParameter()`) Twig functions. Resolves #305 --- lib/Pico.php | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/lib/Pico.php b/lib/Pico.php index 58b6de0..10abb8c 100644 --- a/lib/Pico.php +++ b/lib/Pico.php @@ -1321,8 +1321,10 @@ class Pico $this->twig->addExtension(new Twig_Extension_Debug()); $this->twig->addExtension(new PicoTwigExtension($this)); - // register link filter + // register link filter and the url_param and form_param functions $this->twig->addFilter(new Twig_SimpleFilter('link', array($this, 'getPageUrl'))); + $this->twig->addFunction(new Twig_SimpleFunction('url_param', array($this, 'getUrlParameter'))); + $this->twig->addFunction(new Twig_SimpleFunction('form_param', array($this, 'getFormParameter'))); // register content filter // we pass the $pages array by reference to prevent multiple parser runs for the same page @@ -1510,6 +1512,134 @@ class Pico return $this->config['theme_url']; } + /** + * Filters a URL GET parameter with a specified filter + * + * This method is just an alias for {@link Pico::filterVariable()}, see + * {@link Pico::filterVariable()} for a detailed description. It can be + * used in Twig templates by calling the `url_param` function. + * + * @see Pico::filterVariable() + * @param string $name name of the URL GET parameter + * to filter + * @param int|string $filter the filter to apply + * @param mixed|array $options either a associative options + * array to be used by the filter or a scalar default value + * @param int|string|int[]|string[] $flags flags and flag strings to + * be used by the filter + * @return mixed either the filtered data, + * FALSE if the filter fails, or NULL if the URL GET parameter doesn't + * exist and no default value is given + */ + public function getUrlParameter($name, $filter = '', $options = null, $flags = null) + { + $variable = (isset($_GET[$name]) && is_scalar($_GET[$name])) ? $_GET[$name] : null; + return $this->filterVariable($variable, $filter, $options, $flags); + } + + /** + * Filters a HTTP POST parameter with a specified filter + * + * This method is just an alias for {@link Pico::filterVariable()}, see + * {@link Pico::filterVariable()} for a detailed description. It can be + * used in Twig templates by calling the `form_param` function. + * + * @see Pico::filterVariable() + * @param string $name name of the HTTP POST + * parameter to filter + * @param int|string $filter the filter to apply + * @param mixed|array $options either a associative options + * array to be used by the filter or a scalar default value + * @param int|string|int[]|string[] $flags flags and flag strings to + * be used by the filter + * @return mixed either the filtered data, + * FALSE if the filter fails, or NULL if the HTTP POST parameter + * doesn't exist and no default value is given + */ + public function getFormParameter($name, $filter = '', $options = null, $flags = null) + { + $variable = (isset($_POST[$name]) && is_scalar($_POST[$name])) ? $_POST[$name] : null; + return $this->filterVariable($variable, $filter, $options, $flags); + } + + /** + * Filters a variable with a specified filter + * + * This method basically wraps around PHP's `filter_var()` function. It + * filters data by either validating or sanitizing it. This is especially + * useful when the data source contains unknown (or foreign) data, like + * user supplied input. Validation is used to validate or check if the data + * meets certain qualifications, but will not change the data itself. + * Sanitization will sanitize the data, so it may alter it by removing + * undesired characters. It doesn't actually validate the data! The + * behaviour of most filters can optionally be tweaked by flags. + * + * Heads up! Input validation is hard! Always validate your input data the + * most paranoid way you can imagine. Always prefer validation filters over + * sanitization filters; be very careful with sanitization filters, you + * might create cross-site scripting vulnerabilities! + * + * @see https://secure.php.net/manual/en/function.filter-var.php + * PHP's `filter_var()` function + * @see https://secure.php.net/manual/en/filter.filters.validate.php + * Validate filters + * @see https://secure.php.net/manual/en/filter.filters.sanitize.php + * Sanitize filters + * @param mixed $variable value to filter + * @param int|string $filter ID (int) or name (string) of + * the filter to apply; if omitted, the method will return FALSE + * @param mixed|array $options either a associative array + * of options to be used by the filter (e.g. `array('default' => 42)`), + * or a scalar default value that will be returned when the passed + * value is NULL (optional) + * @param int|string|int[]|string[] $flags either a bitwise disjunction + * of flags or a string with the significant part of a flag constant + * (the constant name is the result of "FILTER_FLAG_" and the given + * string in ASCII-only uppercase); you may also pass an array of flags + * and flag strings (optional) + * @return mixed with a validation filter, + * the method either returns the validated value or, provided that the + * value wasn't valid, the given default value or FALSE; with a + * sanitization filter, the method returns the sanitized value; if no + * value (i.e. NULL) was given, the method always returns either the + * provided default value or NULL + */ + protected function filterVariable($variable, $filter = '', $options = null, $flags = null) + { + $defaultValue = null; + if (is_array($options)) { + $defaultValue = isset($options['default']) ? $options['default'] : null; + } elseif ($options !== null) { + $defaultValue = $options; + $options = array('default' => $defaultValue); + } + + if ($variable === null) { + return $defaultValue; + } + + $filter = !empty($filter) ? (is_string($filter) ? filter_id($filter) : (int) $filter) : false; + if (!$filter) { + return false; + } + + $filterOptions = array('options' => $options, 'flags' => 0); + foreach ((array) $flags as $flag) { + if (is_numeric($flag)) { + $filterOptions['flags'] |= (int) $flag; + } elseif (is_string($flag)) { + $flag = strtoupper(preg_replace('/[^a-zA-Z0-9_]/', '', $flag)); + if (($flag === 'NULL_ON_FAILURE') && ($filter === FILTER_VALIDATE_BOOLEAN)) { + $filterOptions['flags'] |= FILTER_NULL_ON_FAILURE; + } else { + $filterOptions['flags'] |= (int) constant('FILTER_FLAG_' . $flag); + } + } + } + + return filter_var($variable, $filter, $filterOptions); + } + /** * Recursively walks through a directory and returns all containing files * matching the specified file extension