namespace Ice; /** * Filter component provides a set of commonly needed data filters. * * @package Ice/Filter * @category Security * @author Ice Team * @copyright (c) 2014-2023 Ice Team * @license http://iceframework.org/license */ class Filter { protected filters; /** * Adds a user-defined filter. * * @param string name * @param callable body * @return object Filter */ public function add(string! name, body) { if typeof body != "object" { throw new Exception("Filter must be an object"); } let this->filters[name] = body; return this; } /** * Sanitizes a value with a specified single or set of filters. * * @param mixed value * @param mixed filters * @return mixed */ public function sanitize(var value, var filters) { var filter; if typeof filters == "string" { let filters = explode("|", filters); } if typeof filters == "array" { for filter in filters { let value = this->doSanitize(value, filter); } } return value; } /** * Internal sanitize. * * @param mixed value * @param string filter * @return mixed */ protected function doSanitize(var value, string! filter) { var custom; // Try a user-defined filter first if fetch custom, this->filters[filter] { // If the filter is a closure we call it in the PHP userland if custom instanceof \Closure { return call_user_func_array(custom, [value]); } return custom->sanitize(value); } switch filter { case "cssmin": let custom = create_instance("Ice\\Filter\\Css"), this->filters["cssmin"] = custom; return custom->sanitize(value); case "jsmin": let custom = create_instance("Ice\\Filter\\Js"), this->filters["jsmin"] = custom; return custom->sanitize(value); case "camelize": return value->camelize(); case "uncamelize": return value->uncamelize(); case "human": // Replace CamelCase and under_scores to spaces return ucfirst(trim(str_replace("_", " ", strtolower(preg_replace("/(?<=\\w)(?=[A-Z])/", " $1", value))))); case "lower": return function_exists("mb_strtolower") ? mb_strtolower(value) : strtolower(value); case "upper": return function_exists("mb_strtoupper") ? mb_strtoupper(value) : strtoupper(value); case "alnum": return preg_replace("/[^a-z0-9]/i", "", value); case "alpha": return preg_replace("/[^a-z]/i", "", value); case "email": return filter_var(value, FILTER_SANITIZE_EMAIL); case "bool": case "boolean": return filter_var(value, FILTER_VALIDATE_BOOLEAN); case "float": return (double) filter_var(value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); case "int": case "integer": return (int) filter_var(value, FILTER_SANITIZE_NUMBER_INT); case "string": return filter_var(value, FILTER_UNSAFE_RAW); case "repeats": case "strip_repeats": // Remove repeating, more than 2 spaces to space, more than 3 br to 2 br, more than 3 the same char to 3 chars return preg_replace(["/[ ]{2,}/", "/((\\r\\n|\\n\\r|\\n|\\r){3,})/", "~(.?)\\1{3,}~"], [" ", PHP_EOL . PHP_EOL, "$1$1$1"], value); case "e": case "escape": case "strip_special": // Convert special characters to HTML entities return htmlspecialchars((string) value, ENT_QUOTES | ENT_HTML5); case "unescape": case "unstrip_special": return htmlspecialchars_decode(value, ENT_QUOTES | ENT_HTML5); default: throw new Exception(sprintf("Filter '%s' is not supported", filter)); } } }