private static $blockedAttributes = '#^(on\\w|srcdoc)#i'; private static function handleAttributes(&$matches) { if (preg_match(self::$blockedAttributes, $matches[1])) { return ''; } $value = html_entity_decode(str_replace(["\r", "\n", "\t"], '', $matches[3])); self::cleanAttributeValue($value); return $matches[1] . '="' . $value . '"'; } private static function cleanAttributeValue(&$value) { if (strpos($value, '&') === FALSE) { return; } $value = html_entity_decode($value); $value = preg_replace_callback('/&#x([\\da-f]{1,6})/i', 'self::chrFirstFromHex', $value); $value = preg_replace_callback('/&#(\\d+)/', 'self::chrFirstFromDec', $value); self::cleanNonPrinting($value); } private static function chrFirstFromHex(&$matches) { return chr(hexdec($matches[1])); } private static function chrFirstFromDec(&$matches) { return chr($matches[1]); } } XSS::setNonPrinting(); // run once