_values = $values; if (isset($exceptionClass)) { $this->_exceptionClass = $exceptionClass; } } /** * Require parameters to be non-empty, and then check * them against provided filters. A convenience wrapper around * expect() and filter(). */ public function expectFiltered (array $filters) { $failures = array(); // first, did we get all the desired fields? try { $this->expect(array_keys($filters)); } catch (Exception $e) { $missing = $e->getErrors(); } // second, do they pass the provided filters? try { $this->filter($filters); } catch (Exception $e) { $invalid = $e->getErrors(); } if (isset($missing)) { foreach ($missing as $field => $val) $failures[$field] = $val; } if (isset($invalid)) { foreach ($invalid as $field => $val) $failures[$field] = $val; } if ($failures) { $e_class = $this->_exceptionClass; throw new $e_class($failures); } } /** * Require request parameters to be non-empty(). For example, in a * Controller action: * * $this->req()->expect('foo', 'bar'); * * @param mixed... array or variable length list of parameters to expect * @throws \SparkLib\Application\RequestException */ public function expect () { $args = func_get_args(); // DIRTY DIRTY HACK if (is_array($args[0])) $expectations = $args[0]; else $expectations = $args; // Check everything in requires to make sure we have a value $failures = $this->checkParams($expectations, $this->_values); if (count($failures) > 0) { $e_class = $this->_exceptionClass; throw new $e_class($failures); } } private function checkParams ($expectation, $value) { $failures = []; if (is_array($expectation)) { foreach ($expectation as $key => $expected) { $check = is_array($expected) ? $key : $expected; $fail = $this->checkParams($expected, $value[$check]); $failures = array_merge($failures, $fail); } } else if (!is_array($value) && !strlen(trim($value))) { $failures[$expectation] = 'missing'; } return $failures; } /** * Match request parameters against filters. * * $filters = array( * 'foo' => 'FILTER_VALIDATE_INT', * 'bar' => '/^[a-z]+$/', * 'baz' => function ($value) { * if ($value == 'barf') { * return false; * } * return true; * } * ); * $this->req()->filter($filters); * * A filter may be the name of a filter constant, a / delimited * PCRE expression, or an anonymous function which takes one parameter * and returns true to pass or false to fail. * * Like expect(), this will throw a \SparkLib\Application\RequestException if something * doesn't match, because programmers suck at checking error conditions and * I'd rather make failures obvious. Wrap it in a catch block if you want to * handle things more gracefully than a "Something broke". RequestException * provides getErrors(), which returns the array of validation errors. * * See also: http://www.php.net/manual/en/filter.filters.validate.php * * @param array filters to check against specific parameters * @throws \SparkLib\Application\RequestException */ public function filter (array $filters) { $failures = array(); // Check every param in the request against any defined filters foreach ($filters as $param => $filter) { // If we weren't given a value, don't filter it. // (If you want to mandate that the value is set, use expect() or expectFiltered()) // There is a special case here for the string '0', which empty() considers empty. // Let Lerdorf hope that I never encounter him in a dark alley. if (empty($this->_values[$param]) && ($this->_values[$param] !== '0')) { continue; } $errstring = 'invalid'; if (is_array($filter)) { $errstring = $filter[1]; $filter = $filter[0]; } if (is_string($filter)) { if ($filter[0] === '/') // treat the filter as a regexp { // fail if no match: if (! preg_match($filter, $this->_values[$param])) $failures[$param] = $errstring; } // treat the filter as a builtin filter elseif (filter_var($this->_values[$param], constant($filter)) === FALSE) { $failures[$param] = $errstring; } } elseif (is_callable($filter)) { // treat the filter as a callback if (! $filter($this->_values[$param])) $failures[$param] = $errstring; } } if (count($failures) > 0) { $e_class = $this->_exceptionClass; throw new $e_class($failures); } } }