. * * PHP version 5.1.6+ * * @category Security * @package PHPIDS * @author Mario Heiderich * @author Christian Matthies * @author Lars Strojny * @license http://www.gnu.org/licenses/lgpl.html LGPL * @link http://php-ids.org/ */ namespace IDS; /** * PHPIDS report object * * The report objects collects a number of events and thereby presents the * detected results. It provides a convenient API to work with the results. * * Note that this class implements Countable, IteratorAggregate and * a __toString() method * * @category Security * @package PHPIDS * @author Christian Matthies * @author Mario Heiderich * @author Lars Strojny * @copyright 2007-2009 The PHPIDS Group * @license http://www.gnu.org/licenses/lgpl.html LGPL * @link http://php-ids.org/ */ class Report implements \Countable, \IteratorAggregate { /** * Event container * * @var Event[]|array */ protected $events = array(); /** * List of affected tags * * This list of tags is collected from the collected event objects on * demand when IDS_Report->getTags() is called * * @var string[]|array */ protected $tags = array(); /** * Impact level * * The impact level is calculated on demand by adding the results of the * event objects on IDS\Report->getImpact() * * @var integer */ protected $impact = 0; /** * Centrifuge data * * This variable - initiated as an empty array - carries all information * about the centrifuge data if available * * @var array */ protected $centrifuge = array(); /** * Constructor * * @param array $events the events the report should include * * @return Report */ public function __construct(array $events = null) { foreach ((array) $events as $event) { $this->addEvent($event); } } /** * Adds an IDS_Event object to the report * * @param Event $event IDS_Event * * @return self $this */ public function addEvent(Event $event) { $this->clear(); $this->events[$event->getName()] = $event; return $this; } /** * Get event by name * * In most cases an event is identified by the key of the variable that * contained maliciously appearing content * * @param string|integer $name the event name * * @throws \InvalidArgumentException if argument is invalid * @return Event|null IDS_Event object or false if the event does not exist */ public function getEvent($name) { if (!is_scalar($name)) { throw new \InvalidArgumentException('Invalid argument type given'); } return $this->hasEvent($name) ? $this->events[$name] : null; } /** * Returns list of events * * @return string[]|array */ public function getEvents() { return $this->events; } /** * Returns list of affected tags * * @return string[]|array */ public function getTags() { if (!$this->tags) { $this->tags = array(); foreach ($this->events as $event) { $this->tags = array_merge($this->tags, $event->getTags()); } $this->tags = array_values(array_unique($this->tags)); } return $this->tags; } /** * Returns total impact * * Each stored IDS_Event object and its IDS_Filter sub-object are called * to calculate the overall impact level of this request * * @return integer */ public function getImpact() { if (!$this->impact) { $this->impact = 0; foreach ($this->events as $event) { $this->impact += $event->getImpact(); } } return $this->impact; } /** * Checks if a specific event with given name exists * * @param string|integer $name the event name * * @throws \InvalidArgumentException if argument is illegal * @return boolean */ public function hasEvent($name) { if (!is_scalar($name)) { throw new \InvalidArgumentException('Invalid argument given'); } return isset($this->events[$name]); } /** * Returns total amount of events * * @return integer */ public function count() { return count($this->events); } /** * Return iterator object * * In order to provide the possibility to directly iterate over the * IDS_Event object the IteratorAggregate is implemented. One can easily * use foreach() to iterate through all stored IDS_Event objects. * * @return \Iterator the event collection */ public function getIterator() { return new \ArrayIterator($this->events); } /** * Checks if any events are registered * * @return boolean */ public function isEmpty() { return empty($this->events); } /** * Clears calculated/collected values * * @return void */ protected function clear() { $this->impact = 0; $this->tags = array(); } /** * This method returns the centrifuge property or null if not * filled with data * * @return array */ public function getCentrifuge() { return $this->centrifuge; } /** * This method sets the centrifuge property * * @param array $centrifuge the centrifuge data * * @throws \InvalidArgumentException if argument is illegal * @return void */ public function setCentrifuge(array $centrifuge = array()) { if (!$centrifuge) { throw new \InvalidArgumentException('Empty centrifuge given'); } $this->centrifuge = $centrifuge; } /** * Directly outputs all available information * * @return string */ public function __toString() { $output = ''; if (!$this->isEmpty()) { $output .= vsprintf( "Total impact: %d
\nAffected tags: %s
\n", array( $this->getImpact(), implode(', ', $this->getTags()) ) ); foreach ($this->events as $event) { $output .= vsprintf( "
\nVariable: %s | Value: %s
\nImpact: %d | Tags: %s
\n", array( htmlspecialchars($event->getName()), htmlspecialchars($event->getValue()), $event->getImpact(), implode(', ', $event->getTags()) ) ); foreach ($event as $filter) { $output .= vsprintf( "Description: %s | Tags: %s | ID %s
\n", array( $filter->getDescription(), implode(', ', $filter->getTags()), $filter->getId() ) ); } } $output .= '
'; if ($centrifuge = $this->getCentrifuge()) { $output .= vsprintf( "Centrifuge detection data
Threshold: %s
Ratio: %s", array( isset($centrifuge['threshold']) && $centrifuge['threshold'] ? $centrifuge['threshold'] : '---', isset($centrifuge['ratio']) && $centrifuge['ratio'] ? $centrifuge['ratio'] : '---' ) ); if (isset($centrifuge['converted'])) { $output .= '
Converted: ' . $centrifuge['converted']; } $output .= "

\n"; } } return $output; } }