array('href', 'title'), 'img' => array('src', 'alt', 'width', 'height', 'style'), ); private $parser; private $started; protected $out; function __construct() { $this->parser = xml_parser_create('utf-8'); xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false); xml_set_object($this->parser, $this); xml_set_element_handler($this->parser, 'startElement', 'endElement'); xml_set_character_data_handler($this->parser, 'characters'); } function __destruct() { xml_parser_free($this->parser); } public function parse($text) { if (xml_parse($this->parser, ''.$text.'') !== 1) { $code = xml_get_error_code($this->parser); throw new ParsingError(xml_error_string($code), $code, $this->parser); } return $this->out; } protected function startElement($parser, $name, $attrs) { if ($name == 'root') { $this->started = true; $this->out = ''; return; } if (!in_array($name, self::$allowedElements)) { throw new ParsingError("{$name} есть недопустимый элемент.", 0, $parser); } if (array_key_exists($name, self::$allowedAttributes)) { $allowedAttrs = self::$allowedAttributes[$name]; } else { $allowedAttrs = null; } $out = '<' . $name; foreach ($attrs as $attr => $value) { if (is_null($allowedAttrs) OR !in_array($attr, $allowedAttrs)) { throw new ParsingError("{$attr} есть недопустимый аттрибут для элемента {$name}.", 0, $parser); } $out .= ' ' . $attr . '="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '"'; } $out .= '>'; $this->out .= $out; } protected function endElement($parser, $name) { if ($name == 'root') { return; } $this->out .= ""; } protected function characters($parser, $data) { $this->out .= htmlspecialchars($data, ENT_NOQUOTES, 'UTF-8'); } } class ParsingError extends Exception { public $row; public $col; public function __construct($message, $code, $parser) { parent::__construct($message, $code); $this->col = xml_get_current_column_number($parser); $this->row = xml_get_current_line_number($parser); } } // test code below ?> </head> <body> <form action="test.php" method="post"> <p> <textarea name="test" cols="50" rows="25"><?php echo htmlspecialchars(@$_POST['test'], ENT_COMPAT, 'UTF-8'); ?></textarea> </p> <p> <button type="submit">Submit</button> </p> </form> <?php if (@$_POST['test']) { $o = new XSSFilter(); try { $text = $o->parse($_POST['test']); echo '<p>', $text, '</p>'; } catch (ParsingError $e) { echo '<h2>', htmlspecialchars($e->getMessage()), '</h2>'; echo "<p>Строка {$e->row}, столбец {$e->col}.</p>"; } } ?> </body> </html>