diff --git a/lib/htmlpurifier/CREDITS b/lib/htmlpurifier/CREDITS
index c3e7bb8e2f8..7921b45af7d 100644
--- a/lib/htmlpurifier/CREDITS
+++ b/lib/htmlpurifier/CREDITS
@@ -5,3 +5,5 @@ Almost everything written by Edward Z. Yang (Ambush Commander). Lots of thanks
to the DevNetwork Community for their help (see docs/ref-devnetwork.html for
more details), Feyd especially (namely IPv6 and optimization). Thanks to RSnake
for letting me package his fantastic XSS cheatsheet for a smoketest.
+
+ vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier.auto.php b/lib/htmlpurifier/HTMLPurifier.auto.php
deleted file mode 100644
index cb6a84265dd..00000000000
--- a/lib/htmlpurifier/HTMLPurifier.auto.php
+++ /dev/null
@@ -1,9 +0,0 @@
-purify($html, $config);
-}
-
diff --git a/lib/htmlpurifier/HTMLPurifier.php b/lib/htmlpurifier/HTMLPurifier.php
index 17cb1f80b81..fff46788621 100644
--- a/lib/htmlpurifier/HTMLPurifier.php
+++ b/lib/htmlpurifier/HTMLPurifier.php
@@ -1,12 +1,11 @@
Warning:
-Currently this feature is very patchy and experimental, with lots of
-possible error messages not yet implemented. It will not cause any problems,
-but it may not help your users either. This directive has been available
-since 2.0.0.
-');
-
/**
* Facade that coordinates HTML Purifier's subsystems in order to purify HTML.
- *
- * @note There are several points in which configuration can be specified
+ *
+ * @note There are several points in which configuration can be specified
* for HTML Purifier. The precedence of these (from lowest to
* highest) is as follows:
* -# Instance: new HTMLPurifier($config)
* -# Invocation: purify($html, $config)
* These configurations are entirely independent of each other and
- * are *not* merged.
- *
- * @todo We need an easier way to inject strategies, it'll probably end
- * up getting done through config though.
+ * are *not* merged (this behavior may change in the future).
+ *
+ * @todo We need an easier way to inject strategies using the configuration
+ * object.
*/
class HTMLPurifier
{
-
- var $version = '2.1.5';
-
- var $config;
- var $filters = array();
-
- var $strategy, $generator;
-
+
+ /** Version of HTML Purifier */
+ public $version = '4.1.0';
+
+ /** Constant with version of HTML Purifier */
+ const VERSION = '4.1.0';
+
+ /** Global configuration object */
+ public $config;
+
+ /** Array of extra HTMLPurifier_Filter objects to run on HTML, for backwards compatibility */
+ private $filters = array();
+
+ /** Single instance of HTML Purifier */
+ private static $instance;
+
+ protected $strategy, $generator;
+
/**
* Resultant HTMLPurifier_Context of last run purification. Is an array
* of contexts if the last called method was purifyArray().
- * @public
*/
- var $context;
-
+ public $context;
+
/**
* Initializes the purifier.
* @param $config Optional HTMLPurifier_Config object for all instances of
@@ -105,26 +85,26 @@ class HTMLPurifier
* The parameter can also be any type that
* HTMLPurifier_Config::create() supports.
*/
- function HTMLPurifier($config = null) {
-
+ public function __construct($config = null) {
+
$this->config = HTMLPurifier_Config::create($config);
-
+
$this->strategy = new HTMLPurifier_Strategy_Core();
- $this->generator = new HTMLPurifier_Generator();
-
+
}
-
+
/**
* Adds a filter to process the output. First come first serve
* @param $filter HTMLPurifier_Filter object
*/
- function addFilter($filter) {
+ public function addFilter($filter) {
+ trigger_error('HTMLPurifier->addFilter() is deprecated, use configuration directives in the Filter namespace or Filter.Custom', E_USER_WARNING);
$this->filters[] = $filter;
}
-
+
/**
* Filters an HTML snippet/document to be XSS-free and standards-compliant.
- *
+ *
* @param $html String of HTML to purify
* @param $config HTMLPurifier_Config object for this operation, if omitted,
* defaults to the config object specified during this
@@ -132,44 +112,63 @@ class HTMLPurifier
* that HTMLPurifier_Config::create() supports.
* @return Purified HTML
*/
- function purify($html, $config = null) {
-
+ public function purify($html, $config = null) {
+
+ // :TODO: make the config merge in, instead of replace
$config = $config ? HTMLPurifier_Config::create($config) : $this->config;
-
+
// implementation is partially environment dependant, partially
// configuration dependant
$lexer = HTMLPurifier_Lexer::create($config);
-
+
$context = new HTMLPurifier_Context();
-
- // our friendly neighborhood generator, all primed with configuration too!
- $this->generator->generateFromTokens(array(), $config, $context);
+
+ // setup HTML generator
+ $this->generator = new HTMLPurifier_Generator($config, $context);
$context->register('Generator', $this->generator);
-
+
// set up global context variables
- if ($config->get('Core', 'CollectErrors')) {
+ if ($config->get('Core.CollectErrors')) {
// may get moved out if other facilities use it
$language_factory = HTMLPurifier_LanguageFactory::instance();
$language = $language_factory->create($config, $context);
$context->register('Locale', $language);
-
+
$error_collector = new HTMLPurifier_ErrorCollector($context);
$context->register('ErrorCollector', $error_collector);
}
-
+
// setup id_accumulator context, necessary due to the fact that
// AttrValidator can be called from many places
$id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context);
$context->register('IDAccumulator', $id_accumulator);
-
+
$html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context);
-
- for ($i = 0, $size = count($this->filters); $i < $size; $i++) {
- $html = $this->filters[$i]->preFilter($html, $config, $context);
+
+ // setup filters
+ $filter_flags = $config->getBatch('Filter');
+ $custom_filters = $filter_flags['Custom'];
+ unset($filter_flags['Custom']);
+ $filters = array();
+ foreach ($filter_flags as $filter => $flag) {
+ if (!$flag) continue;
+ if (strpos($filter, '.') !== false) continue;
+ $class = "HTMLPurifier_Filter_$filter";
+ $filters[] = new $class;
}
-
+ foreach ($custom_filters as $filter) {
+ // maybe "HTMLPurifier_Filter_$filter", but be consistent with AutoFormat
+ $filters[] = $filter;
+ }
+ $filters = array_merge($filters, $this->filters);
+ // maybe prepare(), but later
+
+ for ($i = 0, $filter_size = count($filters); $i < $filter_size; $i++) {
+ $html = $filters[$i]->preFilter($html, $config, $context);
+ }
+
// purified HTML
- $html =
+ $html =
$this->generator->generateFromTokens(
// list of tokens
$this->strategy->execute(
@@ -179,26 +178,25 @@ class HTMLPurifier
$html, $config, $context
),
$config, $context
- ),
- $config, $context
+ )
);
-
- for ($i = $size - 1; $i >= 0; $i--) {
- $html = $this->filters[$i]->postFilter($html, $config, $context);
+
+ for ($i = $filter_size - 1; $i >= 0; $i--) {
+ $html = $filters[$i]->postFilter($html, $config, $context);
}
-
+
$html = HTMLPurifier_Encoder::convertFromUTF8($html, $config, $context);
$this->context =& $context;
return $html;
}
-
+
/**
* Filters an array of HTML snippets
* @param $config Optional HTMLPurifier_Config object for this operation.
* See HTMLPurifier::purify() for more details.
* @return Array of purified HTML
*/
- function purifyArray($array_of_html, $config = null) {
+ public function purifyArray($array_of_html, $config = null) {
$context_array = array();
foreach ($array_of_html as $key => $html) {
$array_of_html[$key] = $this->purify($html, $config);
@@ -207,29 +205,33 @@ class HTMLPurifier
$this->context = $context_array;
return $array_of_html;
}
-
+
/**
* Singleton for enforcing just one HTML Purifier in your system
* @param $prototype Optional prototype HTMLPurifier instance to
- * overload singleton with.
+ * overload singleton with, or HTMLPurifier_Config
+ * instance to configure the generated version with.
*/
- function &instance($prototype = null) {
- static $htmlpurifier;
- if (!$htmlpurifier || $prototype) {
- if (is_a($prototype, 'HTMLPurifier')) {
- $htmlpurifier = $prototype;
+ public static function instance($prototype = null) {
+ if (!self::$instance || $prototype) {
+ if ($prototype instanceof HTMLPurifier) {
+ self::$instance = $prototype;
} elseif ($prototype) {
- $htmlpurifier = new HTMLPurifier($prototype);
+ self::$instance = new HTMLPurifier($prototype);
} else {
- $htmlpurifier = new HTMLPurifier();
+ self::$instance = new HTMLPurifier();
}
}
- return $htmlpurifier;
+ return self::$instance;
}
-
- function &getInstance($prototype = null) {
+
+ /**
+ * @note Backwards compatibility, see instance()
+ */
+ public static function getInstance($prototype = null) {
return HTMLPurifier::instance($prototype);
}
-
+
}
+// vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier.safe-includes.php b/lib/htmlpurifier/HTMLPurifier.safe-includes.php
new file mode 100644
index 00000000000..6402de04584
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier.safe-includes.php
@@ -0,0 +1,204 @@
+attr_collections as $coll_i => $coll) {
@@ -47,13 +45,13 @@ class HTMLPurifier_AttrCollections
$this->expandIdentifiers($this->info[$name], $attr_types);
}
}
-
+
/**
* Takes a reference to an attribute associative array and performs
* all inclusions specified by the zero index.
* @param &$attr Reference to attribute array
*/
- function performInclusions(&$attr) {
+ public function performInclusions(&$attr) {
if (!isset($attr[0])) return;
$merge = $attr[0];
$seen = array(); // recursion guard
@@ -74,25 +72,25 @@ class HTMLPurifier_AttrCollections
}
unset($attr[0]);
}
-
+
/**
* Expands all string identifiers in an attribute array by replacing
* them with the appropriate values inside HTMLPurifier_AttrTypes
* @param &$attr Reference to attribute array
* @param $attr_types HTMLPurifier_AttrTypes instance
*/
- function expandIdentifiers(&$attr, $attr_types) {
-
+ public function expandIdentifiers(&$attr, $attr_types) {
+
// because foreach will process new elements we add, make sure we
// skip duplicates
$processed = array();
-
+
foreach ($attr as $def_i => $def) {
// skip inclusions
if ($def_i === 0) continue;
-
+
if (isset($processed[$def_i])) continue;
-
+
// determine whether or not attribute is required
if ($required = (strpos($def_i, '*') !== false)) {
// rename the definition
@@ -100,21 +98,21 @@ class HTMLPurifier_AttrCollections
$def_i = trim($def_i, '*');
$attr[$def_i] = $def;
}
-
+
$processed[$def_i] = true;
-
+
// if we've already got a literal object, move on
if (is_object($def)) {
// preserve previous required
$attr[$def_i]->required = ($required || $attr[$def_i]->required);
continue;
}
-
+
if ($def === false) {
unset($attr[$def_i]);
continue;
}
-
+
if ($t = $attr_types->get($def)) {
$attr[$def_i] = $t;
$attr[$def_i]->required = $required;
@@ -122,8 +120,9 @@ class HTMLPurifier_AttrCollections
unset($attr[$def_i]);
}
}
-
+
}
-
+
}
+// vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/AttrDef.php b/lib/htmlpurifier/HTMLPurifier/AttrDef.php
index 5417270e647..d32fa62d6ad 100644
--- a/lib/htmlpurifier/HTMLPurifier/AttrDef.php
+++ b/lib/htmlpurifier/HTMLPurifier/AttrDef.php
@@ -2,90 +2,86 @@
/**
* Base class for all validating attribute definitions.
- *
+ *
* This family of classes forms the core for not only HTML attribute validation,
* but also any sort of string that needs to be validated or cleaned (which
- * means CSS properties and composite definitions are defined here too).
+ * means CSS properties and composite definitions are defined here too).
* Besides defining (through code) what precisely makes the string valid,
* subclasses are also responsible for cleaning the code if possible.
*/
-class HTMLPurifier_AttrDef
+abstract class HTMLPurifier_AttrDef
{
-
+
/**
* Tells us whether or not an HTML attribute is minimized. Has no
* meaning in other contexts.
*/
- var $minimized = false;
-
+ public $minimized = false;
+
/**
* Tells us whether or not an HTML attribute is required. Has no
* meaning in other contexts
*/
- var $required = false;
-
+ public $required = false;
+
/**
* Validates and cleans passed string according to a definition.
- *
- * @public
+ *
* @param $string String to be validated and cleaned.
* @param $config Mandatory HTMLPurifier_Config object.
* @param $context Mandatory HTMLPurifier_AttrContext object.
*/
- function validate($string, $config, &$context) {
- trigger_error('Cannot call abstract function', E_USER_ERROR);
- }
-
+ abstract public function validate($string, $config, $context);
+
/**
* Convenience method that parses a string as if it were CDATA.
- *
+ *
* This method process a string in the manner specified at
* %s where
- the url-encoded original URI should be inserted (sample:
- http://www.google.com/url?q=%s).
-
- Uses for this directive: -
-- This directive has been available since 1.3.0. -
-'); - -// disabling directives - -HTMLPurifier_ConfigSchema::define( - 'URI', 'Disable', false, 'bool', ' -- Disables all URIs in all forms. Not sure why you\'d want to do that - (after all, the Internet\'s founded on the notion of a hyperlink). - This directive has been available since 1.3.0. -
-'); -HTMLPurifier_ConfigSchema::defineAlias('Attr', 'DisableURI', 'URI', 'Disable'); - -HTMLPurifier_ConfigSchema::define( - 'URI', 'DisableResources', false, 'bool', ' -- Disables embedding resources, essentially meaning no pictures. You can - still link to them though. See %URI.DisableExternalResources for why - this might be a good idea. This directive has been available since 1.3.0. -
-'); - /** * Validates a URI as defined by RFC 3986. * @note Scheme-specific mechanics deferred to HTMLPurifier_URIScheme */ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef { - - var $parser; - var $embedsResource; - + + protected $parser; + protected $embedsResource; + /** * @param $embeds_resource_resource Does the URI here result in an extra HTTP request? */ - function HTMLPurifier_AttrDef_URI($embeds_resource = false) { + public function __construct($embeds_resource = false) { $this->parser = new HTMLPurifier_URIParser(); $this->embedsResource = (bool) $embeds_resource; } - - function validate($uri, $config, &$context) { - - if ($config->get('URI', 'Disable')) return false; - + + public function make($string) { + $embeds = (bool) $string; + return new HTMLPurifier_AttrDef_URI($embeds); + } + + public function validate($uri, $config, $context) { + + if ($config->get('URI.Disable')) return false; + $uri = $this->parseCDATA($uri); - + // parse the URI $uri = $this->parser->parse($uri); if ($uri === false) return false; - + // add embedded flag to context for validators - $context->register('EmbeddedURI', $this->embedsResource); - + $context->register('EmbeddedURI', $this->embedsResource); + $ok = false; do { - + // generic validation $result = $uri->validate($config, $context); if (!$result) break; - + // chained filtering - $uri_def =& $config->getDefinition('URI'); + $uri_def = $config->getDefinition('URI'); $result = $uri_def->filter($uri, $config, $context); if (!$result) break; - - // scheme-specific validation + + // scheme-specific validation $scheme_obj = $uri->getSchemeObj($config, $context); if (!$scheme_obj) break; if ($this->embedsResource && !$scheme_obj->browsable) break; $result = $scheme_obj->validate($uri, $config, $context); if (!$result) break; - + + // Post chained filtering + $result = $uri_def->postFilter($uri, $config, $context); + if (!$result) break; + // survived gauntlet $ok = true; - + } while (false); - + $context->destroy('EmbeddedURI'); if (!$ok) return false; - + // back to string - $result = $uri->toString(); - - // munge entire URI if necessary - if ( - !is_null($uri->host) && // indicator for authority - !empty($scheme_obj->browsable) && - !is_null($munge = $config->get('URI', 'Munge')) - ) { - $result = str_replace('%s', rawurlencode($result), $munge); - } - - return $result; - + return $uri->toString(); + } - + } - +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Email.php b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Email.php index ababd9eae07..bfee9d166c8 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Email.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Email.php @@ -1,18 +1,17 @@ " // that needs more percent encoding to be done if ($string == '') return false; @@ -17,6 +15,7 @@ class HTMLPurifier_AttrDef_URI_Email_SimpleCheck extends HTMLPurifier_AttrDef_UR $result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string); return $result ? $string : false; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php index 4812ad1d3dc..2156c10c660 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php @@ -1,31 +1,27 @@ ipv4 = new HTMLPurifier_AttrDef_URI_IPv4(); $this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6(); } - - function validate($string, $config, &$context) { + + public function validate($string, $config, $context) { $length = strlen($string); if ($string === '') return ''; if ($length > 1 && $string[0] === '[' && $string[$length-1] === ']') { @@ -35,17 +31,17 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef if ($valid === false) return false; return '['. $valid . ']'; } - + // need to do checks on unusual encodings too $ipv4 = $this->ipv4->validate($string, $config, $context); if ($ipv4 !== false) return $ipv4; - + // A regular domain name. - + // This breaks I18N domain names, but we don't have proper IRI support, - // so force users to insert Punycode. If there's complaining we'll + // so force users to insert Punycode. If there's complaining we'll // try to fix things into an international friendly form. - + // The productions describing this are: $a = '[a-z]'; // alpha $an = '[a-z0-9]'; // alphanum @@ -57,9 +53,10 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef // hostname = *( domainlabel "." ) toplabel [ "." ] $match = preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string); if (!$match) return false; - + return $string; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv4.php b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv4.php index 9a1af293bad..ec4cf591b82 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv4.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv4.php @@ -1,41 +1,39 @@ ip4) $this->_loadRegex(); - + if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) { return $aIP; } - + return false; - + } - + /** * Lazy load function to prevent regex from being stuffed in * cache. */ - function _loadRegex() { + protected function _loadRegex() { $oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255 $this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})"; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv6.php b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv6.php index f48b803dd7f..9454e9be50e 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv6.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrDef/URI/IPv6.php @@ -1,7 +1,5 @@ ip4) $this->_loadRegex(); - + $original = $aIP; - + $hex = '[0-9a-fA-F]'; $blk = '(?:' . $hex . '{1,4})'; $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128 - + // prefix check if (strpos($aIP, '/') !== false) { @@ -34,8 +32,8 @@ class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4 return false; } } - - // IPv4-compatiblity check + + // IPv4-compatiblity check if (preg_match('#(?<=:'.')' . $this->ip4 . '$#s', $aIP, $find)) { $aIP = substr($aIP, 0, 0-strlen($find[0])); @@ -44,7 +42,7 @@ class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4 $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3]; unset($find, $ip); } - + // compression check $aIP = explode('::', $aIP); $c = count($aIP); @@ -57,12 +55,12 @@ class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4 list($first, $second) = $aIP; $first = explode(':', $first); $second = explode(':', $second); - + if (count($first) + count($second) > 8) { return false; } - + while(count($first) < 8) { array_push($first, '0'); @@ -77,12 +75,12 @@ class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4 $aIP = explode(':', $aIP[0]); } $c = count($aIP); - + if ($c != 8) { return false; } - + // All the pieces should be 16-bit hex strings. Are they? foreach ($aIP as $piece) { @@ -91,10 +89,11 @@ class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4 return false; } } - + return $original; - + } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform.php index ce69fcbe82c..e61d3e01b6d 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrTransform.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform.php @@ -2,56 +2,55 @@ /** * Processes an entire attribute array for corrections needing multiple values. - * + * * Occasionally, a certain attribute will need to be removed and popped onto * another value. Instead of creating a complex return syntax for * HTMLPurifier_AttrDef, we just pass the whole attribute array to a * specialized object and have that do the special work. That is the * family of HTMLPurifier_AttrTransform. - * + * * An attribute transformation can be assigned to run before or after * HTMLPurifier_AttrDef validation. See HTMLPurifier_HTMLDefinition for * more details. */ -class HTMLPurifier_AttrTransform +abstract class HTMLPurifier_AttrTransform { - + /** * Abstract: makes changes to the attributes dependent on multiple values. - * + * * @param $attr Assoc array of attributes, usually from * HTMLPurifier_Token_Tag::$attr * @param $config Mandatory HTMLPurifier_Config object. * @param $context Mandatory HTMLPurifier_Context object * @returns Processed attribute array. */ - function transform($attr, $config, &$context) { - trigger_error('Cannot call abstract function', E_USER_ERROR); - } - + abstract public function transform($attr, $config, $context); + /** * Prepends CSS properties to the style attribute, creating the * attribute if it doesn't exist. * @param $attr Attribute array to process (passed by reference) * @param $css CSS to prepend */ - function prependCSS(&$attr, $css) { + public function prependCSS(&$attr, $css) { $attr['style'] = isset($attr['style']) ? $attr['style'] : ''; $attr['style'] = $css . $attr['style']; } - + /** * Retrieves and removes an attribute * @param $attr Attribute array to process (passed by reference) * @param $key Key of attribute to confiscate */ - function confiscateAttr(&$attr, $key) { + public function confiscateAttr(&$attr, $key) { if (!isset($attr[$key])) return null; $value = $attr[$key]; unset($attr[$key]); return $value; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/Background.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Background.php new file mode 100644 index 00000000000..0e1ff24a3ed --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Background.php @@ -0,0 +1,23 @@ +confiscateAttr($attr, 'background'); + // some validation should happen here + + $this->prependCSS($attr, "background-image:url($background);"); + + return $attr; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/BdoDir.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/BdoDir.php index f127feb2b29..4d1a05665e4 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrTransform/BdoDir.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/BdoDir.php @@ -1,30 +1,19 @@ get('Attr', 'DefaultTextDir'); + $attr['dir'] = $config->get('Attr.DefaultTextDir'); return $attr; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/BgColor.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/BgColor.php index de2867efdd6..ad3916bb967 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrTransform/BgColor.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/BgColor.php @@ -1,25 +1,23 @@ confiscateAttr($attr, 'bgcolor'); // some validation should happen here - + $this->prependCSS($attr, "background-color:$bgcolor;"); - + return $attr; - + } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/BoolToCSS.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/BoolToCSS.php index 25548eea7c9..51159b67157 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrTransform/BoolToCSS.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/BoolToCSS.php @@ -1,38 +1,36 @@ attr = $attr; $this->css = $css; } - - function transform($attr, $config, &$context) { + + public function transform($attr, $config, $context) { if (!isset($attr[$this->attr])) return $attr; unset($attr[$this->attr]); $this->prependCSS($attr, $this->css); return $attr; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/Border.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Border.php index 7da4f6a8041..476b0b079b1 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrTransform/Border.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Border.php @@ -1,19 +1,18 @@ confiscateAttr($attr, 'border'); // some validation should happen here $this->prependCSS($attr, "border:{$border_width}px solid;"); return $attr; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/EnumToCSS.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/EnumToCSS.php index 0470413dd48..2a5b4514ab4 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrTransform/EnumToCSS.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/EnumToCSS.php @@ -1,59 +1,58 @@ attr = $attr; $this->enumToCSS = $enum_to_css; $this->caseSensitive = (bool) $case_sensitive; } - - function transform($attr, $config, &$context) { - + + public function transform($attr, $config, $context) { + if (!isset($attr[$this->attr])) return $attr; - + $value = trim($attr[$this->attr]); unset($attr[$this->attr]); - + if (!$this->caseSensitive) $value = strtolower($value); - + if (!isset($this->enumToCSS[$value])) { return $attr; } - + $this->prependCSS($attr, $this->enumToCSS[$value]); - + return $attr; - + } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/ImgRequired.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/ImgRequired.php index d0428055381..7f0e4b7a59f 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrTransform/ImgRequired.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/ImgRequired.php @@ -1,24 +1,7 @@ get('Core', 'RemoveInvalidImg')) return $attr; - $attr['src'] = $config->get('Attr', 'DefaultInvalidImage'); + if ($config->get('Core.RemoveInvalidImg')) return $attr; + $attr['src'] = $config->get('Attr.DefaultInvalidImage'); $src = false; } - + if (!isset($attr['alt'])) { if ($src) { - $attr['alt'] = basename($attr['src']); + $alt = $config->get('Attr.DefaultImageAlt'); + if ($alt === null) { + // truncate if the alt is too long + $attr['alt'] = substr(basename($attr['src']),0,40); + } else { + $attr['alt'] = $alt; + } } else { - $attr['alt'] = $config->get('Attr', 'DefaultInvalidImageAlt'); + $attr['alt'] = $config->get('Attr.DefaultInvalidImageAlt'); } } - + return $attr; - + } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/ImgSpace.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/ImgSpace.php index 60d5edc781f..fd84c10c361 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrTransform/ImgSpace.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/ImgSpace.php @@ -1,46 +1,44 @@ array('left', 'right'), 'vspace' => array('top', 'bottom') ); - - function HTMLPurifier_AttrTransform_ImgSpace($attr) { + + public function __construct($attr) { $this->attr = $attr; if (!isset($this->css[$attr])) { trigger_error(htmlspecialchars($attr) . ' is not valid space attribute'); } } - - function transform($attr, $config, &$context) { - + + public function transform($attr, $config, $context) { + if (!isset($attr[$this->attr])) return $attr; - + $width = $this->confiscateAttr($attr, $this->attr); // some validation could happen here - + if (!isset($this->css[$this->attr])) return $attr; - + $style = ''; foreach ($this->css[$this->attr] as $suffix) { $property = "margin-$suffix"; $style .= "$property:{$width}px;"; } - + $this->prependCSS($attr, $style); - + return $attr; - + } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/Input.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Input.php new file mode 100644 index 00000000000..16829552d14 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Input.php @@ -0,0 +1,40 @@ +pixels = new HTMLPurifier_AttrDef_HTML_Pixels(); + } + + public function transform($attr, $config, $context) { + if (!isset($attr['type'])) $t = 'text'; + else $t = strtolower($attr['type']); + if (isset($attr['checked']) && $t !== 'radio' && $t !== 'checkbox') { + unset($attr['checked']); + } + if (isset($attr['maxlength']) && $t !== 'text' && $t !== 'password') { + unset($attr['maxlength']); + } + if (isset($attr['size']) && $t !== 'text' && $t !== 'password') { + $result = $this->pixels->validate($attr['size'], $config, $context); + if ($result === false) unset($attr['size']); + else $attr['size'] = $result; + } + if (isset($attr['src']) && $t !== 'image') { + unset($attr['src']); + } + if (!isset($attr['value']) && ($t === 'radio' || $t === 'checkbox')) { + $attr['value'] = ''; + } + return $attr; + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/Lang.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Lang.php index 899f5c8dc53..5869e7f8203 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrTransform/Lang.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Lang.php @@ -1,7 +1,5 @@ name = $name; $this->cssName = $css_name ? $css_name : $name; } - - function transform($attr, $config, &$context) { + + public function transform($attr, $config, $context) { if (!isset($attr[$this->name])) return $attr; $length = $this->confiscateAttr($attr, $this->name); if(ctype_digit($length)) $length .= 'px'; $this->prependCSS($attr, $this->cssName . ":$length;"); return $attr; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/Name.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Name.php index 248d0e02fee..15315bc7353 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrTransform/Name.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Name.php @@ -1,20 +1,21 @@ get('HTML.Attr.Name.UseCDATA')) return $attr; if (!isset($attr['name'])) return $attr; $id = $this->confiscateAttr($attr, 'name'); if ( isset($attr['id'])) return $attr; $attr['id'] = $id; return $attr; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/NameSync.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/NameSync.php new file mode 100644 index 00000000000..a95638c140e --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/NameSync.php @@ -0,0 +1,27 @@ +idDef = new HTMLPurifier_AttrDef_HTML_ID(); + } + + public function transform($attr, $config, $context) { + if (!isset($attr['name'])) return $attr; + $name = $attr['name']; + if (isset($attr['id']) && $attr['id'] === $name) return $attr; + $result = $this->idDef->validate($name, $config, $context); + if ($result === false) unset($attr['name']); + else $attr['name'] = $result; + return $attr; + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/SafeEmbed.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/SafeEmbed.php new file mode 100644 index 00000000000..4da449981fb --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/SafeEmbed.php @@ -0,0 +1,15 @@ +uri = new HTMLPurifier_AttrDef_URI(true); // embedded + } + + public function transform($attr, $config, $context) { + // If we add support for other objects, we'll need to alter the + // transforms. + switch ($attr['name']) { + // application/x-shockwave-flash + // Keep this synchronized with Injector/SafeObject.php + case 'allowScriptAccess': + $attr['value'] = 'never'; + break; + case 'allowNetworking': + $attr['value'] = 'internal'; + break; + case 'wmode': + $attr['value'] = 'window'; + break; + case 'movie': + case 'src': + $attr['name'] = "movie"; + $attr['value'] = $this->uri->validate($attr['value'], $config, $context); + break; + case 'flashvars': + // we're going to allow arbitrary inputs to the SWF, on + // the reasoning that it could only hack the SWF, not us. + break; + // add other cases to support other param name/value pairs + default: + $attr['name'] = $attr['value'] = null; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/ScriptRequired.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/ScriptRequired.php new file mode 100644 index 00000000000..4499050a22a --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/ScriptRequired.php @@ -0,0 +1,16 @@ + + */ +class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform +{ + public function transform($attr, $config, $context) { + if (!isset($attr['type'])) { + $attr['type'] = 'text/javascript'; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTransform/Textarea.php b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Textarea.php new file mode 100644 index 00000000000..81ac3488ba8 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/AttrTransform/Textarea.php @@ -0,0 +1,18 @@ + + */ +class HTMLPurifier_AttrTransform_Textarea extends HTMLPurifier_AttrTransform +{ + + public function transform($attr, $config, $context) { + // Calculated from Firefox + if (!isset($attr['cols'])) $attr['cols'] = '22'; + if (!isset($attr['rows'])) $attr['rows'] = '3'; + return $attr; + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrTypes.php b/lib/htmlpurifier/HTMLPurifier/AttrTypes.php index 93abb0d02b7..fc2ea4e5881 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrTypes.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrTypes.php @@ -1,18 +1,5 @@ info['Enum'] = new HTMLPurifier_AttrDef_Enum(); $this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool(); - + $this->info['CDATA'] = new HTMLPurifier_AttrDef_Text(); $this->info['ID'] = new HTMLPurifier_AttrDef_HTML_ID(); $this->info['Length'] = new HTMLPurifier_AttrDef_HTML_Length(); @@ -43,43 +29,49 @@ class HTMLPurifier_AttrTypes $this->info['URI'] = new HTMLPurifier_AttrDef_URI(); $this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang(); $this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color(); - + // unimplemented aliases $this->info['ContentType'] = new HTMLPurifier_AttrDef_Text(); - + $this->info['ContentTypes'] = new HTMLPurifier_AttrDef_Text(); + $this->info['Charsets'] = new HTMLPurifier_AttrDef_Text(); + $this->info['Character'] = new HTMLPurifier_AttrDef_Text(); + + // "proprietary" types + $this->info['Class'] = new HTMLPurifier_AttrDef_HTML_Class(); + // number is really a positive integer (one or more digits) // FIXME: ^^ not always, see start and value of list items $this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true); } - + /** * Retrieves a type * @param $type String type name * @return Object AttrDef for type */ - function get($type) { - + public function get($type) { + // determine if there is any extra info tacked on if (strpos($type, '#') !== false) list($type, $string) = explode('#', $type, 2); else $string = ''; - + if (!isset($this->info[$type])) { trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR); return; } - + return $this->info[$type]->make($string); - + } - + /** * Sets a new implementation for a type * @param $type String type name * @param $impl Object AttrDef for type */ - function set($type, $impl) { + public function set($type, $impl) { $this->info[$type] = $impl; } } - +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/AttrValidator.php b/lib/htmlpurifier/HTMLPurifier/AttrValidator.php index f020e0080e5..829a0f8f225 100644 --- a/lib/htmlpurifier/HTMLPurifier/AttrValidator.php +++ b/lib/htmlpurifier/HTMLPurifier/AttrValidator.php @@ -7,7 +7,7 @@ */ class HTMLPurifier_AttrValidator { - + /** * Validates the attributes of a token, returning a modified token * that has valid tokens @@ -18,57 +18,64 @@ class HTMLPurifier_AttrValidator * @param $config Instance of HTMLPurifier_Config * @param $context Instance of HTMLPurifier_Context */ - function validateToken(&$token, &$config, &$context) { - + public function validateToken(&$token, &$config, $context) { + $definition = $config->getHTMLDefinition(); $e =& $context->get('ErrorCollector', true); - + // initialize IDAccumulator if necessary $ok =& $context->get('IDAccumulator', true); if (!$ok) { $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); $context->register('IDAccumulator', $id_accumulator); } - + // initialize CurrentToken if necessary $current_token =& $context->get('CurrentToken', true); if (!$current_token) $context->register('CurrentToken', $token); - - if ($token->type !== 'start' && $token->type !== 'empty') return $token; - + + if ( + !$token instanceof HTMLPurifier_Token_Start && + !$token instanceof HTMLPurifier_Token_Empty + ) return $token; + // create alias to global definition array, see also $defs // DEFINITION CALL $d_defs = $definition->info_global_attr; - + // don't update token until the very end, to ensure an atomic update $attr = $token->attr; - + // do global transformations (pre) // nothing currently utilizes this foreach ($definition->info_attr_transform_pre as $transform) { $attr = $transform->transform($o = $attr, $config, $context); - if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + if ($e) { + if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } } - + // do local transformations only applicable to this element (pre) // ex.to
foreach ($definition->info[$token->name]->attr_transform_pre as $transform) { $attr = $transform->transform($o = $attr, $config, $context); - if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + if ($e) { + if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } } - + // create alias to this element's attribute definition array, see // also $d_defs (global attribute definition array) // DEFINITION CALL $defs = $definition->info[$token->name]->attr; - + $attr_key = false; $context->register('CurrentAttr', $attr_key); - + // iterate through all the attribute keypairs // Watch out for name collisions: $key has previously been used foreach ($attr as $attr_key => $value) { - + // call the definition if ( isset($defs[$attr_key]) ) { // there is a local definition defined @@ -95,54 +102,61 @@ class HTMLPurifier_AttrValidator // system never heard of the attribute? DELETE! $result = false; } - + // put the results into effect if ($result === false || $result === null) { // this is a generic error message that should replaced // with more specific ones when possible if ($e) $e->send(E_ERROR, 'AttrValidator: Attribute removed'); - + // remove the attribute unset($attr[$attr_key]); } elseif (is_string($result)) { // generally, if a substitution is happening, there // was some sort of implicit correction going on. We'll // delegate it to the attribute classes to say exactly what. - + // simple substitution $attr[$attr_key] = $result; + } else { + // nothing happens } - + // we'd also want slightly more complicated substitution // involving an array as the return value, // although we're not sure how colliding attributes would // resolve (certain ones would be completely overriden, // others would prepend themselves). } - + $context->destroy('CurrentAttr'); - + // post transforms - + // global (error reporting untested) foreach ($definition->info_attr_transform_post as $transform) { $attr = $transform->transform($o = $attr, $config, $context); - if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + if ($e) { + if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } } - + // local (error reporting untested) foreach ($definition->info[$token->name]->attr_transform_post as $transform) { $attr = $transform->transform($o = $attr, $config, $context); - if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + if ($e) { + if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } } - + $token->attr = $attr; - + // destroy CurrentToken if we made it ourselves if (!$current_token) $context->destroy('CurrentToken'); - + } - - + + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/Bootstrap.php b/lib/htmlpurifier/HTMLPurifier/Bootstrap.php new file mode 100644 index 00000000000..559f61a2320 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/Bootstrap.php @@ -0,0 +1,98 @@ + +if (!defined('PHP_EOL')) { + switch (strtoupper(substr(PHP_OS, 0, 3))) { + case 'WIN': + define('PHP_EOL', "\r\n"); + break; + case 'DAR': + define('PHP_EOL', "\r"); + break; + default: + define('PHP_EOL', "\n"); + } +} + +/** + * Bootstrap class that contains meta-functionality for HTML Purifier such as + * the autoload function. + * + * @note + * This class may be used without any other files from HTML Purifier. + */ +class HTMLPurifier_Bootstrap +{ + + /** + * Autoload function for HTML Purifier + * @param $class Class to load + */ + public static function autoload($class) { + $file = HTMLPurifier_Bootstrap::getPath($class); + if (!$file) return false; + require HTMLPURIFIER_PREFIX . '/' . $file; + return true; + } + + /** + * Returns the path for a specific class. + */ + public static function getPath($class) { + if (strncmp('HTMLPurifier', $class, 12) !== 0) return false; + // Custom implementations + if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) { + $code = str_replace('_', '-', substr($class, 22)); + $file = 'HTMLPurifier/Language/classes/' . $code . '.php'; + } else { + $file = str_replace('_', '/', $class) . '.php'; + } + if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) return false; + return $file; + } + + /** + * "Pre-registers" our autoloader on the SPL stack. + */ + public static function registerAutoload() { + $autoload = array('HTMLPurifier_Bootstrap', 'autoload'); + if ( ($funcs = spl_autoload_functions()) === false ) { + spl_autoload_register($autoload); + } elseif (function_exists('spl_autoload_unregister')) { + $compat = version_compare(PHP_VERSION, '5.1.2', '<=') && + version_compare(PHP_VERSION, '5.1.0', '>='); + foreach ($funcs as $func) { + if (is_array($func)) { + // :TRICKY: There are some compatibility issues and some + // places where we need to error out + $reflector = new ReflectionMethod($func[0], $func[1]); + if (!$reflector->isStatic()) { + throw new Exception(' + HTML Purifier autoloader registrar is not compatible + with non-static object methods due to PHP Bug #44144; + Please do not use HTMLPurifier.autoload.php (or any + file that includes this file); instead, place the code: + spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\')) + after your own autoloaders. + '); + } + // Suprisingly, spl_autoload_register supports the + // Class::staticMethod callback format, although call_user_func doesn't + if ($compat) $func = implode('::', $func); + } + spl_autoload_unregister($func); + } + spl_autoload_register($autoload); + foreach ($funcs as $func) spl_autoload_register($func); + } + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/CSSDefinition.php b/lib/htmlpurifier/HTMLPurifier/CSSDefinition.php index c90f5d91f49..6a2e6f56d99 100644 --- a/lib/htmlpurifier/HTMLPurifier/CSSDefinition.php +++ b/lib/htmlpurifier/HTMLPurifier/CSSDefinition.php @@ -1,79 +1,37 @@ - Revision identifier for your custom definition. See - %HTML.DefinitionRev for details. This directive has been available - since 2.0.0. -
-'); - -HTMLPurifier_ConfigSchema::define( - 'CSS', 'MaxImgLength', '1200px', 'string/null', ' -
- This parameter sets the maximum allowed length on img tags,
- effectively the width and height properties.
- Only absolute units of measurement (in, pt, pc, mm, cm) and pixels (px) are allowed. This is
- in place to prevent imagecrash attacks, disable with null at your own risk.
- This directive is similar to %HTML.MaxImgLength, and both should be
- concurrently edited, although there are
- subtle differences in the input format (the CSS max is a number with
- a unit).
-
Injectors)');
- $this->defineNamespace('AutoFormatParam', 'Configuration for customizing auto-formatting functionality');
- $this->defineNamespace('Output', 'Configuration relating to the generation of (X)HTML.');
- $this->defineNamespace('Cache', 'Configuration for DefinitionCache and related subclasses.');
- $this->defineNamespace('Test', 'Developer testing configuration for our unit tests.');
+ static protected $singleton;
+
+ public function __construct() {
+ $this->defaultPlist = new HTMLPurifier_PropertyList();
}
-
+
+ /**
+ * Unserializes the default ConfigSchema.
+ */
+ public static function makeFromSerial() {
+ return unserialize(file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema.ser'));
+ }
+
/**
* Retrieves an instance of the application-wide configuration definition.
- * @static
*/
- function &instance($prototype = null) {
- static $instance;
+ public static function instance($prototype = null) {
if ($prototype !== null) {
- $instance = $prototype;
- } elseif ($instance === null || $prototype === true) {
- $instance = new HTMLPurifier_ConfigSchema();
- $instance->initialize();
+ HTMLPurifier_ConfigSchema::$singleton = $prototype;
+ } elseif (HTMLPurifier_ConfigSchema::$singleton === null || $prototype === true) {
+ HTMLPurifier_ConfigSchema::$singleton = HTMLPurifier_ConfigSchema::makeFromSerial();
}
- return $instance;
+ return HTMLPurifier_ConfigSchema::$singleton;
}
-
+
/**
* Defines a directive for configuration
- * @static
- * @warning Will fail of directive's namespace is defined
+ * @warning Will fail of directive's namespace is defined.
+ * @warning This method's signature is slightly different from the legacy
+ * define() static method! Beware!
* @param $namespace Namespace the directive is in
* @param $name Key of directive
* @param $default Default value of directive
* @param $type Allowed type of the directive. See
* HTMLPurifier_DirectiveDef::$type for allowed values
- * @param $description Description of directive for documentation
+ * @param $allow_null Whether or not to allow null values
*/
- function define($namespace, $name, $default, $type, $description) {
- $def =& HTMLPurifier_ConfigSchema::instance();
-
- // basic sanity checks
- if (HTMLPURIFIER_SCHEMA_STRICT) {
- if (!isset($def->info[$namespace])) {
- trigger_error('Cannot define directive for undefined namespace',
- E_USER_ERROR);
- return;
- }
- if (!ctype_alnum($name)) {
- trigger_error('Directive name must be alphanumeric',
- E_USER_ERROR);
- return;
- }
- if (empty($description)) {
- trigger_error('Description must be non-empty',
- E_USER_ERROR);
- return;
- }
- }
-
- if (isset($def->info[$namespace][$name])) {
- // already defined
- if (
- $def->info[$namespace][$name]->type !== $type ||
- $def->defaults[$namespace][$name] !== $default
- ) {
- trigger_error('Inconsistent default or type, cannot redefine');
- return;
- }
- } else {
- // needs defining
-
- // process modifiers (OPTIMIZE!)
- $type_values = explode('/', $type, 2);
- $type = $type_values[0];
- $modifier = isset($type_values[1]) ? $type_values[1] : false;
- $allow_null = ($modifier === 'null');
-
- if (HTMLPURIFIER_SCHEMA_STRICT) {
- if (!isset($def->types[$type])) {
- trigger_error('Invalid type for configuration directive',
- E_USER_ERROR);
- return;
- }
- $default = $def->validate($default, $type, $allow_null);
- if ($def->isError($default)) {
- trigger_error('Default value does not match directive type',
- E_USER_ERROR);
- return;
- }
- }
-
- $def->info[$namespace][$name] =
- new HTMLPurifier_ConfigDef_Directive();
- $def->info[$namespace][$name]->type = $type;
- $def->info[$namespace][$name]->allow_null = $allow_null;
- $def->defaults[$namespace][$name] = $default;
- }
- if (!HTMLPURIFIER_SCHEMA_STRICT) return;
- $backtrace = debug_backtrace();
- $file = $def->mungeFilename($backtrace[0]['file']);
- $line = $backtrace[0]['line'];
- $def->info[$namespace][$name]->addDescription($file,$line,$description);
+ public function add($key, $default, $type, $allow_null) {
+ $obj = new stdclass();
+ $obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type];
+ if ($allow_null) $obj->allow_null = true;
+ $this->info[$key] = $obj;
+ $this->defaults[$key] = $default;
+ $this->defaultPlist->set($key, $default);
}
-
- /**
- * Defines a namespace for directives to be put into.
- * @static
- * @param $namespace Namespace's name
- * @param $description Description of the namespace
- */
- function defineNamespace($namespace, $description) {
- $def =& HTMLPurifier_ConfigSchema::instance();
- if (HTMLPURIFIER_SCHEMA_STRICT) {
- if (isset($def->info[$namespace])) {
- trigger_error('Cannot redefine namespace', E_USER_ERROR);
- return;
- }
- if (!ctype_alnum($namespace)) {
- trigger_error('Namespace name must be alphanumeric',
- E_USER_ERROR);
- return;
- }
- if (empty($description)) {
- trigger_error('Description must be non-empty',
- E_USER_ERROR);
- return;
- }
- }
- $def->info[$namespace] = array();
- $def->info_namespace[$namespace] = new HTMLPurifier_ConfigDef_Namespace();
- $def->info_namespace[$namespace]->description = $description;
- $def->defaults[$namespace] = array();
- }
-
+
/**
* Defines a directive value alias.
- *
+ *
* Directive value aliases are convenient for developers because it lets
* them set a directive to several values and get the same result.
- * @static
* @param $namespace Directive's namespace
* @param $name Name of Directive
- * @param $alias Name of aliased value
- * @param $real Value aliased value will be converted into
+ * @param $aliases Hash of aliased values to the real alias
*/
- function defineValueAliases($namespace, $name, $aliases) {
- $def =& HTMLPurifier_ConfigSchema::instance();
- if (HTMLPURIFIER_SCHEMA_STRICT && !isset($def->info[$namespace][$name])) {
- trigger_error('Cannot set value alias for non-existant directive',
- E_USER_ERROR);
- return;
+ public function addValueAliases($key, $aliases) {
+ if (!isset($this->info[$key]->aliases)) {
+ $this->info[$key]->aliases = array();
}
foreach ($aliases as $alias => $real) {
- if (HTMLPURIFIER_SCHEMA_STRICT) {
- if (!$def->info[$namespace][$name] !== true &&
- !isset($def->info[$namespace][$name]->allowed[$real])
- ) {
- trigger_error('Cannot define alias to value that is not allowed',
- E_USER_ERROR);
- return;
- }
- if (isset($def->info[$namespace][$name]->allowed[$alias])) {
- trigger_error('Cannot define alias over allowed value',
- E_USER_ERROR);
- return;
- }
- }
- $def->info[$namespace][$name]->aliases[$alias] = $real;
+ $this->info[$key]->aliases[$alias] = $real;
}
}
-
+
/**
* Defines a set of allowed values for a directive.
- * @static
+ * @warning This is slightly different from the corresponding static
+ * method definition.
* @param $namespace Namespace of directive
* @param $name Name of directive
- * @param $allowed_values Arraylist of allowed values
+ * @param $allowed Lookup array of allowed values
*/
- function defineAllowedValues($namespace, $name, $allowed_values) {
- $def =& HTMLPurifier_ConfigSchema::instance();
- if (HTMLPURIFIER_SCHEMA_STRICT && !isset($def->info[$namespace][$name])) {
- trigger_error('Cannot define allowed values for undefined directive',
- E_USER_ERROR);
- return;
- }
- $directive =& $def->info[$namespace][$name];
- $type = $directive->type;
- if (HTMLPURIFIER_SCHEMA_STRICT && $type != 'string' && $type != 'istring') {
- trigger_error('Cannot define allowed values for directive whose type is not string',
- E_USER_ERROR);
- return;
- }
- if ($directive->allowed === true) {
- $directive->allowed = array();
- }
- foreach ($allowed_values as $value) {
- $directive->allowed[$value] = true;
- }
- if (
- HTMLPURIFIER_SCHEMA_STRICT &&
- $def->defaults[$namespace][$name] !== null &&
- !isset($directive->allowed[$def->defaults[$namespace][$name]])
- ) {
- trigger_error('Default value must be in allowed range of variables',
- E_USER_ERROR);
- $directive->allowed = true; // undo undo!
- return;
- }
+ public function addAllowedValues($key, $allowed) {
+ $this->info[$key]->allowed = $allowed;
}
-
+
/**
* Defines a directive alias for backwards compatibility
- * @static
* @param $namespace
* @param $name Directive that will be aliased
* @param $new_namespace
* @param $new_name Directive that the alias will be to
*/
- function defineAlias($namespace, $name, $new_namespace, $new_name) {
- $def =& HTMLPurifier_ConfigSchema::instance();
- if (HTMLPURIFIER_SCHEMA_STRICT) {
- if (!isset($def->info[$namespace])) {
- trigger_error('Cannot define directive alias in undefined namespace',
- E_USER_ERROR);
- return;
- }
- if (!ctype_alnum($name)) {
- trigger_error('Directive name must be alphanumeric',
- E_USER_ERROR);
- return;
- }
- if (isset($def->info[$namespace][$name])) {
- trigger_error('Cannot define alias over directive',
- E_USER_ERROR);
- return;
- }
- if (!isset($def->info[$new_namespace][$new_name])) {
- trigger_error('Cannot define alias to undefined directive',
- E_USER_ERROR);
- return;
- }
- if ($def->info[$new_namespace][$new_name]->class == 'alias') {
- trigger_error('Cannot define alias to alias',
- E_USER_ERROR);
- return;
+ public function addAlias($key, $new_key) {
+ $obj = new stdclass;
+ $obj->key = $new_key;
+ $obj->isAlias = true;
+ $this->info[$key] = $obj;
+ }
+
+ /**
+ * Replaces any stdclass that only has the type property with type integer.
+ */
+ public function postProcess() {
+ foreach ($this->info as $key => $v) {
+ if (count((array) $v) == 1) {
+ $this->info[$key] = $v->type;
+ } elseif (count((array) $v) == 2 && isset($v->allow_null)) {
+ $this->info[$key] = -$v->type;
}
}
- $def->info[$namespace][$name] =
- new HTMLPurifier_ConfigDef_DirectiveAlias(
- $new_namespace, $new_name);
- $def->info[$new_namespace][$new_name]->directiveAliases[] = "$namespace.$name";
- }
-
- /**
- * Validate a variable according to type. Return null if invalid.
- */
- function validate($var, $type, $allow_null = false) {
- if (!isset($this->types[$type])) {
- trigger_error('Invalid type', E_USER_ERROR);
- return;
- }
- if ($allow_null && $var === null) return null;
- switch ($type) {
- case 'mixed':
- //if (is_string($var)) $var = unserialize($var);
- return $var;
- case 'istring':
- case 'string':
- case 'text': // no difference, just is longer/multiple line string
- case 'itext':
- if (!is_string($var)) break;
- if ($type === 'istring' || $type === 'itext') $var = strtolower($var);
- return $var;
- case 'int':
- if (is_string($var) && ctype_digit($var)) $var = (int) $var;
- elseif (!is_int($var)) break;
- return $var;
- case 'float':
- if (is_string($var) && is_numeric($var)) $var = (float) $var;
- elseif (!is_float($var)) break;
- return $var;
- case 'bool':
- if (is_int($var) && ($var === 0 || $var === 1)) {
- $var = (bool) $var;
- } elseif (is_string($var)) {
- if ($var == 'on' || $var == 'true' || $var == '1') {
- $var = true;
- } elseif ($var == 'off' || $var == 'false' || $var == '0') {
- $var = false;
- } else {
- break;
- }
- } elseif (!is_bool($var)) break;
- return $var;
- case 'list':
- case 'hash':
- case 'lookup':
- if (is_string($var)) {
- // special case: technically, this is an array with
- // a single empty string item, but having an empty
- // array is more intuitive
- if ($var == '') return array();
- if (strpos($var, "\n") === false && strpos($var, "\r") === false) {
- // simplistic string to array method that only works
- // for simple lists of tag names or alphanumeric characters
- $var = explode(',',$var);
- } else {
- $var = preg_split('/(,|[\n\r]+)/', $var);
- }
- // remove spaces
- foreach ($var as $i => $j) $var[$i] = trim($j);
- if ($type === 'hash') {
- // key:value,key2:value2
- $nvar = array();
- foreach ($var as $keypair) {
- $c = explode(':', $keypair, 2);
- if (!isset($c[1])) continue;
- $nvar[$c[0]] = $c[1];
- }
- $var = $nvar;
- }
- }
- if (!is_array($var)) break;
- $keys = array_keys($var);
- if ($keys === array_keys($keys)) {
- if ($type == 'list') return $var;
- elseif ($type == 'lookup') {
- $new = array();
- foreach ($var as $key) {
- $new[$key] = true;
- }
- return $new;
- } else break;
- }
- if ($type === 'lookup') {
- foreach ($var as $key => $value) {
- $var[$key] = true;
- }
- }
- return $var;
- }
- $error = new HTMLPurifier_Error();
- return $error;
- }
-
- /**
- * Takes an absolute path and munges it into a more manageable relative path
- */
- function mungeFilename($filename) {
- if (!HTMLPURIFIER_SCHEMA_STRICT) return $filename;
- $offset = strrpos($filename, 'HTMLPurifier');
- $filename = substr($filename, $offset);
- $filename = str_replace('\\', '/', $filename);
- return $filename;
- }
-
- /**
- * Checks if var is an HTMLPurifier_Error object
- */
- function isError($var) {
- if (!is_object($var)) return false;
- if (!is_a($var, 'HTMLPurifier_Error')) return false;
- return true;
}
+
}
-
+// vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php
new file mode 100644
index 00000000000..c05668a7060
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php
@@ -0,0 +1,44 @@
+directives as $d) {
+ $schema->add(
+ $d->id->key,
+ $d->default,
+ $d->type,
+ $d->typeAllowsNull
+ );
+ if ($d->allowed !== null) {
+ $schema->addAllowedValues(
+ $d->id->key,
+ $d->allowed
+ );
+ }
+ foreach ($d->aliases as $alias) {
+ $schema->addAlias(
+ $alias->key,
+ $d->id->key
+ );
+ }
+ if ($d->valueAliases !== null) {
+ $schema->addValueAliases(
+ $d->id->key,
+ $d->valueAliases
+ );
+ }
+ }
+ $schema->postProcess();
+ return $schema;
+ }
+
+}
+
+// vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Builder/Xml.php b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Builder/Xml.php
new file mode 100644
index 00000000000..244561a3726
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Builder/Xml.php
@@ -0,0 +1,106 @@
+startElement('div');
+
+ $purifier = HTMLPurifier::getInstance();
+ $html = $purifier->purify($html);
+ $this->writeAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
+ $this->writeRaw($html);
+
+ $this->endElement(); // div
+ }
+
+ protected function export($var) {
+ if ($var === array()) return 'array()';
+ return var_export($var, true);
+ }
+
+ public function build($interchange) {
+ // global access, only use as last resort
+ $this->interchange = $interchange;
+
+ $this->setIndent(true);
+ $this->startDocument('1.0', 'UTF-8');
+ $this->startElement('configdoc');
+ $this->writeElement('title', $interchange->name);
+
+ foreach ($interchange->directives as $directive) {
+ $this->buildDirective($directive);
+ }
+
+ if ($this->namespace) $this->endElement(); // namespace
+
+ $this->endElement(); // configdoc
+ $this->flush();
+ }
+
+ public function buildDirective($directive) {
+
+ // Kludge, although I suppose having a notion of a "root namespace"
+ // certainly makes things look nicer when documentation is built.
+ // Depends on things being sorted.
+ if (!$this->namespace || $this->namespace !== $directive->id->getRootNamespace()) {
+ if ($this->namespace) $this->endElement(); // namespace
+ $this->namespace = $directive->id->getRootNamespace();
+ $this->startElement('namespace');
+ $this->writeAttribute('id', $this->namespace);
+ $this->writeElement('name', $this->namespace);
+ }
+
+ $this->startElement('directive');
+ $this->writeAttribute('id', $directive->id->toString());
+
+ $this->writeElement('name', $directive->id->getDirective());
+
+ $this->startElement('aliases');
+ foreach ($directive->aliases as $alias) $this->writeElement('alias', $alias->toString());
+ $this->endElement(); // aliases
+
+ $this->startElement('constraints');
+ if ($directive->version) $this->writeElement('version', $directive->version);
+ $this->startElement('type');
+ if ($directive->typeAllowsNull) $this->writeAttribute('allow-null', 'yes');
+ $this->text($directive->type);
+ $this->endElement(); // type
+ if ($directive->allowed) {
+ $this->startElement('allowed');
+ foreach ($directive->allowed as $value => $x) $this->writeElement('value', $value);
+ $this->endElement(); // allowed
+ }
+ $this->writeElement('default', $this->export($directive->default));
+ $this->writeAttribute('xml:space', 'preserve');
+ if ($directive->external) {
+ $this->startElement('external');
+ foreach ($directive->external as $project) $this->writeElement('project', $project);
+ $this->endElement();
+ }
+ $this->endElement(); // constraints
+
+ if ($directive->deprecatedVersion) {
+ $this->startElement('deprecated');
+ $this->writeElement('version', $directive->deprecatedVersion);
+ $this->writeElement('use', $directive->deprecatedUse->toString());
+ $this->endElement(); // deprecated
+ }
+
+ $this->startElement('description');
+ $this->writeHTMLDiv($directive->description);
+ $this->endElement(); // description
+
+ $this->endElement(); // directive
+ }
+
+}
+
+// vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Exception.php b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Exception.php
new file mode 100644
index 00000000000..2671516c588
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Exception.php
@@ -0,0 +1,11 @@
+ array(directive info)
+ */
+ public $directives = array();
+
+ /**
+ * Adds a directive array to $directives
+ */
+ public function addDirective($directive) {
+ if (isset($this->directives[$i = $directive->id->toString()])) {
+ throw new HTMLPurifier_ConfigSchema_Exception("Cannot redefine directive '$i'");
+ }
+ $this->directives[$i] = $directive;
+ }
+
+ /**
+ * Convenience function to perform standard validation. Throws exception
+ * on failed validation.
+ */
+ public function validate() {
+ $validator = new HTMLPurifier_ConfigSchema_Validator();
+ return $validator->validate($this);
+ }
+
+}
+
+// vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Interchange/Directive.php b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Interchange/Directive.php
new file mode 100644
index 00000000000..ac8be0d9707
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Interchange/Directive.php
@@ -0,0 +1,77 @@
+ true).
+ * Null if all values are allowed.
+ */
+ public $allowed;
+
+ /**
+ * List of aliases for the directive,
+ * e.g. array(new HTMLPurifier_ConfigSchema_Interchange_Id('Ns', 'Dir'))).
+ */
+ public $aliases = array();
+
+ /**
+ * Hash of value aliases, e.g. array('alt' => 'real'). Null if value
+ * aliasing is disabled (necessary for non-scalar types).
+ */
+ public $valueAliases;
+
+ /**
+ * Version of HTML Purifier the directive was introduced, e.g. '1.3.1'.
+ * Null if the directive has always existed.
+ */
+ public $version;
+
+ /**
+ * ID of directive that supercedes this old directive, is an instance
+ * of HTMLPurifier_ConfigSchema_Interchange_Id. Null if not deprecated.
+ */
+ public $deprecatedUse;
+
+ /**
+ * Version of HTML Purifier this directive was deprecated. Null if not
+ * deprecated.
+ */
+ public $deprecatedVersion;
+
+ /**
+ * List of external projects this directive depends on, e.g. array('CSSTidy').
+ */
+ public $external = array();
+
+}
+
+// vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Interchange/Id.php b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Interchange/Id.php
new file mode 100644
index 00000000000..b9b3c6f5cfb
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Interchange/Id.php
@@ -0,0 +1,37 @@
+key = $key;
+ }
+
+ /**
+ * @warning This is NOT magic, to ensure that people don't abuse SPL and
+ * cause problems for PHP 5.0 support.
+ */
+ public function toString() {
+ return $this->key;
+ }
+
+ public function getRootNamespace() {
+ return substr($this->key, 0, strpos($this->key, "."));
+ }
+
+ public function getDirective() {
+ return substr($this->key, strpos($this->key, ".") + 1);
+ }
+
+ public static function make($id) {
+ return new HTMLPurifier_ConfigSchema_Interchange_Id($id);
+ }
+
+}
+
+// vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/InterchangeBuilder.php b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/InterchangeBuilder.php
new file mode 100644
index 00000000000..785b72ce8e9
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/InterchangeBuilder.php
@@ -0,0 +1,180 @@
+varParser = $varParser ? $varParser : new HTMLPurifier_VarParser_Native();
+ }
+
+ public static function buildFromDirectory($dir = null) {
+ $builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder();
+ $interchange = new HTMLPurifier_ConfigSchema_Interchange();
+ return $builder->buildDir($interchange, $dir);
+ }
+
+ public function buildDir($interchange, $dir = null) {
+ if (!$dir) $dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema';
+ if (file_exists($dir . '/info.ini')) {
+ $info = parse_ini_file($dir . '/info.ini');
+ $interchange->name = $info['name'];
+ }
+
+ $files = array();
+ $dh = opendir($dir);
+ while (false !== ($file = readdir($dh))) {
+ if (!$file || $file[0] == '.' || strrchr($file, '.') !== '.txt') {
+ continue;
+ }
+ $files[] = $file;
+ }
+ closedir($dh);
+
+ sort($files);
+ foreach ($files as $file) {
+ $this->buildFile($interchange, $dir . '/' . $file);
+ }
+
+ return $interchange;
+ }
+
+ public function buildFile($interchange, $file) {
+ $parser = new HTMLPurifier_StringHashParser();
+ $this->build(
+ $interchange,
+ new HTMLPurifier_StringHash( $parser->parseFile($file) )
+ );
+ }
+
+ /**
+ * Builds an interchange object based on a hash.
+ * @param $interchange HTMLPurifier_ConfigSchema_Interchange object to build
+ * @param $hash HTMLPurifier_ConfigSchema_StringHash source data
+ */
+ public function build($interchange, $hash) {
+ if (!$hash instanceof HTMLPurifier_StringHash) {
+ $hash = new HTMLPurifier_StringHash($hash);
+ }
+ if (!isset($hash['ID'])) {
+ throw new HTMLPurifier_ConfigSchema_Exception('Hash does not have any ID');
+ }
+ if (strpos($hash['ID'], '.') === false) {
+ if (count($hash) == 2 && isset($hash['DESCRIPTION'])) {
+ $hash->offsetGet('DESCRIPTION'); // prevent complaining
+ } else {
+ throw new HTMLPurifier_ConfigSchema_Exception('All directives must have a namespace');
+ }
+ } else {
+ $this->buildDirective($interchange, $hash);
+ }
+ $this->_findUnused($hash);
+ }
+
+ public function buildDirective($interchange, $hash) {
+ $directive = new HTMLPurifier_ConfigSchema_Interchange_Directive();
+
+ // These are required elements:
+ $directive->id = $this->id($hash->offsetGet('ID'));
+ $id = $directive->id->toString(); // convenience
+
+ if (isset($hash['TYPE'])) {
+ $type = explode('/', $hash->offsetGet('TYPE'));
+ if (isset($type[1])) $directive->typeAllowsNull = true;
+ $directive->type = $type[0];
+ } else {
+ throw new HTMLPurifier_ConfigSchema_Exception("TYPE in directive hash '$id' not defined");
+ }
+
+ if (isset($hash['DEFAULT'])) {
+ try {
+ $directive->default = $this->varParser->parse($hash->offsetGet('DEFAULT'), $directive->type, $directive->typeAllowsNull);
+ } catch (HTMLPurifier_VarParserException $e) {
+ throw new HTMLPurifier_ConfigSchema_Exception($e->getMessage() . " in DEFAULT in directive hash '$id'");
+ }
+ }
+
+ if (isset($hash['DESCRIPTION'])) {
+ $directive->description = $hash->offsetGet('DESCRIPTION');
+ }
+
+ if (isset($hash['ALLOWED'])) {
+ $directive->allowed = $this->lookup($this->evalArray($hash->offsetGet('ALLOWED')));
+ }
+
+ if (isset($hash['VALUE-ALIASES'])) {
+ $directive->valueAliases = $this->evalArray($hash->offsetGet('VALUE-ALIASES'));
+ }
+
+ if (isset($hash['ALIASES'])) {
+ $raw_aliases = trim($hash->offsetGet('ALIASES'));
+ $aliases = preg_split('/\s*,\s*/', $raw_aliases);
+ foreach ($aliases as $alias) {
+ $directive->aliases[] = $this->id($alias);
+ }
+ }
+
+ if (isset($hash['VERSION'])) {
+ $directive->version = $hash->offsetGet('VERSION');
+ }
+
+ if (isset($hash['DEPRECATED-USE'])) {
+ $directive->deprecatedUse = $this->id($hash->offsetGet('DEPRECATED-USE'));
+ }
+
+ if (isset($hash['DEPRECATED-VERSION'])) {
+ $directive->deprecatedVersion = $hash->offsetGet('DEPRECATED-VERSION');
+ }
+
+ if (isset($hash['EXTERNAL'])) {
+ $directive->external = preg_split('/\s*,\s*/', trim($hash->offsetGet('EXTERNAL')));
+ }
+
+ $interchange->addDirective($directive);
+ }
+
+ /**
+ * Evaluates an array PHP code string without array() wrapper
+ */
+ protected function evalArray($contents) {
+ return eval('return array('. $contents .');');
+ }
+
+ /**
+ * Converts an array list into a lookup array.
+ */
+ protected function lookup($array) {
+ $ret = array();
+ foreach ($array as $val) $ret[$val] = true;
+ return $ret;
+ }
+
+ /**
+ * Convenience function that creates an HTMLPurifier_ConfigSchema_Interchange_Id
+ * object based on a string Id.
+ */
+ protected function id($id) {
+ return HTMLPurifier_ConfigSchema_Interchange_Id::make($id);
+ }
+
+ /**
+ * Triggers errors for any unused keys passed in the hash; such keys
+ * may indicate typos, missing values, etc.
+ * @param $hash Instance of ConfigSchema_StringHash to check.
+ */
+ protected function _findUnused($hash) {
+ $accessed = $hash->getAccessed();
+ foreach ($hash as $k => $v) {
+ if (!isset($accessed[$k])) {
+ trigger_error("String hash key '$k' not used by builder", E_USER_NOTICE);
+ }
+ }
+ }
+
+}
+
+// vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Validator.php b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Validator.php
new file mode 100644
index 00000000000..f374f6a0225
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/Validator.php
@@ -0,0 +1,206 @@
+parser = new HTMLPurifier_VarParser();
+ }
+
+ /**
+ * Validates a fully-formed interchange object. Throws an
+ * HTMLPurifier_ConfigSchema_Exception if there's a problem.
+ */
+ public function validate($interchange) {
+ $this->interchange = $interchange;
+ $this->aliases = array();
+ // PHP is a bit lax with integer <=> string conversions in
+ // arrays, so we don't use the identical !== comparison
+ foreach ($interchange->directives as $i => $directive) {
+ $id = $directive->id->toString();
+ if ($i != $id) $this->error(false, "Integrity violation: key '$i' does not match internal id '$id'");
+ $this->validateDirective($directive);
+ }
+ return true;
+ }
+
+ /**
+ * Validates a HTMLPurifier_ConfigSchema_Interchange_Id object.
+ */
+ public function validateId($id) {
+ $id_string = $id->toString();
+ $this->context[] = "id '$id_string'";
+ if (!$id instanceof HTMLPurifier_ConfigSchema_Interchange_Id) {
+ // handled by InterchangeBuilder
+ $this->error(false, 'is not an instance of HTMLPurifier_ConfigSchema_Interchange_Id');
+ }
+ // keys are now unconstrained (we might want to narrow down to A-Za-z0-9.)
+ // we probably should check that it has at least one namespace
+ $this->with($id, 'key')
+ ->assertNotEmpty()
+ ->assertIsString(); // implicit assertIsString handled by InterchangeBuilder
+ array_pop($this->context);
+ }
+
+ /**
+ * Validates a HTMLPurifier_ConfigSchema_Interchange_Directive object.
+ */
+ public function validateDirective($d) {
+ $id = $d->id->toString();
+ $this->context[] = "directive '$id'";
+ $this->validateId($d->id);
+
+ $this->with($d, 'description')
+ ->assertNotEmpty();
+
+ // BEGIN - handled by InterchangeBuilder
+ $this->with($d, 'type')
+ ->assertNotEmpty();
+ $this->with($d, 'typeAllowsNull')
+ ->assertIsBool();
+ try {
+ // This also tests validity of $d->type
+ $this->parser->parse($d->default, $d->type, $d->typeAllowsNull);
+ } catch (HTMLPurifier_VarParserException $e) {
+ $this->error('default', 'had error: ' . $e->getMessage());
+ }
+ // END - handled by InterchangeBuilder
+
+ if (!is_null($d->allowed) || !empty($d->valueAliases)) {
+ // allowed and valueAliases require that we be dealing with
+ // strings, so check for that early.
+ $d_int = HTMLPurifier_VarParser::$types[$d->type];
+ if (!isset(HTMLPurifier_VarParser::$stringTypes[$d_int])) {
+ $this->error('type', 'must be a string type when used with allowed or value aliases');
+ }
+ }
+
+ $this->validateDirectiveAllowed($d);
+ $this->validateDirectiveValueAliases($d);
+ $this->validateDirectiveAliases($d);
+
+ array_pop($this->context);
+ }
+
+ /**
+ * Extra validation if $allowed member variable of
+ * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
+ */
+ public function validateDirectiveAllowed($d) {
+ if (is_null($d->allowed)) return;
+ $this->with($d, 'allowed')
+ ->assertNotEmpty()
+ ->assertIsLookup(); // handled by InterchangeBuilder
+ if (is_string($d->default) && !isset($d->allowed[$d->default])) {
+ $this->error('default', 'must be an allowed value');
+ }
+ $this->context[] = 'allowed';
+ foreach ($d->allowed as $val => $x) {
+ if (!is_string($val)) $this->error("value $val", 'must be a string');
+ }
+ array_pop($this->context);
+ }
+
+ /**
+ * Extra validation if $valueAliases member variable of
+ * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
+ */
+ public function validateDirectiveValueAliases($d) {
+ if (is_null($d->valueAliases)) return;
+ $this->with($d, 'valueAliases')
+ ->assertIsArray(); // handled by InterchangeBuilder
+ $this->context[] = 'valueAliases';
+ foreach ($d->valueAliases as $alias => $real) {
+ if (!is_string($alias)) $this->error("alias $alias", 'must be a string');
+ if (!is_string($real)) $this->error("alias target $real from alias '$alias'", 'must be a string');
+ if ($alias === $real) {
+ $this->error("alias '$alias'", "must not be an alias to itself");
+ }
+ }
+ if (!is_null($d->allowed)) {
+ foreach ($d->valueAliases as $alias => $real) {
+ if (isset($d->allowed[$alias])) {
+ $this->error("alias '$alias'", 'must not be an allowed value');
+ } elseif (!isset($d->allowed[$real])) {
+ $this->error("alias '$alias'", 'must be an alias to an allowed value');
+ }
+ }
+ }
+ array_pop($this->context);
+ }
+
+ /**
+ * Extra validation if $aliases member variable of
+ * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
+ */
+ public function validateDirectiveAliases($d) {
+ $this->with($d, 'aliases')
+ ->assertIsArray(); // handled by InterchangeBuilder
+ $this->context[] = 'aliases';
+ foreach ($d->aliases as $alias) {
+ $this->validateId($alias);
+ $s = $alias->toString();
+ if (isset($this->interchange->directives[$s])) {
+ $this->error("alias '$s'", 'collides with another directive');
+ }
+ if (isset($this->aliases[$s])) {
+ $other_directive = $this->aliases[$s];
+ $this->error("alias '$s'", "collides with alias for directive '$other_directive'");
+ }
+ $this->aliases[$s] = $d->id->toString();
+ }
+ array_pop($this->context);
+ }
+
+ // protected helper functions
+
+ /**
+ * Convenience function for generating HTMLPurifier_ConfigSchema_ValidatorAtom
+ * for validating simple member variables of objects.
+ */
+ protected function with($obj, $member) {
+ return new HTMLPurifier_ConfigSchema_ValidatorAtom($this->getFormattedContext(), $obj, $member);
+ }
+
+ /**
+ * Emits an error, providing helpful context.
+ */
+ protected function error($target, $msg) {
+ if ($target !== false) $prefix = ucfirst($target) . ' in ' . $this->getFormattedContext();
+ else $prefix = ucfirst($this->getFormattedContext());
+ throw new HTMLPurifier_ConfigSchema_Exception(trim($prefix . ' ' . $msg));
+ }
+
+ /**
+ * Returns a formatted context string.
+ */
+ protected function getFormattedContext() {
+ return implode(' in ', array_reverse($this->context));
+ }
+
+}
+
+// vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/ValidatorAtom.php b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/ValidatorAtom.php
new file mode 100644
index 00000000000..b95aea18cc7
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/ValidatorAtom.php
@@ -0,0 +1,66 @@
+context = $context;
+ $this->obj = $obj;
+ $this->member = $member;
+ $this->contents =& $obj->$member;
+ }
+
+ public function assertIsString() {
+ if (!is_string($this->contents)) $this->error('must be a string');
+ return $this;
+ }
+
+ public function assertIsBool() {
+ if (!is_bool($this->contents)) $this->error('must be a boolean');
+ return $this;
+ }
+
+ public function assertIsArray() {
+ if (!is_array($this->contents)) $this->error('must be an array');
+ return $this;
+ }
+
+ public function assertNotNull() {
+ if ($this->contents === null) $this->error('must not be null');
+ return $this;
+ }
+
+ public function assertAlnum() {
+ $this->assertIsString();
+ if (!ctype_alnum($this->contents)) $this->error('must be alphanumeric');
+ return $this;
+ }
+
+ public function assertNotEmpty() {
+ if (empty($this->contents)) $this->error('must not be empty');
+ return $this;
+ }
+
+ public function assertIsLookup() {
+ $this->assertIsArray();
+ foreach ($this->contents as $v) {
+ if ($v !== true) $this->error('must be a lookup array');
+ }
+ return $this;
+ }
+
+ protected function error($msg) {
+ throw new HTMLPurifier_ConfigSchema_Exception(ucfirst($this->member) . ' in ' . $this->context . ' ' . $msg);
+ }
+
+}
+
+// vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema.ser b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema.ser
new file mode 100644
index 00000000000..22b8d54a59f
Binary files /dev/null and b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema.ser differ
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt
new file mode 100644
index 00000000000..0517fed0a11
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt
@@ -0,0 +1,8 @@
+Attr.AllowedClasses
+TYPE: lookup/null
+VERSION: 4.0.0
+DEFAULT: null
+--DESCRIPTION--
+List of allowed class values in the class attribute. By default, this is null,
+which means all classes are allowed.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt
new file mode 100644
index 00000000000..249edd647b0
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt
@@ -0,0 +1,12 @@
+Attr.AllowedFrameTargets
+TYPE: lookup
+DEFAULT: array()
+--DESCRIPTION--
+Lookup table of all allowed link frame targets. Some commonly used link
+targets include _blank, _self, _parent and _top. Values should be
+lowercase, as validation will be done in a case-sensitive manner despite
+W3C's recommendation. XHTML 1.0 Strict does not permit the target attribute
+so this directive will have no effect in that doctype. XHTML 1.1 does not
+enable the Target module by default, you will have to manually enable it
+(see the module documentation for more details.)
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt
new file mode 100644
index 00000000000..9a8fa6a2e20
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt
@@ -0,0 +1,9 @@
+Attr.AllowedRel
+TYPE: lookup
+VERSION: 1.6.0
+DEFAULT: array()
+--DESCRIPTION--
+List of allowed forward document relationships in the rel attribute. Common
+values may be nofollow or print. By default, this is empty, meaning that no
+document relationships are allowed.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt
new file mode 100644
index 00000000000..b0178834859
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt
@@ -0,0 +1,9 @@
+Attr.AllowedRev
+TYPE: lookup
+VERSION: 1.6.0
+DEFAULT: array()
+--DESCRIPTION--
+List of allowed reverse document relationships in the rev attribute. This
+attribute is a bit of an edge-case; if you don't know what it is for, stay
+away.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt
new file mode 100644
index 00000000000..e774b823b1b
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt
@@ -0,0 +1,19 @@
+Attr.ClassUseCDATA
+TYPE: bool/null
+DEFAULT: null
+VERSION: 4.0.0
+--DESCRIPTION--
+If null, class will auto-detect the doctype and, if matching XHTML 1.1 or
+XHTML 2.0, will use the restrictive NMTOKENS specification of class. Otherwise,
+it will use a relaxed CDATA definition. If true, the relaxed CDATA definition
+is forced; if false, the NMTOKENS definition is forced. To get behavior
+of HTML Purifier prior to 4.0.0, set this directive to false.
+
+Some rational behind the auto-detection:
+in previous versions of HTML Purifier, it was assumed that the form of
+class was NMTOKENS, as specified by the XHTML Modularization (representing
+XHTML 1.1 and XHTML 2.0). The DTDs for HTML 4.01 and XHTML 1.0, however
+specify class as CDATA. HTML 5 effectively defines it as CDATA, but
+with the additional constraint that each name should be unique (this is not
+explicitly outlined in previous specifications).
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt
new file mode 100644
index 00000000000..533165e1759
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt
@@ -0,0 +1,11 @@
+Attr.DefaultImageAlt
+TYPE: string/null
+DEFAULT: null
+VERSION: 3.2.0
+--DESCRIPTION--
+This is the content of the alt tag of an image if the user had not
+previously specified an alt attribute. This applies to all images without
+a valid alt attribute, as opposed to %Attr.DefaultInvalidImageAlt, which
+only applies to invalid images, and overrides in the case of an invalid image.
+Default behavior with null is to use the basename of the src tag for the alt.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt
new file mode 100644
index 00000000000..9eb7e38469f
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt
@@ -0,0 +1,9 @@
+Attr.DefaultInvalidImage
+TYPE: string
+DEFAULT: ''
+--DESCRIPTION--
+This is the default image an img tag will be pointed to if it does not have
+a valid src attribute. In future versions, we may allow the image tag to
+be removed completely, but due to design issues, this is not possible right
+now.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt
new file mode 100644
index 00000000000..2f17bf477a3
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt
@@ -0,0 +1,8 @@
+Attr.DefaultInvalidImageAlt
+TYPE: string
+DEFAULT: 'Invalid image'
+--DESCRIPTION--
+This is the content of the alt tag of an invalid image if the user had not
+previously specified an alt attribute. It has no effect when the image is
+valid but there was no alt attribute present.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt
new file mode 100644
index 00000000000..52654b53ae3
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt
@@ -0,0 +1,10 @@
+Attr.DefaultTextDir
+TYPE: string
+DEFAULT: 'ltr'
+--DESCRIPTION--
+Defines the default text direction (ltr or rtl) of the document being
+parsed. This generally is the same as the value of the dir attribute in
+HTML, or ltr if that is not specified.
+--ALLOWED--
+'ltr', 'rtl'
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt
new file mode 100644
index 00000000000..6440d210321
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt
@@ -0,0 +1,16 @@
+Attr.EnableID
+TYPE: bool
+DEFAULT: false
+VERSION: 1.2.0
+--DESCRIPTION--
+Allows the ID attribute in HTML. This is disabled by default due to the
+fact that without proper configuration user input can easily break the
+validation of a webpage by specifying an ID that is already on the
+surrounding HTML. If you don't mind throwing caution to the wind, enable
+this directive, but I strongly recommend you also consider blacklisting IDs
+you use (%Attr.IDBlacklist) or prefixing all user supplied IDs
+(%Attr.IDPrefix). When set to true HTML Purifier reverts to the behavior of
+pre-1.2.0 versions.
+--ALIASES--
+HTML.EnableAttrID
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt
new file mode 100644
index 00000000000..f31d226f58b
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt
@@ -0,0 +1,8 @@
+Attr.ForbiddenClasses
+TYPE: lookup
+VERSION: 4.0.0
+DEFAULT: array()
+--DESCRIPTION--
+List of forbidden class values in the class attribute. By default, this is
+empty, which means that no classes are forbidden. See also %Attr.AllowedClasses.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt
new file mode 100644
index 00000000000..5f2b5e3d2cd
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt
@@ -0,0 +1,5 @@
+Attr.IDBlacklist
+TYPE: list
+DEFAULT: array()
+DESCRIPTION: Array of IDs not allowed in the document.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt
new file mode 100644
index 00000000000..6f5824586ec
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt
@@ -0,0 +1,9 @@
+Attr.IDBlacklistRegexp
+TYPE: string/null
+VERSION: 1.6.0
+DEFAULT: NULL
+--DESCRIPTION--
+PCRE regular expression to be matched against all IDs. If the expression is
+matches, the ID is rejected. Use this with care: may cause significant
+degradation. ID matching is done after all other validation.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt
new file mode 100644
index 00000000000..cc49d43fd0c
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt
@@ -0,0 +1,12 @@
+Attr.IDPrefix
+TYPE: string
+VERSION: 1.2.0
+DEFAULT: ''
+--DESCRIPTION--
+String to prefix to IDs. If you have no idea what IDs your pages may use,
+you may opt to simply add a prefix to all user-submitted ID attributes so
+that they are still usable, but will not conflict with core page IDs.
+Example: setting the directive to 'user_' will result in a user submitted
+'foo' to become 'user_foo' Be sure to set %HTML.EnableAttrID to true
+before using this.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt
new file mode 100644
index 00000000000..2c5924a7ade
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt
@@ -0,0 +1,14 @@
+Attr.IDPrefixLocal
+TYPE: string
+VERSION: 1.2.0
+DEFAULT: ''
+--DESCRIPTION--
+Temporary prefix for IDs used in conjunction with %Attr.IDPrefix. If you
+need to allow multiple sets of user content on web page, you may need to
+have a seperate prefix that changes with each iteration. This way,
+seperately submitted user content displayed on the same page doesn't
+clobber each other. Ideal values are unique identifiers for the content it
+represents (i.e. the id of the row in the database). Be sure to add a
+seperator (like an underscore) at the end. Warning: this directive will
+not work unless %Attr.IDPrefix is set to a non-empty value!
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt
new file mode 100644
index 00000000000..d5caa1bb978
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt
@@ -0,0 +1,31 @@
+AutoFormat.AutoParagraph
+TYPE: bool
+VERSION: 2.0.1
+DEFAULT: false
+--DESCRIPTION--
+
++ This directive turns on auto-paragraphing, where double newlines are + converted in to paragraphs whenever possible. Auto-paragraphing: +
+
+ p tags must be allowed for this directive to take effect.
+ We do not use br tags for paragraphing, as that is
+ semantically incorrect.
+
+ To prevent auto-paragraphing as a content-producer, refrain from using
+ double-newlines except to specify a new paragraph or in contexts where
+ it has special meaning (whitespace usually has no meaning except in
+ tags like pre, so this should not be difficult.) To prevent
+ the paragraphing of inline text adjacent to block elements, wrap them
+ in div tags (the behavior is slightly different outside of
+ the root node.)
+
+ This directive can be used to add custom auto-format injectors. + Specify an array of injector names (class name minus the prefix) + or concrete implementations. Injector class must exist. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt new file mode 100644 index 00000000000..663064a3447 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt @@ -0,0 +1,11 @@ +AutoFormat.DisplayLinkURI +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- ++ This directive turns on the in-text display of URIs in <a> tags, and disables + those links. For example, example becomes + example (http://example.com). +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt new file mode 100644 index 00000000000..3a48ba960e9 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt @@ -0,0 +1,12 @@ +AutoFormat.Linkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +
+ This directive turns on linkification, auto-linking http, ftp and
+ https URLs. a tags with the href attribute
+ must be allowed.
+
+ Location of configuration documentation to link to, let %s substitute + into the configuration's namespace and directive names sans the percent + sign. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt new file mode 100644 index 00000000000..7996488be0d --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt @@ -0,0 +1,12 @@ +AutoFormat.PurifierLinkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +
+ Internal auto-formatter that converts configuration directives in
+ syntax %Namespace.Directive to links. a tags
+ with the href attribute must be allowed.
+
+ When %AutoFormat.RemoveEmpty and %AutoFormat.RemoveEmpty.RemoveNbsp + are enabled, this directive defines what HTML elements should not be + removede if they have only a non-breaking space in them. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt new file mode 100644 index 00000000000..ca17eb1dc48 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt @@ -0,0 +1,15 @@ +AutoFormat.RemoveEmpty.RemoveNbsp +TYPE: bool +VERSION: 4.0.0 +DEFAULT: false +--DESCRIPTION-- ++ When enabled, HTML Purifier will treat any elements that contain only + non-breaking spaces as well as regular whitespace as empty, and remove + them when %AutoForamt.RemoveEmpty is enabled. +
++ See %AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions for a list of elements + that don't have this behavior applied to them. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt new file mode 100644 index 00000000000..34657ba47b1 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt @@ -0,0 +1,46 @@ +AutoFormat.RemoveEmpty +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- ++ When enabled, HTML Purifier will attempt to remove empty elements that + contribute no semantic information to the document. The following types + of nodes will be removed: +
+<a></a> but not
+ <br />), and
+ colgroup element, orid or name attribute,
+ when those attributes are permitted on those elements.
+ + Please be very careful when using this functionality; while it may not + seem that empty elements contain useful information, they can alter the + layout of a document given appropriate styling. This directive is most + useful when you are processing machine-generated HTML, please avoid using + it on regular user HTML. +
++ Elements that contain only whitespace will be treated as empty. Non-breaking + spaces, however, do not count as whitespace. See + %AutoFormat.RemoveEmpty.RemoveNbsp for alternate behavior. +
++ This algorithm is not perfect; you may still notice some empty tags, + particularly if a node had elements, but those elements were later removed + because they were not permitted in that context, or tags that, after + being auto-closed by another tag, where empty. This is for safety reasons + to prevent clever code from breaking validation. The general rule of thumb: + if a tag looked empty on the way in, it will get removed; if HTML Purifier + made it empty, it will stay. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt new file mode 100755 index 00000000000..dde990ab260 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt @@ -0,0 +1,11 @@ +AutoFormat.RemoveSpansWithoutAttributes +TYPE: bool +VERSION: 4.0.1 +DEFAULT: false +--DESCRIPTION-- +
+ This directive causes span tags without any attributes
+ to be removed. It will also remove spans that had all attributes
+ removed during processing.
+
display:none; is considered a tricky property that
+will only be allowed if this directive is set to true.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt
new file mode 100644
index 00000000000..460112ebe0a
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt
@@ -0,0 +1,18 @@
+CSS.AllowedProperties
+TYPE: lookup/null
+VERSION: 3.1.0
+DEFAULT: NULL
+--DESCRIPTION--
+
++ If HTML Purifier's style attributes set is unsatisfactory for your needs, + you can overload it with your own list of tags to allow. Note that this + method is subtractive: it does its job by taking away from HTML Purifier + usual feature set, so you cannot add an attribute that HTML Purifier never + supported in the first place. +
++ Warning: If another directive conflicts with the + elements here, that directive will win and override. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt new file mode 100644 index 00000000000..5cb7dda3bae --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt @@ -0,0 +1,11 @@ +CSS.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + ++ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt new file mode 100644 index 00000000000..7a3291470cc --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt @@ -0,0 +1,16 @@ +CSS.MaxImgLength +TYPE: string/null +DEFAULT: '1200px' +VERSION: 3.1.1 +--DESCRIPTION-- +
+ This parameter sets the maximum allowed length on img tags,
+ effectively the width and height properties.
+ Only absolute units of measurement (in, pt, pc, mm, cm) and pixels (px) are allowed. This is
+ in place to prevent imagecrash attacks, disable with null at your own risk.
+ This directive is similar to %HTML.MaxImgLength, and both should be
+ concurrently edited, although there are
+ subtle differences in the input format (the CSS max is a number with
+ a unit).
+
+ Whether or not to allow safe, proprietary CSS values. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt new file mode 100644 index 00000000000..c486724c88a --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt @@ -0,0 +1,14 @@ +Cache.DefinitionImpl +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: 'Serializer' +--DESCRIPTION-- + +This directive defines which method to use when caching definitions, +the complex data-type that makes HTML Purifier tick. Set to null +to disable caching (not recommended, as you will see a definite +performance degradation). + +--ALIASES-- +Core.DefinitionCache +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt new file mode 100644 index 00000000000..54036507d6c --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt @@ -0,0 +1,13 @@ +Cache.SerializerPath +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + ++ Absolute path with no trailing slash to store serialized definitions in. + Default is within the + HTML Purifier library inside DefinitionCache/Serializer. This + path must be writable by the webserver. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt new file mode 100644 index 00000000000..568cbf3b328 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt @@ -0,0 +1,18 @@ +Core.AggressivelyFixLt +TYPE: bool +VERSION: 2.1.0 +DEFAULT: true +--DESCRIPTION-- ++ This directive enables aggressive pre-filter fixes HTML Purifier can + perform in order to ensure that open angled-brackets do not get killed + during parsing stage. Enabling this will result in two preg_replace_callback + calls and at least two preg_replace calls for every HTML document parsed; + if your users make very well-formed HTML, you can set this directive false. + This has no effect when DirectLex is used. +
++ Notice: This directive's default turned from false to true + in HTML Purifier 3.2.0. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt new file mode 100644 index 00000000000..d7317911fa3 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt @@ -0,0 +1,12 @@ +Core.CollectErrors +TYPE: bool +VERSION: 2.0.0 +DEFAULT: false +--DESCRIPTION-- + +Whether or not to collect errors found while filtering the document. This +is a useful way to give feedback to your users. Warning: +Currently this feature is very patchy and experimental, with lots of +possible error messages not yet implemented. It will not cause any +problems, but it may not help your users either. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt new file mode 100644 index 00000000000..08b381d34c1 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt @@ -0,0 +1,28 @@ +Core.ColorKeywords +TYPE: hash +VERSION: 2.0.0 +--DEFAULT-- +array ( + 'maroon' => '#800000', + 'red' => '#FF0000', + 'orange' => '#FFA500', + 'yellow' => '#FFFF00', + 'olive' => '#808000', + 'purple' => '#800080', + 'fuchsia' => '#FF00FF', + 'white' => '#FFFFFF', + 'lime' => '#00FF00', + 'green' => '#008000', + 'navy' => '#000080', + 'blue' => '#0000FF', + 'aqua' => '#00FFFF', + 'teal' => '#008080', + 'black' => '#000000', + 'silver' => '#C0C0C0', + 'gray' => '#808080', +) +--DESCRIPTION-- + +Lookup array of color names to six digit hexadecimal number corresponding +to color, with preceding hash mark. Used when parsing colors. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt new file mode 100644 index 00000000000..64b114fce2b --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt @@ -0,0 +1,14 @@ +Core.ConvertDocumentToFragment +TYPE: bool +DEFAULT: true +--DESCRIPTION-- + +This parameter determines whether or not the filter should convert +input that is a full document with html and body tags to a fragment +of just the contents of a body tag. This parameter is simply something +HTML Purifier can do during an edge-case: for most inputs, this +processing is not necessary. + +--ALIASES-- +Core.AcceptFullDocuments +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt new file mode 100644 index 00000000000..36f16e07eae --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt @@ -0,0 +1,17 @@ +Core.DirectLexLineNumberSyncInterval +TYPE: int +VERSION: 2.0.0 +DEFAULT: 0 +--DESCRIPTION-- + ++ Specifies the number of tokens the DirectLex line number tracking + implementations should process before attempting to resyncronize the + current line count by manually counting all previous new-lines. When + at 0, this functionality is disabled. Lower values will decrease + performance, and this is only strictly necessary if the counting + algorithm is buggy (in which case you should report it as a bug). + This has no effect when %Core.MaintainLineNumbers is disabled or DirectLex is + not being used. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt new file mode 100644 index 00000000000..8bfb47c3ac1 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt @@ -0,0 +1,15 @@ +Core.Encoding +TYPE: istring +DEFAULT: 'utf-8' +--DESCRIPTION-- +If for some reason you are unable to convert all webpages to UTF-8, you can +use this directive as a stop-gap compatibility change to let HTML Purifier +deal with non UTF-8 input. This technique has notable deficiencies: +absolutely no characters outside of the selected character encoding will be +preserved, not even the ones that have been ampersand escaped (this is due +to a UTF-8 specific feature that automatically resolves all +entities), making it pretty useless for anything except the most I18N-blind +applications, although %Core.EscapeNonASCIICharacters offers fixes this +trouble with another tradeoff. This directive only accepts ISO-8859-1 if +iconv is not enabled. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt new file mode 100644 index 00000000000..4d5b5055cd3 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt @@ -0,0 +1,10 @@ +Core.EscapeInvalidChildren +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When true, a child is found that is not allowed in the context of the +parent element will be transformed into text as if it were ASCII. When +false, that element and all internal tags will be dropped, though text will +be preserved. There is no option for dropping the element but preserving +child nodes. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt new file mode 100644 index 00000000000..a7a5b249bb7 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt @@ -0,0 +1,7 @@ +Core.EscapeInvalidTags +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When true, invalid tags will be written back to the document as plain text. +Otherwise, they are silently dropped. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt new file mode 100644 index 00000000000..abb499948ac --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt @@ -0,0 +1,13 @@ +Core.EscapeNonASCIICharacters +TYPE: bool +VERSION: 1.4.0 +DEFAULT: false +--DESCRIPTION-- +This directive overcomes a deficiency in %Core.Encoding by blindly +converting all non-ASCII characters into decimal numeric entities before +converting it to its native encoding. This means that even characters that +can be expressed in the non-UTF-8 encoding will be entity-ized, which can +be a real downer for encodings like Big5. It also assumes that the ASCII +repetoire is available, although this is the case for almost all encodings. +Anyway, use UTF-8! +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt new file mode 100644 index 00000000000..915391edb73 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt @@ -0,0 +1,19 @@ +Core.HiddenElements +TYPE: lookup +--DEFAULT-- +array ( + 'script' => true, + 'style' => true, +) +--DESCRIPTION-- + +
+ This directive is a lookup array of elements which should have their
+ contents removed when they are not allowed by the HTML definition.
+ For example, the contents of a script tag are not
+ normally shown in a document, so if script tags are to be removed,
+ their contents should be removed to. This is opposed to a b
+ tag, which defines some presentational changes but does not hide its
+ contents.
+
+ This parameter determines what lexer implementation can be used. The + valid values are: +
+HTMLPurifier_Lexer.
+ I may remove this option simply because I don't expect anyone
+ to use it.
+ + If true, HTML Purifier will add line number information to all tokens. + This is useful when error reporting is turned on, but can result in + significant performance degradation and should not be used when + unnecessary. This directive must be used with the DirectLex lexer, + as the DOMLex lexer does not (yet) support this functionality. + If the value is null, an appropriate value will be selected based + on other configuration. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt new file mode 100644 index 00000000000..4070c2a0de2 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt @@ -0,0 +1,12 @@ +Core.RemoveInvalidImg +TYPE: bool +DEFAULT: true +VERSION: 1.3.0 +--DESCRIPTION-- + +
+ This directive enables pre-emptive URI checking in img
+ tags, as the attribute validation strategy is not authorized to
+ remove elements from the document. Revert to pre-1.3.0 behavior by setting to false.
+
+ This directive enables HTML Purifier to remove not only script tags + but all of their contents. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt new file mode 100644 index 00000000000..3db50ef204b --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt @@ -0,0 +1,11 @@ +Filter.Custom +TYPE: list +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +
+ This directive can be used to add custom filters; it is nearly the
+ equivalent of the now deprecated HTMLPurifier->addFilter()
+ method. Specify an array of concrete implementations.
+
+ Whether or not to escape the dangerous characters <, > and & + as \3C, \3E and \26, respectively. This is can be safely set to false + if the contents of StyleBlocks will be placed in an external stylesheet, + where there is no risk of it being interpreted as HTML. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt new file mode 100644 index 00000000000..7f95f54d125 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt @@ -0,0 +1,29 @@ +Filter.ExtractStyleBlocks.Scope +TYPE: string/null +VERSION: 3.0.0 +DEFAULT: NULL +ALIASES: Filter.ExtractStyleBlocksScope, FilterParam.ExtractStyleBlocksScope +--DESCRIPTION-- + +
+ If you would like users to be able to define external stylesheets, but
+ only allow them to specify CSS declarations for a specific node and
+ prevent them from fiddling with other elements, use this directive.
+ It accepts any valid CSS selector, and will prepend this to any
+ CSS declaration extracted from the document. For example, if this
+ directive is set to #user-content and a user uses the
+ selector a:hover, the final selector will be
+ #user-content a:hover.
+
+ The comma shorthand may be used; consider the above example, with
+ #user-content, #user-content2, the final selector will
+ be #user-content a:hover, #user-content2 a:hover.
+
+ Warning: It is possible for users to bypass this measure + using a naughty + selector. This is a bug in CSS Tidy 1.3, not HTML + Purifier, and I am working to get it fixed. Until then, HTML Purifier + performs a basic check to prevent this. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt new file mode 100644 index 00000000000..6c231b2d7f7 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt @@ -0,0 +1,16 @@ +Filter.ExtractStyleBlocks.TidyImpl +TYPE: mixed/null +VERSION: 3.1.0 +DEFAULT: NULL +ALIASES: FilterParam.ExtractStyleBlocksTidyImpl +--DESCRIPTION-- +
+ If left NULL, HTML Purifier will attempt to instantiate a csstidy
+ class to use for internal cleaning. This will usually be good enough.
+
+ However, for trusted user input, you can set this to false to
+ disable cleaning. In addition, you can supply your own concrete implementation
+ of Tidy's interface to use, although I don't know why you'd want to do that.
+
+ This directive turns on the style block extraction filter, which removes
+ style blocks from input HTML, cleans them up with CSSTidy,
+ and places them in the StyleBlocks context variable, for further
+ use by you, usually to be placed in an external stylesheet, or a
+ style block in the head of your document.
+
+ Sample usage: +
+'; +?> + + + ++Filter.ExtractStyleBlocks +body {color:#F00;} Some text'; + + $config = HTMLPurifier_Config::createDefault(); + $config->set('Filter', 'ExtractStyleBlocks', true); + $purifier = new HTMLPurifier($config); + + $html = $purifier->purify($dirty); + + // This implementation writes the stylesheets to the styles/ directory. + // You can also echo the styles inside the document, but it's a bit + // more difficult to make sure they get interpreted properly by + // browsers; try the usual CSS armoring techniques. + $styles = $purifier->context->get('StyleBlocks'); + $dir = 'styles/'; + if (!is_dir($dir)) mkdir($dir); + $hash = sha1($_GET['html']); + foreach ($styles as $i => $style) { + file_put_contents($name = $dir . $hash . "_$i"); + echo ''; + } +?> + + ++ ++ + +]]>
+ Warning: It is possible for a user to mount an + imagecrash attack using this CSS. Counter-measures are difficult; + it is not simply enough to limit the range of CSS lengths (using + relative lengths with many nesting levels allows for large values + to be attained without actually specifying them in the stylesheet), + and the flexible nature of selectors makes it difficult to selectively + disable lengths on image tags (HTML Purifier, however, does disable + CSS width and height in inline styling). There are probably two effective + counter measures: an explicit width and height set to auto in all + images in your document (unlikely) or the disabling of width and + height (somewhat reasonable). Whether or not these measures should be + used is left to the reader. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt new file mode 100644 index 00000000000..7fa6536b2c7 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt @@ -0,0 +1,11 @@ +Filter.YouTube +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- ++ This directive enables YouTube video embedding in HTML Purifier. Check + this document + on embedding videos for more information on what this filter does. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt new file mode 100644 index 00000000000..3e231d2d16a --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt @@ -0,0 +1,22 @@ +HTML.Allowed +TYPE: itext/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +
+ This is a convenience directive that rolls the functionality of
+ %HTML.AllowedElements and %HTML.AllowedAttributes into one directive.
+ Specify elements and attributes that are allowed using:
+ element1[attr1|attr2],element2.... You can also use
+ newlines instead of commas to separate elements.
+
+ Warning:
+ All of the constraints on the component directives are still enforced.
+ The syntax is a subset of TinyMCE's valid_elements
+ whitelist: directly copy-pasting it here will probably result in
+ broken whitelists. If %HTML.AllowedElements or %HTML.AllowedAttributes
+ are set, this directive has no effect.
+
+ If HTML Purifier's attribute set is unsatisfactory, overload it! + The syntax is "tag.attr" or "*.attr" for the global attributes + (style, id, class, dir, lang, xml:lang). +
++ Warning: If another directive conflicts with the + elements here, that directive will win and override. For + example, %HTML.EnableAttrID will take precedence over *.id in this + directive. You must set that directive to true before you can use + IDs at all. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt new file mode 100644 index 00000000000..888d5581969 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt @@ -0,0 +1,18 @@ +HTML.AllowedElements +TYPE: lookup/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- ++ If HTML Purifier's tag set is unsatisfactory for your needs, you + can overload it with your own list of tags to allow. Note that this + method is subtractive: it does its job by taking away from HTML Purifier + usual feature set, so you cannot add a tag that HTML Purifier never + supported in the first place (like embed, form or head). If you + change this, you probably also want to change %HTML.AllowedAttributes. +
++ Warning: If another directive conflicts with the + elements here, that directive will win and override. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt new file mode 100644 index 00000000000..5a59a55c083 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt @@ -0,0 +1,20 @@ +HTML.AllowedModules +TYPE: lookup/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + ++ A doctype comes with a set of usual modules to use. Without having + to mucking about with the doctypes, you can quickly activate or + disable these modules by specifying which modules you wish to allow + with this directive. This is most useful for unit testing specific + modules, although end users may find it useful for their own ends. +
++ If you specify a module that does not exist, the manager will silently + fail to use it, so be careful! User-defined modules are not affected + by this directive. Modules defined in %HTML.CoreModules are not + affected by this directive. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt new file mode 100644 index 00000000000..151fb7b8264 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt @@ -0,0 +1,11 @@ +HTML.Attr.Name.UseCDATA +TYPE: bool +DEFAULT: false +VERSION: 4.0.0 +--DESCRIPTION-- +The W3C specification DTD defines the name attribute to be CDATA, not ID, due +to limitations of DTD. In certain documents, this relaxed behavior is desired, +whether it is to specify duplicate names, or to specify names that would be +illegal IDs (for example, names that begin with a digit.) Set this configuration +directive to true to use the relaxed parsing rules. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt new file mode 100644 index 00000000000..45ae469ec98 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt @@ -0,0 +1,18 @@ +HTML.BlockWrapper +TYPE: string +VERSION: 1.3.0 +DEFAULT: 'p' +--DESCRIPTION-- + ++ String name of element to wrap inline elements that are inside a block + context. This only occurs in the children of blockquote in strict mode. +
+
+ Example: by default value,
+ <blockquote>Foo</blockquote> would become
+ <blockquote><p>Foo</p></blockquote>.
+ The <p> tags can be replaced with whatever you desire,
+ as long as it is a block level element.
+
+ Certain modularized doctypes (XHTML, namely), have certain modules + that must be included for the doctype to be an conforming document + type: put those modules here. By default, XHTML's core modules + are used. You can set this to a blank array to disable core module + protection, but this is not recommended. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt new file mode 100644 index 00000000000..a64e3d7c363 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt @@ -0,0 +1,9 @@ +HTML.CustomDoctype +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + +A custom doctype for power-users who defined there own document +type. This directive only applies when %HTML.Doctype is blank. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt new file mode 100644 index 00000000000..103db754a28 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt @@ -0,0 +1,33 @@ +HTML.DefinitionID +TYPE: string/null +DEFAULT: NULL +VERSION: 2.0.0 +--DESCRIPTION-- + ++ Unique identifier for a custom-built HTML definition. If you edit + the raw version of the HTMLDefinition, introducing changes that the + configuration object does not reflect, you must specify this variable. + If you change your custom edits, you should change this directive, or + clear your cache. Example: +
+
+$config = HTMLPurifier_Config::createDefault();
+$config->set('HTML', 'DefinitionID', '1');
+$def = $config->getHTMLDefinition();
+$def->addAttribute('a', 'tabindex', 'Number');
+
++ In the above example, the configuration is still at the defaults, but + using the advanced API, an extra attribute has been added. The + configuration object normally has no way of knowing that this change + has taken place, so it needs an extra directive: %HTML.DefinitionID. + If someone else attempts to use the default configuration, these two + pieces of code will not clobber each other in the cache, since one has + an extra directive attached to it. +
++ You must specify a value to this directive to use the + advanced API features. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt new file mode 100644 index 00000000000..229ae0267a6 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt @@ -0,0 +1,16 @@ +HTML.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + ++ Revision identifier for your custom definition specified in + %HTML.DefinitionID. This serves the same purpose: uniquely identifying + your custom definition, but this one does so in a chronological + context: revision 3 is more up-to-date then revision 2. Thus, when + this gets incremented, the cache handling is smart enough to clean + up any older revisions of your definition as well as flush the + cache. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt new file mode 100644 index 00000000000..9dab497f2f3 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt @@ -0,0 +1,11 @@ +HTML.Doctype +TYPE: string/null +DEFAULT: NULL +--DESCRIPTION-- +Doctype to use during filtering. Technically speaking this is not actually +a doctype (as it does not identify a corresponding DTD), but we are using +this name for sake of simplicity. When non-blank, this will override any +older directives like %HTML.XHTML or %HTML.Strict. +--ALLOWED-- +'HTML 4.01 Transitional', 'HTML 4.01 Strict', 'XHTML 1.0 Transitional', 'XHTML 1.0 Strict', 'XHTML 1.1' +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt new file mode 100644 index 00000000000..57358f9bad2 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt @@ -0,0 +1,21 @@ +HTML.ForbiddenAttributes +TYPE: lookup +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +
+ While this directive is similar to %HTML.AllowedAttributes, for
+ forwards-compatibility with XML, this attribute has a different syntax. Instead of
+ tag.attr, use tag@attr. To disallow href
+ attributes in a tags, set this directive to
+ a@href. You can also disallow an attribute globally with
+ attr or *@attr (either syntax is fine; the latter
+ is provided for consistency with %HTML.AllowedAttributes).
+
+ Warning: This directive complements %HTML.ForbiddenElements, + accordingly, check + out that directive for a discussion of why you + should think twice before using this directive. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt new file mode 100644 index 00000000000..93a53e14fb4 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt @@ -0,0 +1,20 @@ +HTML.ForbiddenElements +TYPE: lookup +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- ++ This was, perhaps, the most requested feature ever in HTML + Purifier. Please don't abuse it! This is the logical inverse of + %HTML.AllowedElements, and it will override that directive, or any + other directive. +
+
+ If possible, %HTML.Allowed is recommended over this directive, because it
+ can sometimes be difficult to tell whether or not you've forbidden all of
+ the behavior you would like to disallow. If you forbid img
+ with the expectation of preventing images on your site, you'll be in for
+ a nasty surprise when people start using the background-image
+ CSS property.
+
+ This directive controls the maximum number of pixels in the width and
+ height attributes in img tags. This is
+ in place to prevent imagecrash attacks, disable with null at your own risk.
+ This directive is similar to %CSS.MaxImgLength, and both should be
+ concurrently edited, although there are
+ subtle differences in the input format (the HTML max is an integer).
+
+ String name of element that HTML fragment passed to library will be + inserted in. An interesting variation would be using span as the + parent element, meaning that only inline tags would be allowed. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt new file mode 100644 index 00000000000..dfb720496da --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt @@ -0,0 +1,12 @@ +HTML.Proprietary +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- +
+ Whether or not to allow proprietary elements and attributes in your
+ documents, as per HTMLPurifier_HTMLModule_Proprietary.
+ Warning: This can cause your documents to stop
+ validating!
+
+ Whether or not to permit embed tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to embed tags. Embed is a proprietary + element and will cause your website to stop validating; you should + see if you can use %Output.FlashCompat with %HTML.SafeObject instead + first.
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt new file mode 100644 index 00000000000..ceb342e22b7 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt @@ -0,0 +1,13 @@ +HTML.SafeObject +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- ++ Whether or not to permit object tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to object tags. You should also enable + %Output.FlashCompat in order to generate Internet Explorer + compatibility code for your object tags. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt new file mode 100644 index 00000000000..a8b1de56bef --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt @@ -0,0 +1,9 @@ +HTML.Strict +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +DEPRECATED-VERSION: 1.7.0 +DEPRECATED-USE: HTML.Doctype +--DESCRIPTION-- +Determines whether or not to use Transitional (loose) or Strict rulesets. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt new file mode 100644 index 00000000000..b4c271b7fac --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt @@ -0,0 +1,8 @@ +HTML.TidyAdd +TYPE: lookup +VERSION: 2.0.0 +DEFAULT: array() +--DESCRIPTION-- + +Fixes to add to the default set of Tidy fixes as per your level. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt new file mode 100644 index 00000000000..4186ccd0d19 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt @@ -0,0 +1,24 @@ +HTML.TidyLevel +TYPE: string +VERSION: 2.0.0 +DEFAULT: 'medium' +--DESCRIPTION-- + +General level of cleanliness the Tidy module should enforce. +There are four allowed values:
++ If true, HTML Purifier will generate Internet Explorer compatibility + code for all object code. This is highly recommended if you enable + %HTML.SafeObject. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt new file mode 100644 index 00000000000..79f8ad82cfc --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt @@ -0,0 +1,13 @@ +Output.Newline +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + ++ Newline string to format final output with. If left null, HTML Purifier + will auto-detect the default newline type of the system and use that; + you can manually override it here. Remember, \r\n is Windows, \r + is Mac, and \n is Unix. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt new file mode 100644 index 00000000000..232b02362a4 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt @@ -0,0 +1,14 @@ +Output.SortAttr +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +
+ If true, HTML Purifier will sort attributes by name before writing them back
+ to the document, converting a tag like: <el b="" a="" c="" />
+ to <el a="" b="" c="" />. This is a workaround for
+ a bug in FCKeditor which causes it to swap attributes order, adding noise
+ to text diffs. If you're not seeing this bug, chances are, you don't need
+ this directive.
+
+ Determines whether or not to run Tidy on the final output for pretty + formatting reasons, such as indentation and wrap. +
++ This can greatly improve readability for editors who are hand-editing + the HTML, but is by no means necessary as HTML Purifier has already + fixed all major errors the HTML may have had. Tidy is a non-default + extension, and this directive will silently fail if Tidy is not + available. +
++ If you are looking to make the overall look of your page's source + better, I recommend running Tidy on the entire page rather than just + user-content (after all, the indentation relative to the containing + blocks will be incorrect). +
+--ALIASES-- +Core.TidyFormat +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt new file mode 100644 index 00000000000..071bc0295df --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt @@ -0,0 +1,7 @@ +Test.ForceNoIconv +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When set to true, HTMLPurifier_Encoder will act as if iconv does not exist +and use only pure PHP implementations. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt new file mode 100644 index 00000000000..ae3a913f242 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt @@ -0,0 +1,17 @@ +URI.AllowedSchemes +TYPE: lookup +--DEFAULT-- +array ( + 'http' => true, + 'https' => true, + 'mailto' => true, + 'ftp' => true, + 'nntp' => true, + 'news' => true, +) +--DESCRIPTION-- +Whitelist that defines the schemes that a URI is allowed to have. This +prevents XSS attacks from using pseudo-schemes like javascript or mocha. +There is also support for thedata URI scheme, but it is not
+enabled by default.
+--# vim: et sw=4 sts=4
diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Base.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Base.txt
new file mode 100644
index 00000000000..876f0680cf2
--- /dev/null
+++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Base.txt
@@ -0,0 +1,17 @@
+URI.Base
+TYPE: string/null
+VERSION: 2.1.0
+DEFAULT: NULL
+--DESCRIPTION--
+
++ The base URI is the URI of the document this purified HTML will be + inserted into. This information is important if HTML Purifier needs + to calculate absolute URIs from relative URIs, such as when %URI.MakeAbsolute + is on. You may use a non-absolute URI for this value, but behavior + may vary (%URI.MakeAbsolute deals nicely with both absolute and + relative paths, but forwards-compatibility is not guaranteed). + Warning: If set, the scheme on this URI + overrides the one specified by %URI.DefaultScheme. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt new file mode 100644 index 00000000000..728e378cbeb --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt @@ -0,0 +1,10 @@ +URI.DefaultScheme +TYPE: string +DEFAULT: 'http' +--DESCRIPTION-- + ++ Defines through what scheme the output will be served, in order to + select the proper object validator when no scheme information is present. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt new file mode 100644 index 00000000000..f05312ba862 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt @@ -0,0 +1,11 @@ +URI.DefinitionID +TYPE: string/null +VERSION: 2.1.0 +DEFAULT: NULL +--DESCRIPTION-- + ++ Unique identifier for a custom-built URI definition. If you want + to add custom URIFilters, you must specify this value. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt new file mode 100644 index 00000000000..80cfea93f72 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt @@ -0,0 +1,11 @@ +URI.DefinitionRev +TYPE: int +VERSION: 2.1.0 +DEFAULT: 1 +--DESCRIPTION-- + ++ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt new file mode 100644 index 00000000000..71ce025a2dc --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt @@ -0,0 +1,14 @@ +URI.Disable +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- + ++ Disables all URIs in all forms. Not sure why you'd want to do that + (after all, the Internet's founded on the notion of a hyperlink). +
+ +--ALIASES-- +Attr.DisableURI +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt new file mode 100644 index 00000000000..13c122c8cec --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt @@ -0,0 +1,11 @@ +URI.DisableExternal +TYPE: bool +VERSION: 1.2.0 +DEFAULT: false +--DESCRIPTION-- +Disables links to external websites. This is a highly effective anti-spam +and anti-pagerank-leech measure, but comes at a hefty price: nolinks or +images outside of your domain will be allowed. Non-linkified URIs will +still be preserved. If you want to be able to link to subdomains or use +absolute URIs, specify %URI.Host for your website. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt new file mode 100644 index 00000000000..abcc1efd613 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt @@ -0,0 +1,13 @@ +URI.DisableExternalResources +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- +Disables the embedding of external resources, preventing users from +embedding things like images from other hosts. This prevents access +tracking (good for email viewers), bandwidth leeching, cross-site request +forging, goatse.cx posting, and other nasties, but also results in a loss +of end-user functionality (they can't directly post a pic they posted from +Flickr anymore). Use it if you don't have a robust user-content moderation +team. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt new file mode 100644 index 00000000000..51e6ea91f79 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt @@ -0,0 +1,12 @@ +URI.DisableResources +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- + ++ Disables embedding resources, essentially meaning no pictures. You can + still link to them though. See %URI.DisableExternalResources for why + this might be a good idea. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Host.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Host.txt new file mode 100644 index 00000000000..ee83b121dec --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Host.txt @@ -0,0 +1,19 @@ +URI.Host +TYPE: string/null +VERSION: 1.2.0 +DEFAULT: NULL +--DESCRIPTION-- + ++ Defines the domain name of the server, so we can determine whether or + an absolute URI is from your website or not. Not strictly necessary, + as users should be using relative URIs to reference resources on your + website. It will, however, let you use absolute URIs to link to + subdomains of the domain you post here: i.e. example.com will allow + sub.example.com. However, higher up domains will still be excluded: + if you set %URI.Host to sub.example.com, example.com will be blocked. + Note: This directive overrides %URI.Base because + a given page may be on a sub-domain, but you wish HTML Purifier to be + more relaxed and allow some of the parent domains too. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt new file mode 100644 index 00000000000..0b6df7625dc --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt @@ -0,0 +1,9 @@ +URI.HostBlacklist +TYPE: list +VERSION: 1.3.0 +DEFAULT: array() +--DESCRIPTION-- +List of strings that are forbidden in the host of any URI. Use it to kill +domain names of spam, etc. Note that it will catch anything in the domain, +so moo.com will catch moo.com.example.com. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt new file mode 100644 index 00000000000..4214900a592 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt @@ -0,0 +1,13 @@ +URI.MakeAbsolute +TYPE: bool +VERSION: 2.1.0 +DEFAULT: false +--DESCRIPTION-- + ++ Converts all URIs into absolute forms. This is useful when the HTML + being filtered assumes a specific base path, but will actually be + viewed in a different context (and setting an alternate base URI is + not possible). %URI.Base must be set for this directive to work. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt new file mode 100644 index 00000000000..58c81dcc441 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt @@ -0,0 +1,83 @@ +URI.Munge +TYPE: string/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- + +
+ Munges all browsable (usually http, https and ftp)
+ absolute URIs into another URI, usually a URI redirection service.
+ This directive accepts a URI, formatted with a %s where
+ the url-encoded original URI should be inserted (sample:
+ http://www.google.com/url?q=%s).
+
+ Uses for this directive: +
+
+ Prior to HTML Purifier 3.1.1, this directive also enabled the munging
+ of browsable external resources, which could break things if your redirection
+ script was a splash page or used meta tags. To revert to
+ previous behavior, please use %URI.MungeResources.
+
+ You may want to also use %URI.MungeSecretKey along with this directive + in order to enforce what URIs your redirector script allows. Open + redirector scripts can be a security risk and negatively affect the + reputation of your domain name. +
++ Starting with HTML Purifier 3.1.1, there is also these substitutions: +
+| Key | +Description | +Example <a href=""> |
+
|---|---|---|
| %r | +1 - The URI embeds a resource (blank) - The URI is merely a link |
+ + |
| %n | +The name of the tag this URI came from | +a | +
| %m | +The name of the attribute this URI came from | +href | +
| %p | +The name of the CSS property this URI came from, or blank if irrelevant | ++ |
+ Admittedly, these letters are somewhat arbitrary; the only stipulation + was that they couldn't be a through f. r is for resource (I would have preferred + e, but you take what you can get), n is for name, m + was picked because it came after n (and I couldn't use a), p is for + property. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt new file mode 100644 index 00000000000..6fce0fdc373 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt @@ -0,0 +1,17 @@ +URI.MungeResources +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +
+ If true, any URI munging directives like %URI.Munge
+ will also apply to embedded resources, such as <img src="">.
+ Be careful enabling this directive if you have a redirector script
+ that does not use the Location HTTP header; all of your images
+ and other embedded resources will break.
+
+ Warning: It is strongly advised you use this in conjunction + %URI.MungeSecretKey to mitigate the security risk of an open redirector. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt new file mode 100644 index 00000000000..0d00f62ea8a --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt @@ -0,0 +1,30 @@ +URI.MungeSecretKey +TYPE: string/null +VERSION: 3.1.1 +DEFAULT: NULL +--DESCRIPTION-- ++ This directive enables secure checksum generation along with %URI.Munge. + It should be set to a secure key that is not shared with anyone else. + The checksum can be placed in the URI using %t. Use of this checksum + affords an additional level of protection by allowing a redirector + to check if a URI has passed through HTML Purifier with this line: +
+ +$checksum === sha1($secret_key . ':' . $url)+ +
+ If the output is TRUE, the redirector script should accept the URI. +
+ ++ Please note that it would still be possible for an attacker to procure + secure hashes en-mass by abusing your website's Preview feature or the + like, but this service affords an additional level of protection + that should be combined with website blacklisting. +
+ ++ Remember this has no effect if %URI.Munge is not on. +
+--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt new file mode 100644 index 00000000000..23331a4e790 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt @@ -0,0 +1,9 @@ +URI.OverrideAllowedSchemes +TYPE: bool +DEFAULT: true +--DESCRIPTION-- +If this is set to true (which it is by default), you can override +%URI.AllowedSchemes by simply registering a HTMLPurifier_URIScheme to the +registry. If false, you will also have to update that directive in order +to add more schemes. +--# vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/info.ini b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/info.ini new file mode 100644 index 00000000000..5de4505e1b0 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/info.ini @@ -0,0 +1,3 @@ +name = "HTML Purifier" + +; vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ContentSets.php b/lib/htmlpurifier/HTMLPurifier/ContentSets.php index 7baf7a3101d..3b6e96f5f56 100644 --- a/lib/htmlpurifier/HTMLPurifier/ContentSets.php +++ b/lib/htmlpurifier/HTMLPurifier/ContentSets.php @@ -1,94 +1,98 @@ true) indexed by name. * @note This is in HTMLPurifier_HTMLDefinition->info_content_sets - * @public */ - var $lookup = array(); - + public $lookup = array(); + /** * Synchronized list of defined content sets (keys of info) */ - var $keys = array(); + protected $keys = array(); /** * Synchronized list of defined content values (values of info) */ - var $values = array(); - + protected $values = array(); + /** * Merges in module's content sets, expands identifiers in the content * sets and populates the keys, values and lookup member variables. * @param $modules List of HTMLPurifier_HTMLModule */ - function HTMLPurifier_ContentSets($modules) { + public function __construct($modules) { if (!is_array($modules)) $modules = array($modules); // populate content_sets based on module hints // sorry, no way of overloading foreach ($modules as $module_i => $module) { foreach ($module->content_sets as $key => $value) { - if (isset($this->info[$key])) { + $temp = $this->convertToLookup($value); + if (isset($this->lookup[$key])) { // add it into the existing content set - $this->info[$key] = $this->info[$key] . ' | ' . $value; + $this->lookup[$key] = array_merge($this->lookup[$key], $temp); } else { - $this->info[$key] = $value; + $this->lookup[$key] = $temp; } } } - // perform content_set expansions - $this->keys = array_keys($this->info); - foreach ($this->info as $i => $set) { - // only performed once, so infinite recursion is not - // a problem - $this->info[$i] = - str_replace( - $this->keys, - // must be recalculated each time due to - // changing substitutions - array_values($this->info), - $set); + $old_lookup = false; + while ($old_lookup !== $this->lookup) { + $old_lookup = $this->lookup; + foreach ($this->lookup as $i => $set) { + $add = array(); + foreach ($set as $element => $x) { + if (isset($this->lookup[$element])) { + $add += $this->lookup[$element]; + unset($this->lookup[$i][$element]); + } + } + $this->lookup[$i] += $add; + } } + + foreach ($this->lookup as $key => $lookup) { + $this->info[$key] = implode(' | ', array_keys($lookup)); + } + $this->keys = array_keys($this->info); $this->values = array_values($this->info); - - // generate lookup tables - foreach ($this->info as $name => $set) { - $this->lookup[$name] = $this->convertToLookup($set); - } } - + /** * Accepts a definition; generates and assigns a ChildDef for it * @param $def HTMLPurifier_ElementDef reference * @param $module Module that defined the ElementDef */ - function generateChildDef(&$def, $module) { + public function generateChildDef(&$def, $module) { if (!empty($def->child)) return; // already done! $content_model = $def->content_model; if (is_string($content_model)) { - $def->content_model = str_replace( - $this->keys, $this->values, $content_model); + // Assume that $this->keys is alphanumeric + $def->content_model = preg_replace_callback( + '/\b(' . implode('|', $this->keys) . ')\b/', + array($this, 'generateChildDefCallback'), + $content_model + ); + //$def->content_model = str_replace( + // $this->keys, $this->values, $content_model); } $def->child = $this->getChildDef($def, $module); } - + + public function generateChildDefCallback($matches) { + return $this->info[$matches[0]]; + } + /** * Instantiates a ChildDef based on content_model and content_model_type * member variables in HTMLPurifier_ElementDef @@ -97,7 +101,7 @@ class HTMLPurifier_ContentSets * @param $def HTMLPurifier_ElementDef to have ChildDef extracted * @return HTMLPurifier_ChildDef corresponding to ElementDef */ - function getChildDef($def, $module) { + public function getChildDef($def, $module) { $value = $def->content_model; if (is_object($value)) { trigger_error( @@ -130,14 +134,14 @@ class HTMLPurifier_ContentSets ); return false; } - + /** * Converts a string list of elements separated by pipes into * a lookup array. * @param $string List of elements * @return Lookup array of elements */ - function convertToLookup($string) { + protected function convertToLookup($string) { $array = explode('|', str_replace(' ', '', $string)); $ret = array(); foreach ($array as $i => $k) { @@ -145,6 +149,7 @@ class HTMLPurifier_ContentSets } return $ret; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/Context.php b/lib/htmlpurifier/HTMLPurifier/Context.php index a78a6fb6f63..9ddf0c5476a 100644 --- a/lib/htmlpurifier/HTMLPurifier/Context.php +++ b/lib/htmlpurifier/HTMLPurifier/Context.php @@ -4,22 +4,23 @@ * Registry object that contains information about the current context. * @warning Is a bit buggy when variables are set to null: it thinks * they don't exist! So use false instead, please. + * @note Since the variables Context deals with may not be objects, + * references are very important here! Do not remove! */ class HTMLPurifier_Context { - + /** * Private array that stores the references. - * @private */ - var $_storage = array(); - + private $_storage = array(); + /** * Registers a variable into the context. * @param $name String name - * @param $ref Variable to be registered + * @param $ref Reference to variable to be registered */ - function register($name, &$ref) { + public function register($name, &$ref) { if (isset($this->_storage[$name])) { trigger_error("Name $name produces collision, cannot re-register", E_USER_ERROR); @@ -27,13 +28,13 @@ class HTMLPurifier_Context } $this->_storage[$name] =& $ref; } - + /** * Retrieves a variable reference from the context. * @param $name String name * @param $ignore_error Boolean whether or not to ignore error */ - function &get($name, $ignore_error = false) { + public function &get($name, $ignore_error = false) { if (!isset($this->_storage[$name])) { if (!$ignore_error) { trigger_error("Attempted to retrieve non-existent variable $name", @@ -44,12 +45,12 @@ class HTMLPurifier_Context } return $this->_storage[$name]; } - + /** * Destorys a variable in the context. * @param $name String name */ - function destroy($name) { + public function destroy($name) { if (!isset($this->_storage[$name])) { trigger_error("Attempted to destroy non-existent variable $name", E_USER_ERROR); @@ -57,24 +58,25 @@ class HTMLPurifier_Context } unset($this->_storage[$name]); } - + /** * Checks whether or not the variable exists. * @param $name String name */ - function exists($name) { + public function exists($name) { return isset($this->_storage[$name]); } - + /** * Loads a series of variables from an associative array * @param $context_array Assoc array of variables to load */ - function loadArray(&$context_array) { + public function loadArray($context_array) { foreach ($context_array as $key => $discard) { $this->register($key, $context_array[$key]); } } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/Definition.php b/lib/htmlpurifier/HTMLPurifier/Definition.php index 8f958e4798d..a7408c97498 100644 --- a/lib/htmlpurifier/HTMLPurifier/Definition.php +++ b/lib/htmlpurifier/HTMLPurifier/Definition.php @@ -4,37 +4,36 @@ * Super-class for definition datatype objects, implements serialization * functions for the class. */ -class HTMLPurifier_Definition +abstract class HTMLPurifier_Definition { - + /** * Has setup() been called yet? */ - var $setup = false; - + public $setup = false; + /** * What type of definition is it? */ - var $type; - + public $type; + /** * Sets up the definition object into the final form, something * not done by the constructor * @param $config HTMLPurifier_Config instance */ - function doSetup($config) { - trigger_error('Cannot call abstract method', E_USER_ERROR); - } - + abstract protected function doSetup($config); + /** * Setup function that aborts if already setup * @param $config HTMLPurifier_Config instance */ - function setup($config) { + public function setup($config) { if ($this->setup) return; $this->setup = true; $this->doSetup($config); } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/DefinitionCache.php b/lib/htmlpurifier/HTMLPurifier/DefinitionCache.php index 5b14fdfe4dd..c6e1e388c65 100644 --- a/lib/htmlpurifier/HTMLPurifier/DefinitionCache.php +++ b/lib/htmlpurifier/HTMLPurifier/DefinitionCache.php @@ -1,131 +1,108 @@ type = $type; } - + /** * Generates a unique identifier for a particular configuration * @param Instance of HTMLPurifier_Config */ - function generateKey($config) { - return $config->version . '-' . // possibly replace with function calls - $config->getBatchSerial($this->type) . '-' . - $config->get($this->type, 'DefinitionRev'); + public function generateKey($config) { + return $config->version . ',' . // possibly replace with function calls + $config->getBatchSerial($this->type) . ',' . + $config->get($this->type . '.DefinitionRev'); } - + /** * Tests whether or not a key is old with respect to the configuration's * version and revision number. * @param $key Key to test * @param $config Instance of HTMLPurifier_Config to test against */ - function isOld($key, $config) { - if (substr_count($key, '-') < 2) return true; - list($version, $hash, $revision) = explode('-', $key, 3); + public function isOld($key, $config) { + if (substr_count($key, ',') < 2) return true; + list($version, $hash, $revision) = explode(',', $key, 3); $compare = version_compare($version, $config->version); // version mismatch, is always old if ($compare != 0) return true; // versions match, ids match, check revision number if ( $hash == $config->getBatchSerial($this->type) && - $revision < $config->get($this->type, 'DefinitionRev') + $revision < $config->get($this->type . '.DefinitionRev') ) return true; return false; } - + /** * Checks if a definition's type jives with the cache's type * @note Throws an error on failure * @param $def Definition object to check * @return Boolean true if good, false if not */ - function checkDefType($def) { + public function checkDefType($def) { if ($def->type !== $this->type) { trigger_error("Cannot use definition of type {$def->type} in cache for {$this->type}"); return false; } return true; } - + /** * Adds a definition object to the cache */ - function add($def, $config) { - trigger_error('Cannot call abstract method', E_USER_ERROR); - } - + abstract public function add($def, $config); + /** * Unconditionally saves a definition object to the cache */ - function set($def, $config) { - trigger_error('Cannot call abstract method', E_USER_ERROR); - } - + abstract public function set($def, $config); + /** * Replace an object in the cache */ - function replace($def, $config) { - trigger_error('Cannot call abstract method', E_USER_ERROR); - } - + abstract public function replace($def, $config); + /** * Retrieves a definition object from the cache */ - function get($config) { - trigger_error('Cannot call abstract method', E_USER_ERROR); - } - + abstract public function get($config); + /** * Removes a definition object to the cache */ - function remove($config) { - trigger_error('Cannot call abstract method', E_USER_ERROR); - } - + abstract public function remove($config); + /** * Clears all objects from cache */ - function flush($config) { - trigger_error('Cannot call abstract method', E_USER_ERROR); - } - + abstract public function flush($config); + /** * Clears all expired (older version or revision) objects from cache * @note Be carefuly implementing this method as flush. Flush must * not interfere with other Definition types, and cleanup() * should not be repeatedly called by userland code. */ - function cleanup($config) { - trigger_error('Cannot call abstract method', E_USER_ERROR); - } + abstract public function cleanup($config); + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator.php b/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator.php index 14fca859744..b0fb6d0cd67 100644 --- a/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator.php +++ b/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator.php @@ -1,59 +1,62 @@ copy(); // reference is necessary for mocks in PHP 4 $decorator->cache =& $cache; $decorator->type = $cache->type; return $decorator; } - + /** * Cross-compatible clone substitute */ - function copy() { + public function copy() { return new HTMLPurifier_DefinitionCache_Decorator(); } - - function add($def, $config) { + + public function add($def, $config) { return $this->cache->add($def, $config); } - - function set($def, $config) { + + public function set($def, $config) { return $this->cache->set($def, $config); } - - function replace($def, $config) { + + public function replace($def, $config) { return $this->cache->replace($def, $config); } - - function get($config) { + + public function get($config) { return $this->cache->get($config); } - - function flush($config) { + + public function remove($config) { + return $this->cache->remove($config); + } + + public function flush($config) { return $this->cache->flush($config); } - - function cleanup($config) { + + public function cleanup($config) { return $this->cache->cleanup($config); } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php b/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php index eb47c433fbb..d4cc35c4bc1 100644 --- a/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php +++ b/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php @@ -1,7 +1,5 @@ definitions[$this->generateKey($config)] = $def; return $status; } - - function set($def, $config) { + + public function set($def, $config) { $status = parent::set($def, $config); if ($status) $this->definitions[$this->generateKey($config)] = $def; return $status; } - - function replace($def, $config) { + + public function replace($def, $config) { $status = parent::replace($def, $config); if ($status) $this->definitions[$this->generateKey($config)] = $def; return $status; } - - function get($config) { + + public function get($config) { $key = $this->generateKey($config); if (isset($this->definitions[$key])) return $this->definitions[$key]; $this->definitions[$key] = parent::get($config); return $this->definitions[$key]; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/Template.php.in b/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/Template.php.in index 62235e225db..21a8fcfda24 100644 --- a/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/Template.php.in +++ b/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/Template.php.in @@ -1,46 +1,47 @@ - - Absolute path with no trailing slash to store serialized definitions in. - Default is within the - HTML Purifier library inside DefinitionCache/Serializer. This - path must be writable by the webserver. This directive has been - available since 2.0.0. - -'); - class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCache { - - function add($def, $config) { + + public function add($def, $config) { if (!$this->checkDefType($def)) return; $file = $this->generateFilePath($config); if (file_exists($file)) return false; if (!$this->_prepareDir($config)) return false; return $this->_write($file, serialize($def)); } - - function set($def, $config) { + + public function set($def, $config) { if (!$this->checkDefType($def)) return; $file = $this->generateFilePath($config); if (!$this->_prepareDir($config)) return false; return $this->_write($file, serialize($def)); } - - function replace($def, $config) { + + public function replace($def, $config) { if (!$this->checkDefType($def)) return; $file = $this->generateFilePath($config); if (!file_exists($file)) return false; if (!$this->_prepareDir($config)) return false; return $this->_write($file, serialize($def)); } - - function get($config) { + + public function get($config) { $file = $this->generateFilePath($config); if (!file_exists($file)) return false; return unserialize(file_get_contents($file)); } - - function remove($config) { + + public function remove($config) { $file = $this->generateFilePath($config); if (!file_exists($file)) return false; return unlink($file); } - - function flush($config) { + + public function flush($config) { if (!$this->_prepareDir($config)) return false; $dir = $this->generateDirectoryPath($config); $dh = opendir($dir); @@ -62,8 +49,8 @@ class HTMLPurifier_DefinitionCache_Serializer extends unlink($dir . '/' . $filename); } } - - function cleanup($config) { + + public function cleanup($config) { if (!$this->_prepareDir($config)) return false; $dir = $this->generateDirectoryPath($config); $dh = opendir($dir); @@ -74,91 +61,85 @@ class HTMLPurifier_DefinitionCache_Serializer extends if ($this->isOld($key, $config)) unlink($dir . '/' . $filename); } } - + /** * Generates the file path to the serial file corresponding to * the configuration and definition name + * @todo Make protected */ - function generateFilePath($config) { + public function generateFilePath($config) { $key = $this->generateKey($config); return $this->generateDirectoryPath($config) . '/' . $key . '.ser'; } - + /** * Generates the path to the directory contain this cache's serial files * @note No trailing slash + * @todo Make protected */ - function generateDirectoryPath($config) { + public function generateDirectoryPath($config) { $base = $this->generateBaseDirectoryPath($config); return $base . '/' . $this->type; } - + /** * Generates path to base directory that contains all definition type * serials + * @todo Make protected */ - function generateBaseDirectoryPath($config) { - $base = $config->get('Cache', 'SerializerPath'); + public function generateBaseDirectoryPath($config) { + $base = $config->get('Cache.SerializerPath'); $base = is_null($base) ? HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer' : $base; return $base; } - + /** * Convenience wrapper function for file_put_contents * @param $file File name to write to * @param $data Data to write into file * @return Number of bytes written if success, or false if failure. */ - function _write($file, $data) { - static $file_put_contents; - if ($file_put_contents === null) { - $file_put_contents = function_exists('file_put_contents'); - } - if ($file_put_contents) { - return file_put_contents($file, $data); - } - $fh = fopen($file, 'w'); - if (!$fh) return false; - $status = fwrite($fh, $data); - fclose($fh); - return $status; + private function _write($file, $data) { + return file_put_contents($file, $data); } - + /** * Prepares the directory that this type stores the serials in * @return True if successful */ - function _prepareDir($config) { + private function _prepareDir($config) { $directory = $this->generateDirectoryPath($config); if (!is_dir($directory)) { $base = $this->generateBaseDirectoryPath($config); if (!is_dir($base)) { trigger_error('Base directory '.$base.' does not exist, please create or change using %Cache.SerializerPath', - E_USER_ERROR); + E_USER_WARNING); return false; } elseif (!$this->_testPermissions($base)) { return false; } + $old = umask(0022); // disable group and world writes mkdir($directory); + umask($old); } elseif (!$this->_testPermissions($directory)) { return false; } return true; } - + /** * Tests permissions on a directory and throws out friendly * error messages and attempts to chmod it itself if possible */ - function _testPermissions($dir) { + private function _testPermissions($dir) { // early abort, if it is writable, everything is hunky-dory if (is_writable($dir)) return true; if (!is_dir($dir)) { // generally, you'll want to handle this beforehand // so a more specific error message can be given trigger_error('Directory '.$dir.' does not exist', - E_USER_ERROR); + E_USER_WARNING); return false; } if (function_exists('posix_getuid')) { @@ -176,15 +157,16 @@ class HTMLPurifier_DefinitionCache_Serializer extends } trigger_error('Directory '.$dir.' not writable, '. 'please chmod to ' . $chmod, - E_USER_ERROR); + E_USER_WARNING); } else { // generic error message trigger_error('Directory '.$dir.' not writable, '. 'please alter file permissions', - E_USER_ERROR); + E_USER_WARNING); } return false; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer/README b/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer/README new file mode 100644 index 00000000000..2e35c1c3d06 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer/README @@ -0,0 +1,3 @@ +This is a dummy file to prevent Git from ignoring this empty directory. + + vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php b/lib/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php index dead92a32e9..a6ead628187 100644 --- a/lib/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php +++ b/lib/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php @@ -1,44 +1,26 @@ array()); - var $implementations = array(); - var $decorators = array(); - + + protected $caches = array('Serializer' => array()); + protected $implementations = array(); + protected $decorators = array(); + /** * Initialize default decorators */ - function setup() { + public function setup() { $this->addDecorator('Cleanup'); } - + /** * Retrieves an instance of global definition cache factory. - * @static */ - function &instance($prototype = null) { + public static function instance($prototype = null) { static $instance; if ($prototype !== null) { $instance = $prototype; @@ -48,33 +30,32 @@ class HTMLPurifier_DefinitionCacheFactory } return $instance; } - + /** * Registers a new definition cache object * @param $short Short name of cache object, for reference - * @param $long Full class name of cache object, for construction + * @param $long Full class name of cache object, for construction */ - function register($short, $long) { + public function register($short, $long) { $this->implementations[$short] = $long; } - + /** * Factory method that creates a cache object based on configuration * @param $name Name of definitions handled by cache * @param $config Instance of HTMLPurifier_Config */ - function &create($type, $config) { - $method = $config->get('Cache', 'DefinitionImpl'); + public function create($type, $config) { + $method = $config->get('Cache.DefinitionImpl'); if ($method === null) { - $null = new HTMLPurifier_DefinitionCache_Null($type); - return $null; + return new HTMLPurifier_DefinitionCache_Null($type); } if (!empty($this->caches[$method][$type])) { return $this->caches[$method][$type]; } if ( isset($this->implementations[$method]) && - class_exists($class = $this->implementations[$method]) + class_exists($class = $this->implementations[$method], false) ) { $cache = new $class($type); } else { @@ -92,18 +73,19 @@ class HTMLPurifier_DefinitionCacheFactory $this->caches[$method][$type] = $cache; return $this->caches[$method][$type]; } - + /** * Registers a decorator to add to all new cache objects - * @param + * @param */ - function addDecorator($decorator) { + public function addDecorator($decorator) { if (is_string($decorator)) { $class = "HTMLPurifier_DefinitionCache_Decorator_$decorator"; $decorator = new $class; } $this->decorators[$decorator->name] = $decorator; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/Doctype.php b/lib/htmlpurifier/HTMLPurifier/Doctype.php index 7afdcd74a2a..1e3c574c065 100644 --- a/lib/htmlpurifier/HTMLPurifier/Doctype.php +++ b/lib/htmlpurifier/HTMLPurifier/Doctype.php @@ -11,40 +11,40 @@ class HTMLPurifier_Doctype /** * Full name of doctype */ - var $name; - + public $name; + /** * List of standard modules (string identifiers or literal objects) * that this doctype uses */ - var $modules = array(); - + public $modules = array(); + /** * List of modules to use for tidying up code */ - var $tidyModules = array(); - + public $tidyModules = array(); + /** * Is the language derived from XML (i.e. XHTML)? */ - var $xml = true; - + public $xml = true; + /** * List of aliases for this doctype */ - var $aliases = array(); - + public $aliases = array(); + /** * Public DTD identifier */ - var $dtdPublic; - + public $dtdPublic; + /** * System DTD identifier */ - var $dtdSystem; - - function HTMLPurifier_Doctype($name = null, $xml = true, $modules = array(), + public $dtdSystem; + + public function __construct($name = null, $xml = true, $modules = array(), $tidyModules = array(), $aliases = array(), $dtd_public = null, $dtd_system = null ) { $this->name = $name; @@ -55,12 +55,6 @@ class HTMLPurifier_Doctype $this->dtdPublic = $dtd_public; $this->dtdSystem = $dtd_system; } - - /** - * Clones the doctype, use before resolving modes and the like - */ - function copy() { - return unserialize(serialize($this)); - } } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/DoctypeRegistry.php b/lib/htmlpurifier/HTMLPurifier/DoctypeRegistry.php index e657b3da4b1..86049e9391b 100644 --- a/lib/htmlpurifier/HTMLPurifier/DoctypeRegistry.php +++ b/lib/htmlpurifier/HTMLPurifier/DoctypeRegistry.php @@ -1,38 +1,18 @@ doctypes[$doctype->name] =& $doctype; + $this->doctypes[$doctype->name] = $doctype; $name = $doctype->name; // hookup aliases foreach ($doctype->aliases as $alias) { @@ -65,15 +45,15 @@ class HTMLPurifier_DoctypeRegistry if (isset($this->aliases[$name])) unset($this->aliases[$name]); return $doctype; } - + /** * Retrieves reference to a doctype of a certain name * @note This function resolves aliases * @note When possible, use the more fully-featured make() * @param $doctype Name of doctype - * @return Reference to doctype object + * @return Editable doctype object */ - function &get($doctype) { + public function get($doctype) { if (isset($this->aliases[$doctype])) $doctype = $this->aliases[$doctype]; if (!isset($this->doctypes[$doctype])) { trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist', E_USER_ERROR); @@ -82,7 +62,7 @@ class HTMLPurifier_DoctypeRegistry } return $this->doctypes[$doctype]; } - + /** * Creates a doctype based on a configuration object, * will perform initialization on the doctype @@ -91,34 +71,33 @@ class HTMLPurifier_DoctypeRegistry * Generator whether or not the current document is XML * based or not). */ - function make($config) { - $original_doctype = $this->get($this->getDoctypeFromConfig($config)); - $doctype = $original_doctype->copy(); - return $doctype; + public function make($config) { + return clone $this->get($this->getDoctypeFromConfig($config)); } - + /** * Retrieves the doctype from the configuration object */ - function getDoctypeFromConfig($config) { + public function getDoctypeFromConfig($config) { // recommended test - $doctype = $config->get('HTML', 'Doctype'); + $doctype = $config->get('HTML.Doctype'); if (!empty($doctype)) return $doctype; - $doctype = $config->get('HTML', 'CustomDoctype'); + $doctype = $config->get('HTML.CustomDoctype'); if (!empty($doctype)) return $doctype; // backwards-compatibility - if ($config->get('HTML', 'XHTML')) { + if ($config->get('HTML.XHTML')) { $doctype = 'XHTML 1.0'; } else { $doctype = 'HTML 4.01'; } - if ($config->get('HTML', 'Strict')) { + if ($config->get('HTML.Strict')) { $doctype .= ' Strict'; } else { $doctype .= ' Transitional'; } return $doctype; } - + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ElementDef.php b/lib/htmlpurifier/HTMLPurifier/ElementDef.php index b6439d1a5b6..5498d956704 100644 --- a/lib/htmlpurifier/HTMLPurifier/ElementDef.php +++ b/lib/htmlpurifier/HTMLPurifier/ElementDef.php @@ -5,16 +5,18 @@ * HTMLPurifier_HTMLDefinition and HTMLPurifier_HTMLModule. * @note This class is inspected by HTMLPurifier_Printer_HTMLDefinition. * Please update that class too. + * @warning If you add new properties to this class, you MUST update + * the mergeIn() method. */ class HTMLPurifier_ElementDef { - + /** * Does the definition work by itself, or is it created solely * for the purpose of merging into another definition? */ - var $standalone = true; - + public $standalone = true; + /** * Associative array of attribute name to HTMLPurifier_AttrDef * @note Before being processed by HTMLPurifier_AttrCollections @@ -25,68 +27,58 @@ class HTMLPurifier_ElementDef * contain string indentifiers in lieu of HTMLPurifier_AttrDef, * see HTMLPurifier_AttrTypes on how they are expanded during * HTMLPurifier_HTMLDefinition->setup() processing. - * @public */ - var $attr = array(); - + public $attr = array(); + /** * Indexed list of tag's HTMLPurifier_AttrTransform to be done before validation - * @public */ - var $attr_transform_pre = array(); - + public $attr_transform_pre = array(); + /** * Indexed list of tag's HTMLPurifier_AttrTransform to be done after validation - * @public */ - var $attr_transform_post = array(); - - - + public $attr_transform_post = array(); + /** * HTMLPurifier_ChildDef of this tag. - * @public */ - var $child; - + public $child; + /** * Abstract string representation of internal ChildDef rules. See * HTMLPurifier_ContentSets for how this is parsed and then transformed * into an HTMLPurifier_ChildDef. * @warning This is a temporary variable that is not available after * being processed by HTMLDefinition - * @public */ - var $content_model; - + public $content_model; + /** * Value of $child->type, used to determine which ChildDef to use, * used in combination with $content_model. * @warning This must be lowercase * @warning This is a temporary variable that is not available after * being processed by HTMLDefinition - * @public */ - var $content_model_type; - - - + public $content_model_type; + + + /** * Does the element have a content model (#PCDATA | Inline)*? This - * is important for chameleon ins and del processing in + * is important for chameleon ins and del processing in * HTMLPurifier_ChildDef_Chameleon. Dynamically set: modules don't * have to worry about this one. - * @public */ - var $descendants_are_inline = false; - + public $descendants_are_inline = false; + /** * List of the names of required attributes this element has. Dynamically * populated by HTMLPurifier_HTMLDefinition::getElement - * @public */ - var $required_attr = array(); - + public $required_attr = array(); + /** * Lookup table of tags excluded from all descendants of this tag. * @note SGML permits exclusions for all descendants, but this is @@ -97,35 +89,45 @@ class HTMLPurifier_ElementDef * all descendants and not just children. Note that the XHTML * Modularization Abstract Modules are blithely unaware of such * distinctions. - * @public */ - var $excludes = array(); - + public $excludes = array(); + /** - * Is this element safe for untrusted users to use? + * This tag is explicitly auto-closed by the following tags. */ - var $safe; - + public $autoclose = array(); + + /** + * If a foreign element is found in this element, test if it is + * allowed by this sub-element; if it is, instead of closing the + * current element, place it inside this element. + */ + public $wrap; + + /** + * Whether or not this is a formatting element affected by the + * "Active Formatting Elements" algorithm. + */ + public $formatting; + /** * Low-level factory constructor for creating new standalone element defs - * @static */ - function create($safe, $content_model, $content_model_type, $attr) { + public static function create($content_model, $content_model_type, $attr) { $def = new HTMLPurifier_ElementDef(); - $def->safe = (bool) $safe; $def->content_model = $content_model; $def->content_model_type = $content_model_type; $def->attr = $attr; return $def; } - + /** * Merges the values of another element definition into this one. * Values from the new element def take precedence if a value is * not mergeable. */ - function mergeIn($def) { - + public function mergeIn($def) { + // later keys takes precedence foreach($def->attr as $k => $v) { if ($k === 0) { @@ -145,9 +147,10 @@ class HTMLPurifier_ElementDef $this->_mergeAssocArray($this->attr_transform_pre, $def->attr_transform_pre); $this->_mergeAssocArray($this->attr_transform_post, $def->attr_transform_post); $this->_mergeAssocArray($this->excludes, $def->excludes); - + if(!empty($def->content_model)) { - $this->content_model .= ' | ' . $def->content_model; + $this->content_model = + str_replace("#SUPER", $this->content_model, $def->content_model); $this->child = false; } if(!empty($def->content_model_type)) { @@ -155,17 +158,17 @@ class HTMLPurifier_ElementDef $this->child = false; } if(!is_null($def->child)) $this->child = $def->child; + if(!is_null($def->formatting)) $this->formatting = $def->formatting; if($def->descendants_are_inline) $this->descendants_are_inline = $def->descendants_are_inline; - if(!is_null($def->safe)) $this->safe = $def->safe; - + } - + /** * Merges one array into another, removes values which equal false * @param $a1 Array by reference that is merged into * @param $a2 Array that merges into $a1 */ - function _mergeAssocArray(&$a1, $a2) { + private function _mergeAssocArray(&$a1, $a2) { foreach ($a2 as $k => $v) { if ($v === false) { if (isset($a1[$k])) unset($a1[$k]); @@ -174,14 +177,7 @@ class HTMLPurifier_ElementDef $a1[$k] = $v; } } - - /** - * Retrieves a copy of the element definition - */ - function copy() { - return unserialize(serialize($this)); - } - + } - +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/Encoder.php b/lib/htmlpurifier/HTMLPurifier/Encoder.php index 4ec736066c7..2b3140caaf5 100644 --- a/lib/htmlpurifier/HTMLPurifier/Encoder.php +++ b/lib/htmlpurifier/HTMLPurifier/Encoder.php @@ -1,86 +1,36 @@ feature '. - 'that automatically resolves all entities), making it pretty useless '. - 'for anything except the most I18N-blind applications, although '. - '%Core.EscapeNonASCIICharacters offers fixes this trouble with '. - 'another tradeoff. This directive '. - 'only accepts ISO-8859-1 if iconv is not enabled.' -); - -HTMLPurifier_ConfigSchema::define( - 'Core', 'EscapeNonASCIICharacters', false, 'bool', - 'This directive overcomes a deficiency in %Core.Encoding by blindly '. - 'converting all non-ASCII characters into decimal numeric entities before '. - 'converting it to its native encoding. This means that even '. - 'characters that can be expressed in the non-UTF-8 encoding will '. - 'be entity-ized, which can be a real downer for encodings like Big5. '. - 'It also assumes that the ASCII repetoire is available, although '. - 'this is the case for almost all encodings. Anyway, use UTF-8! This '. - 'directive has been available since 1.4.0.' -); - -if ( !function_exists('iconv') ) { - // only encodings with native PHP support - HTMLPurifier_ConfigSchema::defineAllowedValues( - 'Core', 'Encoding', array( - 'utf-8', - 'iso-8859-1' - ) - ); - HTMLPurifier_ConfigSchema::defineValueAliases( - 'Core', 'Encoding', array( - 'iso8859-1' => 'iso-8859-1' - ) - ); -} - -HTMLPurifier_ConfigSchema::define( - 'Test', 'ForceNoIconv', false, 'bool', - 'When set to true, HTMLPurifier_Encoder will act as if iconv does not '. - 'exist and use only pure PHP implementations.' -); - /** * A UTF-8 specific character encoder that handles cleaning and transforming. * @note All functions in this class should be static. */ class HTMLPurifier_Encoder { - + /** * Constructor throws fatal error if you attempt to instantiate class */ - function HTMLPurifier_Encoder() { + private function __construct() { trigger_error('Cannot instantiate encoder, call methods statically', E_USER_ERROR); } - + /** * Error-handler that mutes errors, alternative to shut-up operator. */ - function muteErrorHandler() {} - - /** + public static function muteErrorHandler() {} + /** * Cleans a UTF-8 string for well-formedness and SGML validity - * + * * It will parse according to UTF-8 and return a valid UTF8 string, with * non-SGML codepoints excluded. - * - * @static + * * @note Just for reference, the non-SGML code points are 0 to 31 and * 127 to 159, inclusive. However, we allow code points 9, 10 * and 13, which are the tab, line feed and carriage return * respectively. 128 and above the code points map to multibyte * UTF-8 representations. - * + * * @note Fallback code adapted from utf8ToUnicode by Henri Sivonen and * hsivonen@iki.fi at' . $this->locale->getMessage('ErrorCollector: No errors') . '
'; } else { return ''; + //$string .= ''; + //$string .= ''; + $ret[] = $string; + } + foreach ($current->children as $type => $array) { + $context[] = $current; + $stack = array_merge($stack, array_reverse($array, true)); + for ($i = count($array); $i > 0; $i--) { + $context_stack[] = $context; + } + } + } + } + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/ErrorStruct.php b/lib/htmlpurifier/HTMLPurifier/ErrorStruct.php new file mode 100644 index 00000000000..9bc8996ec19 --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/ErrorStruct.php @@ -0,0 +1,60 @@ +children[$type][$id])) { + $this->children[$type][$id] = new HTMLPurifier_ErrorStruct(); + $this->children[$type][$id]->type = $type; + } + return $this->children[$type][$id]; + } + + public function addError($severity, $message) { + $this->errors[] = array($severity, $message); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/Exception.php b/lib/htmlpurifier/HTMLPurifier/Exception.php new file mode 100644 index 00000000000..be85b4c560e --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/Exception.php @@ -0,0 +1,12 @@ +preFilter, * 2->preFilter, 3->preFilter, purify, 3->postFilter, 2->postFilter, * 1->postFilter. + * + * @note Methods are not declared abstract as it is perfectly legitimate + * for an implementation not to want anything to happen on a step */ class HTMLPurifier_Filter { - + /** * Name of the filter for identification purposes */ - var $name; - + public $name; + /** - * Pre-processor function, handles HTML before HTML Purifier + * Pre-processor function, handles HTML before HTML Purifier */ - function preFilter($html, $config, &$context) {} - + public function preFilter($html, $config, $context) { + return $html; + } + /** * Post-processor function, handles HTML after HTML Purifier */ - function postFilter($html, $config, &$context) {} - + public function postFilter($html, $config, $context) { + return $html; + } + } +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php b/lib/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php new file mode 100644 index 00000000000..bbf78a6630a --- /dev/null +++ b/lib/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php @@ -0,0 +1,135 @@ + blocks from input HTML, cleans them up + * using CSSTidy, and then places them in $purifier->context->get('StyleBlocks') + * so they can be used elsewhere in the document. + * + * @note + * See tests/HTMLPurifier/Filter/ExtractStyleBlocksTest.php for + * sample usage. + * + * @note + * This filter can also be used on stylesheets not included in the + * document--something purists would probably prefer. Just directly + * call HTMLPurifier_Filter_ExtractStyleBlocks->cleanCSS() + */ +class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter +{ + + public $name = 'ExtractStyleBlocks'; + private $_styleMatches = array(); + private $_tidy; + + public function __construct() { + $this->_tidy = new csstidy(); + } + + /** + * Save the contents of CSS blocks to style matches + * @param $matches preg_replace style $matches array + */ + protected function styleCallback($matches) { + $this->_styleMatches[] = $matches[1]; + } + + /** + * Removes inline #isU', array($this, 'styleCallback'), $html); + $style_blocks = $this->_styleMatches; + $this->_styleMatches = array(); // reset + $context->register('StyleBlocks', $style_blocks); // $context must not be reused + if ($this->_tidy) { + foreach ($style_blocks as &$style) { + $style = $this->cleanCSS($style, $config, $context); + } + } + return $html; + } + + /** + * Takes CSS (the stuff found in in a font-family prop). + if ($config->get('Filter.ExtractStyleBlocks.Escaping')) { + $css = str_replace( + array('<', '>', '&'), + array('\3C ', '\3E ', '\26 '), + $css + ); + } + return $css; + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/HTMLPurifier/Filter/YouTube.php b/lib/htmlpurifier/HTMLPurifier/Filter/YouTube.php index 4f63ad6d560..23df221eaa3 100644 --- a/lib/htmlpurifier/HTMLPurifier/Filter/YouTube.php +++ b/lib/htmlpurifier/HTMLPurifier/Filter/YouTube.php @@ -1,33 +1,39 @@ ]+>.+?'. - 'http://www.youtube.com/v/([A-Za-z0-9\-_]+).+?#s'; + 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?#s'; $pre_replace = ''; return preg_replace($pre_regex, $pre_replace, $html); } - - function postFilter($html, $config, &$context) { - $post_regex = '##'; - $post_replace = '