htmlpurifier 4.7 버전 적용

This commit is contained in:
chicpro
2015-10-20 11:06:15 +09:00
parent 353a0d9409
commit 9bf15fdf32
144 changed files with 31041 additions and 25389 deletions

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,12 @@
class HTMLPurifier_ConfigSchema_Builder_ConfigSchema class HTMLPurifier_ConfigSchema_Builder_ConfigSchema
{ {
public function build($interchange) { /**
* @param HTMLPurifier_ConfigSchema_Interchange $interchange
* @return HTMLPurifier_ConfigSchema
*/
public function build($interchange)
{
$schema = new HTMLPurifier_ConfigSchema(); $schema = new HTMLPurifier_ConfigSchema();
foreach ($interchange->directives as $d) { foreach ($interchange->directives as $d) {
$schema->add( $schema->add(
@ -38,7 +43,6 @@ class HTMLPurifier_ConfigSchema_Builder_ConfigSchema
$schema->postProcess(); $schema->postProcess();
return $schema; return $schema;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -7,10 +7,21 @@
class HTMLPurifier_ConfigSchema_Builder_Xml extends XMLWriter class HTMLPurifier_ConfigSchema_Builder_Xml extends XMLWriter
{ {
/**
* @type HTMLPurifier_ConfigSchema_Interchange
*/
protected $interchange; protected $interchange;
/**
* @type string
*/
private $namespace; private $namespace;
protected function writeHTMLDiv($html) { /**
* @param string $html
*/
protected function writeHTMLDiv($html)
{
$this->startElement('div'); $this->startElement('div');
$purifier = HTMLPurifier::getInstance(); $purifier = HTMLPurifier::getInstance();
@ -21,12 +32,23 @@ class HTMLPurifier_ConfigSchema_Builder_Xml extends XMLWriter
$this->endElement(); // div $this->endElement(); // div
} }
protected function export($var) { /**
if ($var === array()) return 'array()'; * @param mixed $var
* @return string
*/
protected function export($var)
{
if ($var === array()) {
return 'array()';
}
return var_export($var, true); return var_export($var, true);
} }
public function build($interchange) { /**
* @param HTMLPurifier_ConfigSchema_Interchange $interchange
*/
public function build($interchange)
{
// global access, only use as last resort // global access, only use as last resort
$this->interchange = $interchange; $this->interchange = $interchange;
@ -39,19 +61,26 @@ class HTMLPurifier_ConfigSchema_Builder_Xml extends XMLWriter
$this->buildDirective($directive); $this->buildDirective($directive);
} }
if ($this->namespace) $this->endElement(); // namespace if ($this->namespace) {
$this->endElement();
} // namespace
$this->endElement(); // configdoc $this->endElement(); // configdoc
$this->flush(); $this->flush();
} }
public function buildDirective($directive) { /**
* @param HTMLPurifier_ConfigSchema_Interchange_Directive $directive
*/
public function buildDirective($directive)
{
// Kludge, although I suppose having a notion of a "root namespace" // Kludge, although I suppose having a notion of a "root namespace"
// certainly makes things look nicer when documentation is built. // certainly makes things look nicer when documentation is built.
// Depends on things being sorted. // Depends on things being sorted.
if (!$this->namespace || $this->namespace !== $directive->id->getRootNamespace()) { if (!$this->namespace || $this->namespace !== $directive->id->getRootNamespace()) {
if ($this->namespace) $this->endElement(); // namespace if ($this->namespace) {
$this->endElement();
} // namespace
$this->namespace = $directive->id->getRootNamespace(); $this->namespace = $directive->id->getRootNamespace();
$this->startElement('namespace'); $this->startElement('namespace');
$this->writeAttribute('id', $this->namespace); $this->writeAttribute('id', $this->namespace);
@ -64,43 +93,52 @@ class HTMLPurifier_ConfigSchema_Builder_Xml extends XMLWriter
$this->writeElement('name', $directive->id->getDirective()); $this->writeElement('name', $directive->id->getDirective());
$this->startElement('aliases'); $this->startElement('aliases');
foreach ($directive->aliases as $alias) $this->writeElement('alias', $alias->toString()); foreach ($directive->aliases as $alias) {
$this->writeElement('alias', $alias->toString());
}
$this->endElement(); // aliases $this->endElement(); // aliases
$this->startElement('constraints'); $this->startElement('constraints');
if ($directive->version) $this->writeElement('version', $directive->version); if ($directive->version) {
$this->startElement('type'); $this->writeElement('version', $directive->version);
if ($directive->typeAllowsNull) $this->writeAttribute('allow-null', 'yes'); }
$this->text($directive->type); $this->startElement('type');
$this->endElement(); // type if ($directive->typeAllowsNull) {
if ($directive->allowed) { $this->writeAttribute('allow-null', 'yes');
$this->startElement('allowed'); }
foreach ($directive->allowed as $value => $x) $this->writeElement('value', $value); $this->text($directive->type);
$this->endElement(); // allowed $this->endElement(); // type
if ($directive->allowed) {
$this->startElement('allowed');
foreach ($directive->allowed as $value => $x) {
$this->writeElement('value', $value);
} }
$this->writeElement('default', $this->export($directive->default)); $this->endElement(); // allowed
$this->writeAttribute('xml:space', 'preserve'); }
if ($directive->external) { $this->writeElement('default', $this->export($directive->default));
$this->startElement('external'); $this->writeAttribute('xml:space', 'preserve');
foreach ($directive->external as $project) $this->writeElement('project', $project); if ($directive->external) {
$this->endElement(); $this->startElement('external');
foreach ($directive->external as $project) {
$this->writeElement('project', $project);
} }
$this->endElement();
}
$this->endElement(); // constraints $this->endElement(); // constraints
if ($directive->deprecatedVersion) { if ($directive->deprecatedVersion) {
$this->startElement('deprecated'); $this->startElement('deprecated');
$this->writeElement('version', $directive->deprecatedVersion); $this->writeElement('version', $directive->deprecatedVersion);
$this->writeElement('use', $directive->deprecatedUse->toString()); $this->writeElement('use', $directive->deprecatedUse->toString());
$this->endElement(); // deprecated $this->endElement(); // deprecated
} }
$this->startElement('description'); $this->startElement('description');
$this->writeHTMLDiv($directive->description); $this->writeHTMLDiv($directive->description);
$this->endElement(); // description $this->endElement(); // description
$this->endElement(); // directive $this->endElement(); // directive
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -10,18 +10,23 @@ class HTMLPurifier_ConfigSchema_Interchange
/** /**
* Name of the application this schema is describing. * Name of the application this schema is describing.
* @type string
*/ */
public $name; public $name;
/** /**
* Array of Directive ID => array(directive info) * Array of Directive ID => array(directive info)
* @type HTMLPurifier_ConfigSchema_Interchange_Directive[]
*/ */
public $directives = array(); public $directives = array();
/** /**
* Adds a directive array to $directives * Adds a directive array to $directives
* @param HTMLPurifier_ConfigSchema_Interchange_Directive $directive
* @throws HTMLPurifier_ConfigSchema_Exception
*/ */
public function addDirective($directive) { public function addDirective($directive)
{
if (isset($this->directives[$i = $directive->id->toString()])) { if (isset($this->directives[$i = $directive->id->toString()])) {
throw new HTMLPurifier_ConfigSchema_Exception("Cannot redefine directive '$i'"); throw new HTMLPurifier_ConfigSchema_Exception("Cannot redefine directive '$i'");
} }
@ -32,11 +37,11 @@ class HTMLPurifier_ConfigSchema_Interchange
* Convenience function to perform standard validation. Throws exception * Convenience function to perform standard validation. Throws exception
* on failed validation. * on failed validation.
*/ */
public function validate() { public function validate()
{
$validator = new HTMLPurifier_ConfigSchema_Validator(); $validator = new HTMLPurifier_ConfigSchema_Validator();
return $validator->validate($this); return $validator->validate($this);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -7,71 +7,83 @@ class HTMLPurifier_ConfigSchema_Interchange_Directive
{ {
/** /**
* ID of directive, instance of HTMLPurifier_ConfigSchema_Interchange_Id. * ID of directive.
* @type HTMLPurifier_ConfigSchema_Interchange_Id
*/ */
public $id; public $id;
/** /**
* String type, e.g. 'integer' or 'istring'. * Type, e.g. 'integer' or 'istring'.
* @type string
*/ */
public $type; public $type;
/** /**
* Default value, e.g. 3 or 'DefaultVal'. * Default value, e.g. 3 or 'DefaultVal'.
* @type mixed
*/ */
public $default; public $default;
/** /**
* HTML description. * HTML description.
* @type string
*/ */
public $description; public $description;
/** /**
* Boolean whether or not null is allowed as a value. * Whether or not null is allowed as a value.
* @type bool
*/ */
public $typeAllowsNull = false; public $typeAllowsNull = false;
/** /**
* Lookup table of allowed scalar values, e.g. array('allowed' => true). * Lookup table of allowed scalar values.
* e.g. array('allowed' => true).
* Null if all values are allowed. * Null if all values are allowed.
* @type array
*/ */
public $allowed; public $allowed;
/** /**
* List of aliases for the directive, * List of aliases for the directive.
* e.g. array(new HTMLPurifier_ConfigSchema_Interchange_Id('Ns', 'Dir'))). * e.g. array(new HTMLPurifier_ConfigSchema_Interchange_Id('Ns', 'Dir'))).
* @type HTMLPurifier_ConfigSchema_Interchange_Id[]
*/ */
public $aliases = array(); public $aliases = array();
/** /**
* Hash of value aliases, e.g. array('alt' => 'real'). Null if value * Hash of value aliases, e.g. array('alt' => 'real'). Null if value
* aliasing is disabled (necessary for non-scalar types). * aliasing is disabled (necessary for non-scalar types).
* @type array
*/ */
public $valueAliases; public $valueAliases;
/** /**
* Version of HTML Purifier the directive was introduced, e.g. '1.3.1'. * Version of HTML Purifier the directive was introduced, e.g. '1.3.1'.
* Null if the directive has always existed. * Null if the directive has always existed.
* @type string
*/ */
public $version; public $version;
/** /**
* ID of directive that supercedes this old directive, is an instance * ID of directive that supercedes this old directive.
* of HTMLPurifier_ConfigSchema_Interchange_Id. Null if not deprecated. * Null if not deprecated.
* @type HTMLPurifier_ConfigSchema_Interchange_Id
*/ */
public $deprecatedUse; public $deprecatedUse;
/** /**
* Version of HTML Purifier this directive was deprecated. Null if not * Version of HTML Purifier this directive was deprecated. Null if not
* deprecated. * deprecated.
* @type string
*/ */
public $deprecatedVersion; public $deprecatedVersion;
/** /**
* List of external projects this directive depends on, e.g. array('CSSTidy'). * List of external projects this directive depends on, e.g. array('CSSTidy').
* @type array
*/ */
public $external = array(); public $external = array();
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -6,32 +6,53 @@
class HTMLPurifier_ConfigSchema_Interchange_Id class HTMLPurifier_ConfigSchema_Interchange_Id
{ {
/**
* @type string
*/
public $key; public $key;
public function __construct($key) { /**
* @param string $key
*/
public function __construct($key)
{
$this->key = $key; $this->key = $key;
} }
/** /**
* @return string
* @warning This is NOT magic, to ensure that people don't abuse SPL and * @warning This is NOT magic, to ensure that people don't abuse SPL and
* cause problems for PHP 5.0 support. * cause problems for PHP 5.0 support.
*/ */
public function toString() { public function toString()
{
return $this->key; return $this->key;
} }
public function getRootNamespace() { /**
* @return string
*/
public function getRootNamespace()
{
return substr($this->key, 0, strpos($this->key, ".")); return substr($this->key, 0, strpos($this->key, "."));
} }
public function getDirective() { /**
* @return string
*/
public function getDirective()
{
return substr($this->key, strpos($this->key, ".") + 1); return substr($this->key, strpos($this->key, ".") + 1);
} }
public static function make($id) { /**
* @param string $id
* @return HTMLPurifier_ConfigSchema_Interchange_Id
*/
public static function make($id)
{
return new HTMLPurifier_ConfigSchema_Interchange_Id($id); return new HTMLPurifier_ConfigSchema_Interchange_Id($id);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -5,21 +5,39 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
/** /**
* Used for processing DEFAULT, nothing else. * Used for processing DEFAULT, nothing else.
* @type HTMLPurifier_VarParser
*/ */
protected $varParser; protected $varParser;
public function __construct($varParser = null) { /**
* @param HTMLPurifier_VarParser $varParser
*/
public function __construct($varParser = null)
{
$this->varParser = $varParser ? $varParser : new HTMLPurifier_VarParser_Native(); $this->varParser = $varParser ? $varParser : new HTMLPurifier_VarParser_Native();
} }
public static function buildFromDirectory($dir = null) { /**
$builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder(); * @param string $dir
* @return HTMLPurifier_ConfigSchema_Interchange
*/
public static function buildFromDirectory($dir = null)
{
$builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder();
$interchange = new HTMLPurifier_ConfigSchema_Interchange(); $interchange = new HTMLPurifier_ConfigSchema_Interchange();
return $builder->buildDir($interchange, $dir); return $builder->buildDir($interchange, $dir);
} }
public function buildDir($interchange, $dir = null) { /**
if (!$dir) $dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema'; * @param HTMLPurifier_ConfigSchema_Interchange $interchange
* @param string $dir
* @return HTMLPurifier_ConfigSchema_Interchange
*/
public function buildDir($interchange, $dir = null)
{
if (!$dir) {
$dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema';
}
if (file_exists($dir . '/info.ini')) { if (file_exists($dir . '/info.ini')) {
$info = parse_ini_file($dir . '/info.ini'); $info = parse_ini_file($dir . '/info.ini');
$interchange->name = $info['name']; $interchange->name = $info['name'];
@ -39,24 +57,30 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
foreach ($files as $file) { foreach ($files as $file) {
$this->buildFile($interchange, $dir . '/' . $file); $this->buildFile($interchange, $dir . '/' . $file);
} }
return $interchange; return $interchange;
} }
public function buildFile($interchange, $file) { /**
* @param HTMLPurifier_ConfigSchema_Interchange $interchange
* @param string $file
*/
public function buildFile($interchange, $file)
{
$parser = new HTMLPurifier_StringHashParser(); $parser = new HTMLPurifier_StringHashParser();
$this->build( $this->build(
$interchange, $interchange,
new HTMLPurifier_StringHash( $parser->parseFile($file) ) new HTMLPurifier_StringHash($parser->parseFile($file))
); );
} }
/** /**
* Builds an interchange object based on a hash. * Builds an interchange object based on a hash.
* @param $interchange HTMLPurifier_ConfigSchema_Interchange object to build * @param HTMLPurifier_ConfigSchema_Interchange $interchange HTMLPurifier_ConfigSchema_Interchange object to build
* @param $hash HTMLPurifier_ConfigSchema_StringHash source data * @param HTMLPurifier_StringHash $hash source data
* @throws HTMLPurifier_ConfigSchema_Exception
*/ */
public function build($interchange, $hash) { public function build($interchange, $hash)
{
if (!$hash instanceof HTMLPurifier_StringHash) { if (!$hash instanceof HTMLPurifier_StringHash) {
$hash = new HTMLPurifier_StringHash($hash); $hash = new HTMLPurifier_StringHash($hash);
} }
@ -75,7 +99,13 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
$this->_findUnused($hash); $this->_findUnused($hash);
} }
public function buildDirective($interchange, $hash) { /**
* @param HTMLPurifier_ConfigSchema_Interchange $interchange
* @param HTMLPurifier_StringHash $hash
* @throws HTMLPurifier_ConfigSchema_Exception
*/
public function buildDirective($interchange, $hash)
{
$directive = new HTMLPurifier_ConfigSchema_Interchange_Directive(); $directive = new HTMLPurifier_ConfigSchema_Interchange_Directive();
// These are required elements: // These are required elements:
@ -84,7 +114,9 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
if (isset($hash['TYPE'])) { if (isset($hash['TYPE'])) {
$type = explode('/', $hash->offsetGet('TYPE')); $type = explode('/', $hash->offsetGet('TYPE'));
if (isset($type[1])) $directive->typeAllowsNull = true; if (isset($type[1])) {
$directive->typeAllowsNull = true;
}
$directive->type = $type[0]; $directive->type = $type[0];
} else { } else {
throw new HTMLPurifier_ConfigSchema_Exception("TYPE in directive hash '$id' not defined"); throw new HTMLPurifier_ConfigSchema_Exception("TYPE in directive hash '$id' not defined");
@ -92,7 +124,11 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
if (isset($hash['DEFAULT'])) { if (isset($hash['DEFAULT'])) {
try { try {
$directive->default = $this->varParser->parse($hash->offsetGet('DEFAULT'), $directive->type, $directive->typeAllowsNull); $directive->default = $this->varParser->parse(
$hash->offsetGet('DEFAULT'),
$directive->type,
$directive->typeAllowsNull
);
} catch (HTMLPurifier_VarParserException $e) { } catch (HTMLPurifier_VarParserException $e) {
throw new HTMLPurifier_ConfigSchema_Exception($e->getMessage() . " in DEFAULT in directive hash '$id'"); throw new HTMLPurifier_ConfigSchema_Exception($e->getMessage() . " in DEFAULT in directive hash '$id'");
} }
@ -139,34 +175,45 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
/** /**
* Evaluates an array PHP code string without array() wrapper * Evaluates an array PHP code string without array() wrapper
* @param string $contents
*/ */
protected function evalArray($contents) { protected function evalArray($contents)
return eval('return array('. $contents .');'); {
return eval('return array(' . $contents . ');');
} }
/** /**
* Converts an array list into a lookup array. * Converts an array list into a lookup array.
* @param array $array
* @return array
*/ */
protected function lookup($array) { protected function lookup($array)
{
$ret = array(); $ret = array();
foreach ($array as $val) $ret[$val] = true; foreach ($array as $val) {
$ret[$val] = true;
}
return $ret; return $ret;
} }
/** /**
* Convenience function that creates an HTMLPurifier_ConfigSchema_Interchange_Id * Convenience function that creates an HTMLPurifier_ConfigSchema_Interchange_Id
* object based on a string Id. * object based on a string Id.
* @param string $id
* @return HTMLPurifier_ConfigSchema_Interchange_Id
*/ */
protected function id($id) { protected function id($id)
{
return HTMLPurifier_ConfigSchema_Interchange_Id::make($id); return HTMLPurifier_ConfigSchema_Interchange_Id::make($id);
} }
/** /**
* Triggers errors for any unused keys passed in the hash; such keys * Triggers errors for any unused keys passed in the hash; such keys
* may indicate typos, missing values, etc. * may indicate typos, missing values, etc.
* @param $hash Instance of ConfigSchema_StringHash to check. * @param HTMLPurifier_StringHash $hash Hash to check.
*/ */
protected function _findUnused($hash) { protected function _findUnused($hash)
{
$accessed = $hash->getAccessed(); $accessed = $hash->getAccessed();
foreach ($hash as $k => $v) { foreach ($hash as $k => $v) {
if (!isset($accessed[$k])) { if (!isset($accessed[$k])) {
@ -174,7 +221,6 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
} }
} }
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -12,36 +12,48 @@ class HTMLPurifier_ConfigSchema_Validator
{ {
/** /**
* Easy to access global objects. * @type HTMLPurifier_ConfigSchema_Interchange
*/ */
protected $interchange, $aliases; protected $interchange;
/**
* @type array
*/
protected $aliases;
/** /**
* Context-stack to provide easy to read error messages. * Context-stack to provide easy to read error messages.
* @type array
*/ */
protected $context = array(); protected $context = array();
/** /**
* HTMLPurifier_VarParser to test default's type. * to test default's type.
* @type HTMLPurifier_VarParser
*/ */
protected $parser; protected $parser;
public function __construct() { public function __construct()
{
$this->parser = new HTMLPurifier_VarParser(); $this->parser = new HTMLPurifier_VarParser();
} }
/** /**
* Validates a fully-formed interchange object. Throws an * Validates a fully-formed interchange object.
* HTMLPurifier_ConfigSchema_Exception if there's a problem. * @param HTMLPurifier_ConfigSchema_Interchange $interchange
* @return bool
*/ */
public function validate($interchange) { public function validate($interchange)
{
$this->interchange = $interchange; $this->interchange = $interchange;
$this->aliases = array(); $this->aliases = array();
// PHP is a bit lax with integer <=> string conversions in // PHP is a bit lax with integer <=> string conversions in
// arrays, so we don't use the identical !== comparison // arrays, so we don't use the identical !== comparison
foreach ($interchange->directives as $i => $directive) { foreach ($interchange->directives as $i => $directive) {
$id = $directive->id->toString(); $id = $directive->id->toString();
if ($i != $id) $this->error(false, "Integrity violation: key '$i' does not match internal id '$id'"); if ($i != $id) {
$this->error(false, "Integrity violation: key '$i' does not match internal id '$id'");
}
$this->validateDirective($directive); $this->validateDirective($directive);
} }
return true; return true;
@ -49,8 +61,10 @@ class HTMLPurifier_ConfigSchema_Validator
/** /**
* Validates a HTMLPurifier_ConfigSchema_Interchange_Id object. * Validates a HTMLPurifier_ConfigSchema_Interchange_Id object.
* @param HTMLPurifier_ConfigSchema_Interchange_Id $id
*/ */
public function validateId($id) { public function validateId($id)
{
$id_string = $id->toString(); $id_string = $id->toString();
$this->context[] = "id '$id_string'"; $this->context[] = "id '$id_string'";
if (!$id instanceof HTMLPurifier_ConfigSchema_Interchange_Id) { if (!$id instanceof HTMLPurifier_ConfigSchema_Interchange_Id) {
@ -67,8 +81,10 @@ class HTMLPurifier_ConfigSchema_Validator
/** /**
* Validates a HTMLPurifier_ConfigSchema_Interchange_Directive object. * Validates a HTMLPurifier_ConfigSchema_Interchange_Directive object.
* @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
*/ */
public function validateDirective($d) { public function validateDirective($d)
{
$id = $d->id->toString(); $id = $d->id->toString();
$this->context[] = "directive '$id'"; $this->context[] = "directive '$id'";
$this->validateId($d->id); $this->validateId($d->id);
@ -108,9 +124,13 @@ class HTMLPurifier_ConfigSchema_Validator
/** /**
* Extra validation if $allowed member variable of * Extra validation if $allowed member variable of
* HTMLPurifier_ConfigSchema_Interchange_Directive is defined. * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
* @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
*/ */
public function validateDirectiveAllowed($d) { public function validateDirectiveAllowed($d)
if (is_null($d->allowed)) return; {
if (is_null($d->allowed)) {
return;
}
$this->with($d, 'allowed') $this->with($d, 'allowed')
->assertNotEmpty() ->assertNotEmpty()
->assertIsLookup(); // handled by InterchangeBuilder ->assertIsLookup(); // handled by InterchangeBuilder
@ -119,7 +139,9 @@ class HTMLPurifier_ConfigSchema_Validator
} }
$this->context[] = 'allowed'; $this->context[] = 'allowed';
foreach ($d->allowed as $val => $x) { foreach ($d->allowed as $val => $x) {
if (!is_string($val)) $this->error("value $val", 'must be a string'); if (!is_string($val)) {
$this->error("value $val", 'must be a string');
}
} }
array_pop($this->context); array_pop($this->context);
} }
@ -127,15 +149,23 @@ class HTMLPurifier_ConfigSchema_Validator
/** /**
* Extra validation if $valueAliases member variable of * Extra validation if $valueAliases member variable of
* HTMLPurifier_ConfigSchema_Interchange_Directive is defined. * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
* @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
*/ */
public function validateDirectiveValueAliases($d) { public function validateDirectiveValueAliases($d)
if (is_null($d->valueAliases)) return; {
if (is_null($d->valueAliases)) {
return;
}
$this->with($d, 'valueAliases') $this->with($d, 'valueAliases')
->assertIsArray(); // handled by InterchangeBuilder ->assertIsArray(); // handled by InterchangeBuilder
$this->context[] = 'valueAliases'; $this->context[] = 'valueAliases';
foreach ($d->valueAliases as $alias => $real) { foreach ($d->valueAliases as $alias => $real) {
if (!is_string($alias)) $this->error("alias $alias", 'must be a string'); if (!is_string($alias)) {
if (!is_string($real)) $this->error("alias target $real from alias '$alias'", 'must be a string'); $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) { if ($alias === $real) {
$this->error("alias '$alias'", "must not be an alias to itself"); $this->error("alias '$alias'", "must not be an alias to itself");
} }
@ -155,8 +185,10 @@ class HTMLPurifier_ConfigSchema_Validator
/** /**
* Extra validation if $aliases member variable of * Extra validation if $aliases member variable of
* HTMLPurifier_ConfigSchema_Interchange_Directive is defined. * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
* @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
*/ */
public function validateDirectiveAliases($d) { public function validateDirectiveAliases($d)
{
$this->with($d, 'aliases') $this->with($d, 'aliases')
->assertIsArray(); // handled by InterchangeBuilder ->assertIsArray(); // handled by InterchangeBuilder
$this->context[] = 'aliases'; $this->context[] = 'aliases';
@ -180,27 +212,37 @@ class HTMLPurifier_ConfigSchema_Validator
/** /**
* Convenience function for generating HTMLPurifier_ConfigSchema_ValidatorAtom * Convenience function for generating HTMLPurifier_ConfigSchema_ValidatorAtom
* for validating simple member variables of objects. * for validating simple member variables of objects.
* @param $obj
* @param $member
* @return HTMLPurifier_ConfigSchema_ValidatorAtom
*/ */
protected function with($obj, $member) { protected function with($obj, $member)
{
return new HTMLPurifier_ConfigSchema_ValidatorAtom($this->getFormattedContext(), $obj, $member); return new HTMLPurifier_ConfigSchema_ValidatorAtom($this->getFormattedContext(), $obj, $member);
} }
/** /**
* Emits an error, providing helpful context. * Emits an error, providing helpful context.
* @throws HTMLPurifier_ConfigSchema_Exception
*/ */
protected function error($target, $msg) { protected function error($target, $msg)
if ($target !== false) $prefix = ucfirst($target) . ' in ' . $this->getFormattedContext(); {
else $prefix = ucfirst($this->getFormattedContext()); if ($target !== false) {
$prefix = ucfirst($target) . ' in ' . $this->getFormattedContext();
} else {
$prefix = ucfirst($this->getFormattedContext());
}
throw new HTMLPurifier_ConfigSchema_Exception(trim($prefix . ' ' . $msg)); throw new HTMLPurifier_ConfigSchema_Exception(trim($prefix . ' ' . $msg));
} }
/** /**
* Returns a formatted context string. * Returns a formatted context string.
* @return string
*/ */
protected function getFormattedContext() { protected function getFormattedContext()
{
return implode(' in ', array_reverse($this->context)); return implode(' in ', array_reverse($this->context));
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -8,59 +8,123 @@
*/ */
class HTMLPurifier_ConfigSchema_ValidatorAtom class HTMLPurifier_ConfigSchema_ValidatorAtom
{ {
/**
* @type string
*/
protected $context;
protected $context, $obj, $member, $contents; /**
* @type object
*/
protected $obj;
public function __construct($context, $obj, $member) { /**
$this->context = $context; * @type string
$this->obj = $obj; */
$this->member = $member; protected $member;
$this->contents =& $obj->$member;
/**
* @type mixed
*/
protected $contents;
public function __construct($context, $obj, $member)
{
$this->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 HTMLPurifier_ConfigSchema_ValidatorAtom
return $this; */
} public function assertIsString()
{
public function assertIsBool() { if (!is_string($this->contents)) {
if (!is_bool($this->contents)) $this->error('must be a boolean'); $this->error('must be a string');
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; return $this;
} }
protected function error($msg) { /**
throw new HTMLPurifier_ConfigSchema_Exception(ucfirst($this->member) . ' in ' . $this->context . ' ' . $msg); * @return HTMLPurifier_ConfigSchema_ValidatorAtom
*/
public function assertIsBool()
{
if (!is_bool($this->contents)) {
$this->error('must be a boolean');
}
return $this;
} }
/**
* @return HTMLPurifier_ConfigSchema_ValidatorAtom
*/
public function assertIsArray()
{
if (!is_array($this->contents)) {
$this->error('must be an array');
}
return $this;
}
/**
* @return HTMLPurifier_ConfigSchema_ValidatorAtom
*/
public function assertNotNull()
{
if ($this->contents === null) {
$this->error('must not be null');
}
return $this;
}
/**
* @return HTMLPurifier_ConfigSchema_ValidatorAtom
*/
public function assertAlnum()
{
$this->assertIsString();
if (!ctype_alnum($this->contents)) {
$this->error('must be alphanumeric');
}
return $this;
}
/**
* @return HTMLPurifier_ConfigSchema_ValidatorAtom
*/
public function assertNotEmpty()
{
if (empty($this->contents)) {
$this->error('must not be empty');
}
return $this;
}
/**
* @return HTMLPurifier_ConfigSchema_ValidatorAtom
*/
public function assertIsLookup()
{
$this->assertIsArray();
foreach ($this->contents as $v) {
if ($v !== true) {
$this->error('must be a lookup array');
}
}
return $this;
}
/**
* @param string $msg
* @throws HTMLPurifier_ConfigSchema_Exception
*/
protected function error($msg)
{
throw new HTMLPurifier_ConfigSchema_Exception(ucfirst($this->member) . ' in ' . $this->context . ' ' . $msg);
}
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -0,0 +1,14 @@
AutoFormat.RemoveEmpty.Predicate
TYPE: hash
VERSION: 4.7.0
DEFAULT: array('colgroup' => array(), 'th' => array(), 'td' => array(), 'iframe' => array('src'))
--DESCRIPTION--
<p>
Given that an element has no contents, it will be removed by default, unless
this predicate dictates otherwise. The predicate can either be an associative
map from tag name to list of attributes that must be present for the element
to be considered preserved: thus, the default always preserves <code>colgroup</code>,
<code>th</code> and <code>td</code>, and also <code>iframe</code> if it
has a <code>src</code>.
</p>
--# vim: et sw=4 sts=4

View File

@ -0,0 +1,16 @@
Core.AllowHostnameUnderscore
TYPE: bool
VERSION: 4.6.0
DEFAULT: false
--DESCRIPTION--
<p>
By RFC 1123, underscores are not permitted in host names.
(This is in contrast to the specification for DNS, RFC
2181, which allows underscores.)
However, most browsers do the right thing when faced with
an underscore in the host name, and so some poorly written
websites are written with the expectation this should work.
Setting this parameter to true relaxes our allowed character
check so that underscores are permitted.
</p>
--# vim: et sw=4 sts=4

View File

@ -2,9 +2,11 @@ Core.EscapeInvalidChildren
TYPE: bool TYPE: bool
DEFAULT: false DEFAULT: false
--DESCRIPTION-- --DESCRIPTION--
When true, a child is found that is not allowed in the context of the <p><strong>Warning:</strong> this configuration option is no longer does anything as of 4.6.0.</p>
<p>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 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 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 be preserved. There is no option for dropping the element but preserving
child nodes. child nodes.</p>
--# vim: et sw=4 sts=4 --# vim: et sw=4 sts=4

View File

@ -4,6 +4,6 @@ VERSION: 2.0.1
DEFAULT: NULL DEFAULT: NULL
--DESCRIPTION-- --DESCRIPTION--
A custom doctype for power-users who defined there own document A custom doctype for power-users who defined their own document
type. This directive only applies when %HTML.Doctype is blank. type. This directive only applies when %HTML.Doctype is blank.
--# vim: et sw=4 sts=4 --# vim: et sw=4 sts=4

View File

@ -11,7 +11,7 @@ DEFAULT: NULL
to check if a URI has passed through HTML Purifier with this line: to check if a URI has passed through HTML Purifier with this line:
</p> </p>
<pre>$checksum === sha1($secret_key . ':' . $url)</pre> <pre>$checksum === hash_hmac("sha256", $url, $secret_key)</pre>
<p> <p>
If the output is TRUE, the redirector script should accept the URI. If the output is TRUE, the redirector script should accept the URI.

View File

@ -4,7 +4,9 @@
// understand how to interpret this filter if it's a static method. // understand how to interpret this filter if it's a static method.
// It's all really silly, but if we go this route it might be reasonable // It's all really silly, but if we go this route it might be reasonable
// to coalesce all of these methods into one. // to coalesce all of these methods into one.
function htmlpurifier_filter_extractstyleblocks_muteerrorhandler() {} function htmlpurifier_filter_extractstyleblocks_muteerrorhandler()
{
}
/** /**
* This filter extracts <style> blocks from input HTML, cleans them up * This filter extracts <style> blocks from input HTML, cleans them up
@ -22,38 +24,77 @@ function htmlpurifier_filter_extractstyleblocks_muteerrorhandler() {}
*/ */
class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
{ {
/**
* @type string
*/
public $name = 'ExtractStyleBlocks'; public $name = 'ExtractStyleBlocks';
/**
* @type array
*/
private $_styleMatches = array(); private $_styleMatches = array();
/**
* @type csstidy
*/
private $_tidy; private $_tidy;
/**
* @type HTMLPurifier_AttrDef_HTML_ID
*/
private $_id_attrdef; private $_id_attrdef;
/**
* @type HTMLPurifier_AttrDef_CSS_Ident
*/
private $_class_attrdef; private $_class_attrdef;
/**
* @type HTMLPurifier_AttrDef_Enum
*/
private $_enum_attrdef; private $_enum_attrdef;
public function __construct() { public function __construct()
{
$this->_tidy = new csstidy(); $this->_tidy = new csstidy();
$this->_tidy->set_cfg('lowercase_s', false); $this->_tidy->set_cfg('lowercase_s', false);
$this->_id_attrdef = new HTMLPurifier_AttrDef_HTML_ID(true); $this->_id_attrdef = new HTMLPurifier_AttrDef_HTML_ID(true);
$this->_class_attrdef = new HTMLPurifier_AttrDef_CSS_Ident(); $this->_class_attrdef = new HTMLPurifier_AttrDef_CSS_Ident();
$this->_enum_attrdef = new HTMLPurifier_AttrDef_Enum(array('first-child', 'link', 'visited', 'active', 'hover', 'focus')); $this->_enum_attrdef = new HTMLPurifier_AttrDef_Enum(
array(
'first-child',
'link',
'visited',
'active',
'hover',
'focus'
)
);
} }
/** /**
* Save the contents of CSS blocks to style matches * Save the contents of CSS blocks to style matches
* @param $matches preg_replace style $matches array * @param array $matches preg_replace style $matches array
*/ */
protected function styleCallback($matches) { protected function styleCallback($matches)
{
$this->_styleMatches[] = $matches[1]; $this->_styleMatches[] = $matches[1];
} }
/** /**
* Removes inline <style> tags from HTML, saves them for later use * Removes inline <style> tags from HTML, saves them for later use
* @param string $html
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return string
* @todo Extend to indicate non-text/css style blocks * @todo Extend to indicate non-text/css style blocks
*/ */
public function preFilter($html, $config, $context) { public function preFilter($html, $config, $context)
{
$tidy = $config->get('Filter.ExtractStyleBlocks.TidyImpl'); $tidy = $config->get('Filter.ExtractStyleBlocks.TidyImpl');
if ($tidy !== null) $this->_tidy = $tidy; if ($tidy !== null) {
$this->_tidy = $tidy;
}
$html = preg_replace_callback('#<style(?:\s.*)?>(.+)</style>#isU', array($this, 'styleCallback'), $html); $html = preg_replace_callback('#<style(?:\s.*)?>(.+)</style>#isU', array($this, 'styleCallback'), $html);
$style_blocks = $this->_styleMatches; $style_blocks = $this->_styleMatches;
$this->_styleMatches = array(); // reset $this->_styleMatches = array(); // reset
@ -69,12 +110,14 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
/** /**
* Takes CSS (the stuff found in <style>) and cleans it. * Takes CSS (the stuff found in <style>) and cleans it.
* @warning Requires CSSTidy <http://csstidy.sourceforge.net/> * @warning Requires CSSTidy <http://csstidy.sourceforge.net/>
* @param $css CSS styling to clean * @param string $css CSS styling to clean
* @param $config Instance of HTMLPurifier_Config * @param HTMLPurifier_Config $config
* @param $context Instance of HTMLPurifier_Context * @param HTMLPurifier_Context $context
* @return Cleaned CSS * @throws HTMLPurifier_Exception
* @return string Cleaned CSS
*/ */
public function cleanCSS($css, $config, $context) { public function cleanCSS($css, $config, $context)
{
// prepare scope // prepare scope
$scope = $config->get('Filter.ExtractStyleBlocks.Scope'); $scope = $config->get('Filter.ExtractStyleBlocks.Scope');
if ($scope !== null) { if ($scope !== null) {
@ -102,7 +145,9 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
$new_decls = array(); $new_decls = array();
foreach ($decls as $selector => $style) { foreach ($decls as $selector => $style) {
$selector = trim($selector); $selector = trim($selector);
if ($selector === '') continue; // should not happen if ($selector === '') {
continue;
} // should not happen
// Parse the selector // Parse the selector
// Here is the relevant part of the CSS grammar: // Here is the relevant part of the CSS grammar:
// //
@ -174,7 +219,7 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
// delimiters // delimiters
$nsel = null; $nsel = null;
$delim = null; // guaranteed to be non-null after $delim = null; // guaranteed to be non-null after
// two loop iterations // two loop iterations
for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) { for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) {
$x = $basic_selectors[$i]; $x = $basic_selectors[$i];
if ($i % 2) { if ($i % 2) {
@ -189,7 +234,7 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
$components = preg_split('/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE); $components = preg_split('/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE);
$sdelim = null; $sdelim = null;
$nx = null; $nx = null;
for ($j = 0, $cc = count($components); $j < $cc; $j ++) { for ($j = 0, $cc = count($components); $j < $cc; $j++) {
$y = $components[$j]; $y = $components[$j];
if ($j === 0) { if ($j === 0) {
if ($y === '*' || isset($html_definition->info[$y = strtolower($y)])) { if ($y === '*' || isset($html_definition->info[$y = strtolower($y)])) {
@ -249,7 +294,9 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
} }
} }
} }
if (empty($new_selectors)) continue; if (empty($new_selectors)) {
continue;
}
$selector = implode(', ', $new_selectors); $selector = implode(', ', $new_selectors);
foreach ($style as $name => $value) { foreach ($style as $name => $value) {
if (!isset($css_definition->info[$name])) { if (!isset($css_definition->info[$name])) {
@ -258,8 +305,11 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
} }
$def = $css_definition->info[$name]; $def = $css_definition->info[$name];
$ret = $def->validate($value, $config, $context); $ret = $def->validate($value, $config, $context);
if ($ret === false) unset($style[$name]); if ($ret === false) {
else $style[$name] = $ret; unset($style[$name]);
} else {
$style[$name] = $ret;
}
} }
$new_decls[$selector] = $style; $new_decls[$selector] = $style;
} }
@ -276,14 +326,13 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
// that no funny business occurs (i.e. </style> in a font-family prop). // that no funny business occurs (i.e. </style> in a font-family prop).
if ($config->get('Filter.ExtractStyleBlocks.Escaping')) { if ($config->get('Filter.ExtractStyleBlocks.Escaping')) {
$css = str_replace( $css = str_replace(
array('<', '>', '&'), array('<', '>', '&'),
array('\3C ', '\3E ', '\26 '), array('\3C ', '\3E ', '\26 '),
$css $css
); );
} }
return $css; return $css;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -3,36 +3,62 @@
class HTMLPurifier_Filter_YouTube extends HTMLPurifier_Filter class HTMLPurifier_Filter_YouTube extends HTMLPurifier_Filter
{ {
/**
* @type string
*/
public $name = 'YouTube'; public $name = 'YouTube';
public function preFilter($html, $config, $context) { /**
$pre_regex = '#<object[^>]+>.+?'. * @param string $html
'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s'; * @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return string
*/
public function preFilter($html, $config, $context)
{
$pre_regex = '#<object[^>]+>.+?' .
'(?:http:)?//www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s';
$pre_replace = '<span class="youtube-embed">\1</span>'; $pre_replace = '<span class="youtube-embed">\1</span>';
return preg_replace($pre_regex, $pre_replace, $html); return preg_replace($pre_regex, $pre_replace, $html);
} }
public function postFilter($html, $config, $context) { /**
* @param string $html
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return string
*/
public function postFilter($html, $config, $context)
{
$post_regex = '#<span class="youtube-embed">((?:v|cp)/[A-Za-z0-9\-_=]+)</span>#'; $post_regex = '#<span class="youtube-embed">((?:v|cp)/[A-Za-z0-9\-_=]+)</span>#';
return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html); return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html);
} }
protected function armorUrl($url) { /**
* @param $url
* @return string
*/
protected function armorUrl($url)
{
return str_replace('--', '-&#45;', $url); return str_replace('--', '-&#45;', $url);
} }
protected function postFilterCallback($matches) { /**
* @param array $matches
* @return string
*/
protected function postFilterCallback($matches)
{
$url = $this->armorUrl($matches[1]); $url = $this->armorUrl($matches[1]);
return '<object width="425" height="350" type="application/x-shockwave-flash" '. return '<object width="425" height="350" type="application/x-shockwave-flash" ' .
'data="http://www.youtube.com/'.$url.'">'. 'data="//www.youtube.com/' . $url . '">' .
'<param name="movie" value="http://www.youtube.com/'.$url.'"></param>'. '<param name="movie" value="//www.youtube.com/' . $url . '"></param>' .
'<!--[if IE]>'. '<!--[if IE]>' .
'<embed src="http://www.youtube.com/'.$url.'"'. '<embed src="//www.youtube.com/' . $url . '"' .
'type="application/x-shockwave-flash"'. 'type="application/x-shockwave-flash"' .
'wmode="transparent" width="425" height="350" />'. 'wmode="transparent" width="425" height="350" />' .
'<![endif]-->'. '<![endif]-->' .
'</object>'; '</object>';
} }
} }

View File

@ -4,9 +4,6 @@
class HTMLPurifier_Language_en_x_test extends HTMLPurifier_Language class HTMLPurifier_Language_en_x_test extends HTMLPurifier_Language
{ {
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -4,60 +4,52 @@ $fallback = false;
$messages = array( $messages = array(
'HTMLPurifier' => 'HTML Purifier', 'HTMLPurifier' => 'HTML Purifier',
// for unit testing purposes // for unit testing purposes
'LanguageFactoryTest: Pizza' => 'Pizza', 'LanguageFactoryTest: Pizza' => 'Pizza',
'LanguageTest: List' => '$1', 'LanguageTest: List' => '$1',
'LanguageTest: Hash' => '$1.Keys; $1.Values', 'LanguageTest: Hash' => '$1.Keys; $1.Values',
'Item separator' => ', ',
'Item separator' => ', ', 'Item separator last' => ' and ', // non-Harvard style
'Item separator last' => ' and ', // non-Harvard style
'ErrorCollector: No errors' => 'No errors detected. However, because error reporting is still incomplete, there may have been errors that the error collector was not notified of; please inspect the output HTML carefully.',
'ErrorCollector: At line' => ' at line $line',
'ErrorCollector: Incidental errors' => 'Incidental errors',
'Lexer: Unclosed comment' => 'Unclosed comment',
'Lexer: Unescaped lt' => 'Unescaped less-than sign (<) should be &lt;',
'Lexer: Missing gt' => 'Missing greater-than sign (>), previous less-than sign (<) should be escaped',
'Lexer: Missing attribute key' => 'Attribute declaration has no key',
'Lexer: Missing end quote' => 'Attribute declaration has no end quote',
'Lexer: Extracted body' => 'Removed document metadata tags',
'Strategy_RemoveForeignElements: Tag transform' => '<$1> element transformed into $CurrentToken.Serialized',
'Strategy_RemoveForeignElements: Missing required attribute' => '$CurrentToken.Compact element missing required attribute $1',
'Strategy_RemoveForeignElements: Foreign element to text' => 'Unrecognized $CurrentToken.Serialized tag converted to text',
'Strategy_RemoveForeignElements: Foreign element removed' => 'Unrecognized $CurrentToken.Serialized tag removed',
'Strategy_RemoveForeignElements: Comment removed' => 'Comment containing "$CurrentToken.Data" removed',
'Strategy_RemoveForeignElements: Foreign meta element removed' => 'Unrecognized $CurrentToken.Serialized meta tag and all descendants removed',
'Strategy_RemoveForeignElements: Token removed to end' => 'Tags and text starting from $1 element where removed to end',
'Strategy_RemoveForeignElements: Trailing hyphen in comment removed' => 'Trailing hyphen(s) in comment removed',
'Strategy_RemoveForeignElements: Hyphens in comment collapsed' => 'Double hyphens in comments are not allowed, and were collapsed into single hyphens',
'Strategy_MakeWellFormed: Unnecessary end tag removed' => 'Unnecessary $CurrentToken.Serialized tag removed',
'Strategy_MakeWellFormed: Unnecessary end tag to text' => 'Unnecessary $CurrentToken.Serialized tag converted to text',
'Strategy_MakeWellFormed: Tag auto closed' => '$1.Compact started on line $1.Line auto-closed by $CurrentToken.Compact',
'Strategy_MakeWellFormed: Tag carryover' => '$1.Compact started on line $1.Line auto-continued into $CurrentToken.Compact',
'Strategy_MakeWellFormed: Stray end tag removed' => 'Stray $CurrentToken.Serialized tag removed',
'Strategy_MakeWellFormed: Stray end tag to text' => 'Stray $CurrentToken.Serialized tag converted to text',
'Strategy_MakeWellFormed: Tag closed by element end' => '$1.Compact tag started on line $1.Line closed by end of $CurrentToken.Serialized',
'Strategy_MakeWellFormed: Tag closed by document end' => '$1.Compact tag started on line $1.Line closed by end of document',
'Strategy_FixNesting: Node removed' => '$CurrentToken.Compact node removed',
'Strategy_FixNesting: Node excluded' => '$CurrentToken.Compact node removed due to descendant exclusion by ancestor element',
'Strategy_FixNesting: Node reorganized' => 'Contents of $CurrentToken.Compact node reorganized to enforce its content model',
'Strategy_FixNesting: Node contents removed' => 'Contents of $CurrentToken.Compact node removed',
'AttrValidator: Attributes transformed' => 'Attributes on $CurrentToken.Compact transformed from $1.Keys to $2.Keys',
'AttrValidator: Attribute removed' => '$CurrentAttr.Name attribute on $CurrentToken.Compact removed',
'ErrorCollector: No errors' => 'No errors detected. However, because error reporting is still incomplete, there may have been errors that the error collector was not notified of; please inspect the output HTML carefully.',
'ErrorCollector: At line' => ' at line $line',
'ErrorCollector: Incidental errors' => 'Incidental errors',
'Lexer: Unclosed comment' => 'Unclosed comment',
'Lexer: Unescaped lt' => 'Unescaped less-than sign (<) should be &lt;',
'Lexer: Missing gt' => 'Missing greater-than sign (>), previous less-than sign (<) should be escaped',
'Lexer: Missing attribute key' => 'Attribute declaration has no key',
'Lexer: Missing end quote' => 'Attribute declaration has no end quote',
'Lexer: Extracted body' => 'Removed document metadata tags',
'Strategy_RemoveForeignElements: Tag transform' => '<$1> element transformed into $CurrentToken.Serialized',
'Strategy_RemoveForeignElements: Missing required attribute' => '$CurrentToken.Compact element missing required attribute $1',
'Strategy_RemoveForeignElements: Foreign element to text' => 'Unrecognized $CurrentToken.Serialized tag converted to text',
'Strategy_RemoveForeignElements: Foreign element removed' => 'Unrecognized $CurrentToken.Serialized tag removed',
'Strategy_RemoveForeignElements: Comment removed' => 'Comment containing "$CurrentToken.Data" removed',
'Strategy_RemoveForeignElements: Foreign meta element removed' => 'Unrecognized $CurrentToken.Serialized meta tag and all descendants removed',
'Strategy_RemoveForeignElements: Token removed to end' => 'Tags and text starting from $1 element where removed to end',
'Strategy_RemoveForeignElements: Trailing hyphen in comment removed' => 'Trailing hyphen(s) in comment removed',
'Strategy_RemoveForeignElements: Hyphens in comment collapsed' => 'Double hyphens in comments are not allowed, and were collapsed into single hyphens',
'Strategy_MakeWellFormed: Unnecessary end tag removed' => 'Unnecessary $CurrentToken.Serialized tag removed',
'Strategy_MakeWellFormed: Unnecessary end tag to text' => 'Unnecessary $CurrentToken.Serialized tag converted to text',
'Strategy_MakeWellFormed: Tag auto closed' => '$1.Compact started on line $1.Line auto-closed by $CurrentToken.Compact',
'Strategy_MakeWellFormed: Tag carryover' => '$1.Compact started on line $1.Line auto-continued into $CurrentToken.Compact',
'Strategy_MakeWellFormed: Stray end tag removed' => 'Stray $CurrentToken.Serialized tag removed',
'Strategy_MakeWellFormed: Stray end tag to text' => 'Stray $CurrentToken.Serialized tag converted to text',
'Strategy_MakeWellFormed: Tag closed by element end' => '$1.Compact tag started on line $1.Line closed by end of $CurrentToken.Serialized',
'Strategy_MakeWellFormed: Tag closed by document end' => '$1.Compact tag started on line $1.Line closed by end of document',
'Strategy_FixNesting: Node removed' => '$CurrentToken.Compact node removed',
'Strategy_FixNesting: Node excluded' => '$CurrentToken.Compact node removed due to descendant exclusion by ancestor element',
'Strategy_FixNesting: Node reorganized' => 'Contents of $CurrentToken.Compact node reorganized to enforce its content model',
'Strategy_FixNesting: Node contents removed' => 'Contents of $CurrentToken.Compact node removed',
'AttrValidator: Attributes transformed' => 'Attributes on $CurrentToken.Compact transformed from $1.Keys to $2.Keys',
'AttrValidator: Attribute removed' => '$CurrentAttr.Name attribute on $CurrentToken.Compact removed',
); );
$errorNames = array( $errorNames = array(
E_ERROR => 'Error', E_ERROR => 'Error',
E_WARNING => 'Warning', E_WARNING => 'Warning',
E_NOTICE => 'Notice' E_NOTICE => 'Notice'
); );
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

File diff suppressed because it is too large Load Diff

View File

@ -7,25 +7,30 @@ class HTMLPurifier_Printer
{ {
/** /**
* Instance of HTMLPurifier_Generator for HTML generation convenience funcs * For HTML generation convenience funcs.
* @type HTMLPurifier_Generator
*/ */
protected $generator; protected $generator;
/** /**
* Instance of HTMLPurifier_Config, for easy access * For easy access.
* @type HTMLPurifier_Config
*/ */
protected $config; protected $config;
/** /**
* Initialize $generator. * Initialize $generator.
*/ */
public function __construct() { public function __construct()
{
} }
/** /**
* Give generator necessary configuration if possible * Give generator necessary configuration if possible
* @param HTMLPurifier_Config $config
*/ */
public function prepareGenerator($config) { public function prepareGenerator($config)
{
$all = $config->getAll(); $all = $config->getAll();
$context = new HTMLPurifier_Context(); $context = new HTMLPurifier_Context();
$this->generator = new HTMLPurifier_Generator($config, $context); $this->generator = new HTMLPurifier_Generator($config, $context);
@ -39,45 +44,62 @@ class HTMLPurifier_Printer
/** /**
* Returns a start tag * Returns a start tag
* @param $tag Tag name * @param string $tag Tag name
* @param $attr Attribute array * @param array $attr Attribute array
* @return string
*/ */
protected function start($tag, $attr = array()) { protected function start($tag, $attr = array())
{
return $this->generator->generateFromToken( return $this->generator->generateFromToken(
new HTMLPurifier_Token_Start($tag, $attr ? $attr : array()) new HTMLPurifier_Token_Start($tag, $attr ? $attr : array())
); );
} }
/** /**
* Returns an end teg * Returns an end tag
* @param $tag Tag name * @param string $tag Tag name
* @return string
*/ */
protected function end($tag) { protected function end($tag)
{
return $this->generator->generateFromToken( return $this->generator->generateFromToken(
new HTMLPurifier_Token_End($tag) new HTMLPurifier_Token_End($tag)
); );
} }
/** /**
* Prints a complete element with content inside * Prints a complete element with content inside
* @param $tag Tag name * @param string $tag Tag name
* @param $contents Element contents * @param string $contents Element contents
* @param $attr Tag attributes * @param array $attr Tag attributes
* @param $escape Bool whether or not to escape contents * @param bool $escape whether or not to escape contents
* @return string
*/ */
protected function element($tag, $contents, $attr = array(), $escape = true) { protected function element($tag, $contents, $attr = array(), $escape = true)
{
return $this->start($tag, $attr) . return $this->start($tag, $attr) .
($escape ? $this->escape($contents) : $contents) . ($escape ? $this->escape($contents) : $contents) .
$this->end($tag); $this->end($tag);
} }
protected function elementEmpty($tag, $attr = array()) { /**
* @param string $tag
* @param array $attr
* @return string
*/
protected function elementEmpty($tag, $attr = array())
{
return $this->generator->generateFromToken( return $this->generator->generateFromToken(
new HTMLPurifier_Token_Empty($tag, $attr) new HTMLPurifier_Token_Empty($tag, $attr)
); );
} }
protected function text($text) { /**
* @param string $text
* @return string
*/
protected function text($text)
{
return $this->generator->generateFromToken( return $this->generator->generateFromToken(
new HTMLPurifier_Token_Text($text) new HTMLPurifier_Token_Text($text)
); );
@ -85,24 +107,29 @@ class HTMLPurifier_Printer
/** /**
* Prints a simple key/value row in a table. * Prints a simple key/value row in a table.
* @param $name Key * @param string $name Key
* @param $value Value * @param mixed $value Value
* @return string
*/ */
protected function row($name, $value) { protected function row($name, $value)
if (is_bool($value)) $value = $value ? 'On' : 'Off'; {
if (is_bool($value)) {
$value = $value ? 'On' : 'Off';
}
return return
$this->start('tr') . "\n" . $this->start('tr') . "\n" .
$this->element('th', $name) . "\n" . $this->element('th', $name) . "\n" .
$this->element('td', $value) . "\n" . $this->element('td', $value) . "\n" .
$this->end('tr') $this->end('tr');
;
} }
/** /**
* Escapes a string for HTML output. * Escapes a string for HTML output.
* @param $string String to escape * @param string $string String to escape
* @return string
*/ */
protected function escape($string) { protected function escape($string)
{
$string = HTMLPurifier_Encoder::cleanUTF8($string); $string = HTMLPurifier_Encoder::cleanUTF8($string);
$string = htmlspecialchars($string, ENT_COMPAT, 'UTF-8'); $string = htmlspecialchars($string, ENT_COMPAT, 'UTF-8');
return $string; return $string;
@ -110,32 +137,46 @@ class HTMLPurifier_Printer
/** /**
* Takes a list of strings and turns them into a single list * Takes a list of strings and turns them into a single list
* @param $array List of strings * @param string[] $array List of strings
* @param $polite Bool whether or not to add an end before the last * @param bool $polite Bool whether or not to add an end before the last
* @return string
*/ */
protected function listify($array, $polite = false) { protected function listify($array, $polite = false)
if (empty($array)) return 'None'; {
if (empty($array)) {
return 'None';
}
$ret = ''; $ret = '';
$i = count($array); $i = count($array);
foreach ($array as $value) { foreach ($array as $value) {
$i--; $i--;
$ret .= $value; $ret .= $value;
if ($i > 0 && !($polite && $i == 1)) $ret .= ', '; if ($i > 0 && !($polite && $i == 1)) {
if ($polite && $i == 1) $ret .= 'and '; $ret .= ', ';
}
if ($polite && $i == 1) {
$ret .= 'and ';
}
} }
return $ret; return $ret;
} }
/** /**
* Retrieves the class of an object without prefixes, as well as metadata * Retrieves the class of an object without prefixes, as well as metadata
* @param $obj Object to determine class of * @param object $obj Object to determine class of
* @param $prefix Further prefix to remove * @param string $sec_prefix Further prefix to remove
* @return string
*/ */
protected function getClass($obj, $sec_prefix = '') { protected function getClass($obj, $sec_prefix = '')
{
static $five = null; static $five = null;
if ($five === null) $five = version_compare(PHP_VERSION, '5', '>='); if ($five === null) {
$five = version_compare(PHP_VERSION, '5', '>=');
}
$prefix = 'HTMLPurifier_' . $sec_prefix; $prefix = 'HTMLPurifier_' . $sec_prefix;
if (!$five) $prefix = strtolower($prefix); if (!$five) {
$prefix = strtolower($prefix);
}
$class = str_replace($prefix, '', get_class($obj)); $class = str_replace($prefix, '', get_class($obj));
$lclass = strtolower($class); $lclass = strtolower($class);
$class .= '('; $class .= '(';
@ -164,13 +205,14 @@ class HTMLPurifier_Printer
break; break;
case 'css_importantdecorator': case 'css_importantdecorator':
$class .= $this->getClass($obj->def, $sec_prefix); $class .= $this->getClass($obj->def, $sec_prefix);
if ($obj->allow) $class .= ', !important'; if ($obj->allow) {
$class .= ', !important';
}
break; break;
} }
$class .= ')'; $class .= ')';
return $class; return $class;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -2,10 +2,17 @@
class HTMLPurifier_Printer_CSSDefinition extends HTMLPurifier_Printer class HTMLPurifier_Printer_CSSDefinition extends HTMLPurifier_Printer
{ {
/**
* @type HTMLPurifier_CSSDefinition
*/
protected $def; protected $def;
public function render($config) { /**
* @param HTMLPurifier_Config $config
* @return string
*/
public function render($config)
{
$this->def = $config->getCSSDefinition(); $this->def = $config->getCSSDefinition();
$ret = ''; $ret = '';
@ -32,7 +39,6 @@ class HTMLPurifier_Printer_CSSDefinition extends HTMLPurifier_Printer
return $ret; return $ret;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@ -7,17 +7,20 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
{ {
/** /**
* Printers for specific fields * Printers for specific fields.
* @type HTMLPurifier_Printer[]
*/ */
protected $fields = array(); protected $fields = array();
/** /**
* Documentation URL, can have fragment tagged on end * Documentation URL, can have fragment tagged on end.
* @type string
*/ */
protected $docURL; protected $docURL;
/** /**
* Name of form element to stuff config in * Name of form element to stuff config in.
* @type string
*/ */
protected $name; protected $name;
@ -25,24 +28,27 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
* Whether or not to compress directive names, clipping them off * Whether or not to compress directive names, clipping them off
* after a certain amount of letters. False to disable or integer letters * after a certain amount of letters. False to disable or integer letters
* before clipping. * before clipping.
* @type bool
*/ */
protected $compress = false; protected $compress = false;
/** /**
* @param $name Form element name for directives to be stuffed into * @param string $name Form element name for directives to be stuffed into
* @param $doc_url String documentation URL, will have fragment tagged on * @param string $doc_url String documentation URL, will have fragment tagged on
* @param $compress Integer max length before compressing a directive name, set to false to turn off * @param bool $compress Integer max length before compressing a directive name, set to false to turn off
*/ */
public function __construct( public function __construct(
$name, $doc_url = null, $compress = false $name,
$doc_url = null,
$compress = false
) { ) {
parent::__construct(); parent::__construct();
$this->docURL = $doc_url; $this->docURL = $doc_url;
$this->name = $name; $this->name = $name;
$this->compress = $compress; $this->compress = $compress;
// initialize sub-printers // initialize sub-printers
$this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default(); $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default();
$this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool(); $this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool();
} }
/** /**
@ -50,32 +56,42 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
* @param $cols Integer columns of textarea, null to use default * @param $cols Integer columns of textarea, null to use default
* @param $rows Integer rows of textarea, null to use default * @param $rows Integer rows of textarea, null to use default
*/ */
public function setTextareaDimensions($cols = null, $rows = null) { public function setTextareaDimensions($cols = null, $rows = null)
if ($cols) $this->fields['default']->cols = $cols; {
if ($rows) $this->fields['default']->rows = $rows; if ($cols) {
$this->fields['default']->cols = $cols;
}
if ($rows) {
$this->fields['default']->rows = $rows;
}
} }
/** /**
* Retrieves styling, in case it is not accessible by webserver * Retrieves styling, in case it is not accessible by webserver
*/ */
public static function getCSS() { public static function getCSS()
{
return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css'); return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css');
} }
/** /**
* Retrieves JavaScript, in case it is not accessible by webserver * Retrieves JavaScript, in case it is not accessible by webserver
*/ */
public static function getJavaScript() { public static function getJavaScript()
{
return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js'); return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js');
} }
/** /**
* Returns HTML output for a configuration form * Returns HTML output for a configuration form
* @param $config Configuration object of current form state, or an array * @param HTMLPurifier_Config|array $config Configuration object of current form state, or an array
* where [0] has an HTML namespace and [1] is being rendered. * where [0] has an HTML namespace and [1] is being rendered.
* @param $allowed Optional namespace(s) and directives to restrict form to. * @param array|bool $allowed Optional namespace(s) and directives to restrict form to.
* @param bool $render_controls
* @return string
*/ */
public function render($config, $allowed = true, $render_controls = true) { public function render($config, $allowed = true, $render_controls = true)
{
if (is_array($config) && isset($config[0])) { if (is_array($config) && isset($config[0])) {
$gen_config = $config[0]; $gen_config = $config[0];
$config = $config[1]; $config = $config[1];
@ -91,29 +107,29 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
$all = array(); $all = array();
foreach ($allowed as $key) { foreach ($allowed as $key) {
list($ns, $directive) = $key; list($ns, $directive) = $key;
$all[$ns][$directive] = $config->get($ns .'.'. $directive); $all[$ns][$directive] = $config->get($ns . '.' . $directive);
} }
$ret = ''; $ret = '';
$ret .= $this->start('table', array('class' => 'hp-config')); $ret .= $this->start('table', array('class' => 'hp-config'));
$ret .= $this->start('thead'); $ret .= $this->start('thead');
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', 'Directive', array('class' => 'hp-directive')); $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive'));
$ret .= $this->element('th', 'Value', array('class' => 'hp-value')); $ret .= $this->element('th', 'Value', array('class' => 'hp-value'));
$ret .= $this->end('tr'); $ret .= $this->end('tr');
$ret .= $this->end('thead'); $ret .= $this->end('thead');
foreach ($all as $ns => $directives) { foreach ($all as $ns => $directives) {
$ret .= $this->renderNamespace($ns, $directives); $ret .= $this->renderNamespace($ns, $directives);
} }
if ($render_controls) { if ($render_controls) {
$ret .= $this->start('tbody'); $ret .= $this->start('tbody');
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls'));
$ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit')); $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit'));
$ret .= '[<a href="?">Reset</a>]'; $ret .= '[<a href="?">Reset</a>]';
$ret .= $this->end('td'); $ret .= $this->end('td');
$ret .= $this->end('tr'); $ret .= $this->end('tr');
$ret .= $this->end('tbody'); $ret .= $this->end('tbody');
} }
$ret .= $this->end('table'); $ret .= $this->end('table');
return $ret; return $ret;
@ -122,13 +138,15 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
/** /**
* Renders a single namespace * Renders a single namespace
* @param $ns String namespace name * @param $ns String namespace name
* @param $directive Associative array of directives to values * @param array $directives array of directives to values
* @return string
*/ */
protected function renderNamespace($ns, $directives) { protected function renderNamespace($ns, $directives)
{
$ret = ''; $ret = '';
$ret .= $this->start('tbody', array('class' => 'namespace')); $ret .= $this->start('tbody', array('class' => 'namespace'));
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', $ns, array('colspan' => 2)); $ret .= $this->element('th', $ns, array('colspan' => 2));
$ret .= $this->end('tr'); $ret .= $this->end('tr');
$ret .= $this->end('tbody'); $ret .= $this->end('tbody');
$ret .= $this->start('tbody'); $ret .= $this->start('tbody');
@ -139,40 +157,44 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
$url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL); $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL);
$ret .= $this->start('a', array('href' => $url)); $ret .= $this->start('a', array('href' => $url));
} }
$attr = array('for' => "{$this->name}:$ns.$directive"); $attr = array('for' => "{$this->name}:$ns.$directive");
// crop directive name if it's too long // crop directive name if it's too long
if (!$this->compress || (strlen($directive) < $this->compress)) { if (!$this->compress || (strlen($directive) < $this->compress)) {
$directive_disp = $directive; $directive_disp = $directive;
} else { } else {
$directive_disp = substr($directive, 0, $this->compress - 2) . '...'; $directive_disp = substr($directive, 0, $this->compress - 2) . '...';
$attr['title'] = $directive; $attr['title'] = $directive;
} }
$ret .= $this->element( $ret .= $this->element(
'label', 'label',
$directive_disp, $directive_disp,
// component printers must create an element with this id // component printers must create an element with this id
$attr $attr
); );
if ($this->docURL) $ret .= $this->end('a'); if ($this->docURL) {
$ret .= $this->end('a');
}
$ret .= $this->end('th'); $ret .= $this->end('th');
$ret .= $this->start('td'); $ret .= $this->start('td');
$def = $this->config->def->info["$ns.$directive"]; $def = $this->config->def->info["$ns.$directive"];
if (is_int($def)) { if (is_int($def)) {
$allow_null = $def < 0; $allow_null = $def < 0;
$type = abs($def); $type = abs($def);
} else { } else {
$type = $def->type; $type = $def->type;
$allow_null = isset($def->allow_null); $allow_null = isset($def->allow_null);
} }
if (!isset($this->fields[$type])) $type = 0; // default if (!isset($this->fields[$type])) {
$type_obj = $this->fields[$type]; $type = 0;
if ($allow_null) { } // default
$type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj); $type_obj = $this->fields[$type];
} if ($allow_null) {
$ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config)); $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj);
}
$ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config));
$ret .= $this->end('td'); $ret .= $this->end('td');
$ret .= $this->end('tr'); $ret .= $this->end('tr');
} }
@ -185,19 +207,33 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
/** /**
* Printer decorator for directives that accept null * Printer decorator for directives that accept null
*/ */
class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer { class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer
{
/** /**
* Printer being decorated * Printer being decorated
* @type HTMLPurifier_Printer
*/ */
protected $obj; protected $obj;
/** /**
* @param $obj Printer to decorate * @param HTMLPurifier_Printer $obj Printer to decorate
*/ */
public function __construct($obj) { public function __construct($obj)
{
parent::__construct(); parent::__construct();
$this->obj = $obj; $this->obj = $obj;
} }
public function render($ns, $directive, $value, $name, $config) {
/**
* @param string $ns
* @param string $directive
* @param string $value
* @param string $name
* @param HTMLPurifier_Config|array $config
* @return string
*/
public function render($ns, $directive, $value, $name, $config)
{
if (is_array($config) && isset($config[0])) { if (is_array($config) && isset($config[0])) {
$gen_config = $config[0]; $gen_config = $config[0];
$config = $config[1]; $config = $config[1];
@ -215,15 +251,19 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer
'type' => 'checkbox', 'type' => 'checkbox',
'value' => '1', 'value' => '1',
'class' => 'null-toggle', 'class' => 'null-toggle',
'name' => "$name"."[Null_$ns.$directive]", 'name' => "$name" . "[Null_$ns.$directive]",
'id' => "$name:Null_$ns.$directive", 'id' => "$name:Null_$ns.$directive",
'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!! 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!!
); );
if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) { if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) {
// modify inline javascript slightly // modify inline javascript slightly
$attr['onclick'] = "toggleWriteability('$name:Yes_$ns.$directive',checked);toggleWriteability('$name:No_$ns.$directive',checked)"; $attr['onclick'] =
"toggleWriteability('$name:Yes_$ns.$directive',checked);" .
"toggleWriteability('$name:No_$ns.$directive',checked)";
}
if ($value === null) {
$attr['checked'] = 'checked';
} }
if ($value === null) $attr['checked'] = 'checked';
$ret .= $this->elementEmpty('input', $attr); $ret .= $this->elementEmpty('input', $attr);
$ret .= $this->text(' or '); $ret .= $this->text(' or ');
$ret .= $this->elementEmpty('br'); $ret .= $this->elementEmpty('br');
@ -235,10 +275,28 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer
/** /**
* Swiss-army knife configuration form field printer * Swiss-army knife configuration form field printer
*/ */
class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer
{
/**
* @type int
*/
public $cols = 18; public $cols = 18;
/**
* @type int
*/
public $rows = 5; public $rows = 5;
public function render($ns, $directive, $value, $name, $config) {
/**
* @param string $ns
* @param string $directive
* @param string $value
* @param string $name
* @param HTMLPurifier_Config|array $config
* @return string
*/
public function render($ns, $directive, $value, $name, $config)
{
if (is_array($config) && isset($config[0])) { if (is_array($config) && isset($config[0])) {
$gen_config = $config[0]; $gen_config = $config[0];
$config = $config[1]; $config = $config[1];
@ -262,6 +320,7 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer {
foreach ($array as $val => $b) { foreach ($array as $val => $b) {
$value[] = $val; $value[] = $val;
} }
//TODO does this need a break?
case HTMLPurifier_VarParser::ALIST: case HTMLPurifier_VarParser::ALIST:
$value = implode(PHP_EOL, $value); $value = implode(PHP_EOL, $value);
break; break;
@ -281,25 +340,27 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer {
$value = serialize($value); $value = serialize($value);
} }
$attr = array( $attr = array(
'name' => "$name"."[$ns.$directive]", 'name' => "$name" . "[$ns.$directive]",
'id' => "$name:$ns.$directive" 'id' => "$name:$ns.$directive"
); );
if ($value === null) $attr['disabled'] = 'disabled'; if ($value === null) {
$attr['disabled'] = 'disabled';
}
if (isset($def->allowed)) { if (isset($def->allowed)) {
$ret .= $this->start('select', $attr); $ret .= $this->start('select', $attr);
foreach ($def->allowed as $val => $b) { foreach ($def->allowed as $val => $b) {
$attr = array(); $attr = array();
if ($value == $val) $attr['selected'] = 'selected'; if ($value == $val) {
$attr['selected'] = 'selected';
}
$ret .= $this->element('option', $val, $attr); $ret .= $this->element('option', $val, $attr);
} }
$ret .= $this->end('select'); $ret .= $this->end('select');
} elseif ( } elseif ($type === HTMLPurifier_VarParser::TEXT ||
$type === HTMLPurifier_VarParser::TEXT || $type === HTMLPurifier_VarParser::ITEXT ||
$type === HTMLPurifier_VarParser::ITEXT || $type === HTMLPurifier_VarParser::ALIST ||
$type === HTMLPurifier_VarParser::ALIST || $type === HTMLPurifier_VarParser::HASH ||
$type === HTMLPurifier_VarParser::HASH || $type === HTMLPurifier_VarParser::LOOKUP) {
$type === HTMLPurifier_VarParser::LOOKUP
) {
$attr['cols'] = $this->cols; $attr['cols'] = $this->cols;
$attr['rows'] = $this->rows; $attr['rows'] = $this->rows;
$ret .= $this->start('textarea', $attr); $ret .= $this->start('textarea', $attr);
@ -317,8 +378,18 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer {
/** /**
* Bool form field printer * Bool form field printer
*/ */
class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer { class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer
public function render($ns, $directive, $value, $name, $config) { {
/**
* @param string $ns
* @param string $directive
* @param string $value
* @param string $name
* @param HTMLPurifier_Config|array $config
* @return string
*/
public function render($ns, $directive, $value, $name, $config)
{
if (is_array($config) && isset($config[0])) { if (is_array($config) && isset($config[0])) {
$gen_config = $config[0]; $gen_config = $config[0];
$config = $config[1]; $config = $config[1];
@ -336,12 +407,16 @@ class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer {
$attr = array( $attr = array(
'type' => 'radio', 'type' => 'radio',
'name' => "$name"."[$ns.$directive]", 'name' => "$name" . "[$ns.$directive]",
'id' => "$name:Yes_$ns.$directive", 'id' => "$name:Yes_$ns.$directive",
'value' => '1' 'value' => '1'
); );
if ($value === true) $attr['checked'] = 'checked'; if ($value === true) {
if ($value === null) $attr['disabled'] = 'disabled'; $attr['checked'] = 'checked';
}
if ($value === null) {
$attr['disabled'] = 'disabled';
}
$ret .= $this->elementEmpty('input', $attr); $ret .= $this->elementEmpty('input', $attr);
$ret .= $this->start('label', array('for' => "$name:No_$ns.$directive")); $ret .= $this->start('label', array('for' => "$name:No_$ns.$directive"));
@ -351,12 +426,16 @@ class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer {
$attr = array( $attr = array(
'type' => 'radio', 'type' => 'radio',
'name' => "$name"."[$ns.$directive]", 'name' => "$name" . "[$ns.$directive]",
'id' => "$name:No_$ns.$directive", 'id' => "$name:No_$ns.$directive",
'value' => '0' 'value' => '0'
); );
if ($value === false) $attr['checked'] = 'checked'; if ($value === false) {
if ($value === null) $attr['disabled'] = 'disabled'; $attr['checked'] = 'checked';
}
if ($value === null) {
$attr['disabled'] = 'disabled';
}
$ret .= $this->elementEmpty('input', $attr); $ret .= $this->elementEmpty('input', $attr);
$ret .= $this->end('div'); $ret .= $this->end('div');

View File

@ -4,11 +4,16 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
{ {
/** /**
* Instance of HTMLPurifier_HTMLDefinition, for easy access * @type HTMLPurifier_HTMLDefinition, for easy access
*/ */
protected $def; protected $def;
public function render($config) { /**
* @param HTMLPurifier_Config $config
* @return string
*/
public function render($config)
{
$ret = ''; $ret = '';
$this->config =& $config; $this->config =& $config;
@ -28,8 +33,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/** /**
* Renders the Doctype table * Renders the Doctype table
* @return string
*/ */
protected function renderDoctype() { protected function renderDoctype()
{
$doctype = $this->def->doctype; $doctype = $this->def->doctype;
$ret = ''; $ret = '';
$ret .= $this->start('table'); $ret .= $this->start('table');
@ -45,8 +52,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/** /**
* Renders environment table, which is miscellaneous info * Renders environment table, which is miscellaneous info
* @return string
*/ */
protected function renderEnvironment() { protected function renderEnvironment()
{
$def = $this->def; $def = $this->def;
$ret = ''; $ret = '';
@ -59,28 +68,28 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
$ret .= $this->row('Block wrap name', $def->info_block_wrapper); $ret .= $this->row('Block wrap name', $def->info_block_wrapper);
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', 'Global attributes'); $ret .= $this->element('th', 'Global attributes');
$ret .= $this->element('td', $this->listifyAttr($def->info_global_attr),0,0); $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr), null, 0);
$ret .= $this->end('tr'); $ret .= $this->end('tr');
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', 'Tag transforms'); $ret .= $this->element('th', 'Tag transforms');
$list = array(); $list = array();
foreach ($def->info_tag_transform as $old => $new) { foreach ($def->info_tag_transform as $old => $new) {
$new = $this->getClass($new, 'TagTransform_'); $new = $this->getClass($new, 'TagTransform_');
$list[] = "<$old> with $new"; $list[] = "<$old> with $new";
} }
$ret .= $this->element('td', $this->listify($list)); $ret .= $this->element('td', $this->listify($list));
$ret .= $this->end('tr'); $ret .= $this->end('tr');
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', 'Pre-AttrTransform'); $ret .= $this->element('th', 'Pre-AttrTransform');
$ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre)); $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre));
$ret .= $this->end('tr'); $ret .= $this->end('tr');
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', 'Post-AttrTransform'); $ret .= $this->element('th', 'Post-AttrTransform');
$ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post)); $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post));
$ret .= $this->end('tr'); $ret .= $this->end('tr');
$ret .= $this->end('table'); $ret .= $this->end('table');
@ -89,8 +98,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/** /**
* Renders the Content Sets table * Renders the Content Sets table
* @return string
*/ */
protected function renderContentSets() { protected function renderContentSets()
{
$ret = ''; $ret = '';
$ret .= $this->start('table'); $ret .= $this->start('table');
$ret .= $this->element('caption', 'Content Sets'); $ret .= $this->element('caption', 'Content Sets');
@ -106,8 +117,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/** /**
* Renders the Elements ($info) table * Renders the Elements ($info) table
* @return string
*/ */
protected function renderInfo() { protected function renderInfo()
{
$ret = ''; $ret = '';
$ret .= $this->start('table'); $ret .= $this->start('table');
$ret .= $this->element('caption', 'Elements ($info)'); $ret .= $this->element('caption', 'Elements ($info)');
@ -118,39 +131,39 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
$ret .= $this->end('tr'); $ret .= $this->end('tr');
foreach ($this->def->info as $name => $def) { foreach ($this->def->info as $name => $def) {
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', "<$name>", array('class'=>'heavy', 'colspan' => 2)); $ret .= $this->element('th', "<$name>", array('class' => 'heavy', 'colspan' => 2));
$ret .= $this->end('tr'); $ret .= $this->end('tr');
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', 'Inline content'); $ret .= $this->element('th', 'Inline content');
$ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No'); $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No');
$ret .= $this->end('tr'); $ret .= $this->end('tr');
if (!empty($def->excludes)) { if (!empty($def->excludes)) {
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', 'Excludes'); $ret .= $this->element('th', 'Excludes');
$ret .= $this->element('td', $this->listifyTagLookup($def->excludes)); $ret .= $this->element('td', $this->listifyTagLookup($def->excludes));
$ret .= $this->end('tr'); $ret .= $this->end('tr');
} }
if (!empty($def->attr_transform_pre)) { if (!empty($def->attr_transform_pre)) {
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', 'Pre-AttrTransform'); $ret .= $this->element('th', 'Pre-AttrTransform');
$ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre)); $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre));
$ret .= $this->end('tr'); $ret .= $this->end('tr');
} }
if (!empty($def->attr_transform_post)) { if (!empty($def->attr_transform_post)) {
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', 'Post-AttrTransform'); $ret .= $this->element('th', 'Post-AttrTransform');
$ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post)); $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post));
$ret .= $this->end('tr'); $ret .= $this->end('tr');
} }
if (!empty($def->auto_close)) { if (!empty($def->auto_close)) {
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', 'Auto closed by'); $ret .= $this->element('th', 'Auto closed by');
$ret .= $this->element('td', $this->listifyTagLookup($def->auto_close)); $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close));
$ret .= $this->end('tr'); $ret .= $this->end('tr');
} }
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', 'Allowed attributes'); $ret .= $this->element('th', 'Allowed attributes');
$ret .= $this->element('td',$this->listifyAttr($def->attr), array(), 0); $ret .= $this->element('td', $this->listifyAttr($def->attr), array(), 0);
$ret .= $this->end('tr'); $ret .= $this->end('tr');
if (!empty($def->required_attr)) { if (!empty($def->required_attr)) {
@ -165,64 +178,94 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/** /**
* Renders a row describing the allowed children of an element * Renders a row describing the allowed children of an element
* @param $def HTMLPurifier_ChildDef of pertinent element * @param HTMLPurifier_ChildDef $def HTMLPurifier_ChildDef of pertinent element
* @return string
*/ */
protected function renderChildren($def) { protected function renderChildren($def)
{
$context = new HTMLPurifier_Context(); $context = new HTMLPurifier_Context();
$ret = ''; $ret = '';
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$elements = array();
$attr = array();
if (isset($def->elements)) {
if ($def->type == 'strictblockquote') {
$def->validateChildren(array(), $this->config, $context);
}
$elements = $def->elements;
}
if ($def->type == 'chameleon') {
$attr['rowspan'] = 2;
} elseif ($def->type == 'empty') {
$elements = array(); $elements = array();
$attr = array(); } elseif ($def->type == 'table') {
if (isset($def->elements)) { $elements = array_flip(
if ($def->type == 'strictblockquote') { array(
$def->validateChildren(array(), $this->config, $context); 'col',
} 'caption',
$elements = $def->elements; 'colgroup',
} 'thead',
if ($def->type == 'chameleon') { 'tfoot',
$attr['rowspan'] = 2; 'tbody',
} elseif ($def->type == 'empty') { 'tr'
$elements = array(); )
} elseif ($def->type == 'table') { );
$elements = array_flip(array('col', 'caption', 'colgroup', 'thead', }
'tfoot', 'tbody', 'tr')); $ret .= $this->element('th', 'Allowed children', $attr);
}
$ret .= $this->element('th', 'Allowed children', $attr);
if ($def->type == 'chameleon') { if ($def->type == 'chameleon') {
$ret .= $this->element('td', $ret .= $this->element(
'<em>Block</em>: ' . 'td',
$this->escape($this->listifyTagLookup($def->block->elements)),0,0); '<em>Block</em>: ' .
$ret .= $this->end('tr'); $this->escape($this->listifyTagLookup($def->block->elements)),
$ret .= $this->start('tr'); null,
$ret .= $this->element('td', 0
'<em>Inline</em>: ' . );
$this->escape($this->listifyTagLookup($def->inline->elements)),0,0); $ret .= $this->end('tr');
$ret .= $this->start('tr');
$ret .= $this->element(
'td',
'<em>Inline</em>: ' .
$this->escape($this->listifyTagLookup($def->inline->elements)),
null,
0
);
} elseif ($def->type == 'custom') { } elseif ($def->type == 'custom') {
$ret .= $this->element('td', '<em>'.ucfirst($def->type).'</em>: ' . $ret .= $this->element(
$def->dtd_regex); 'td',
'<em>' . ucfirst($def->type) . '</em>: ' .
$def->dtd_regex
);
} else { } else {
$ret .= $this->element('td', $ret .= $this->element(
'<em>'.ucfirst($def->type).'</em>: ' . 'td',
$this->escape($this->listifyTagLookup($elements)),0,0); '<em>' . ucfirst($def->type) . '</em>: ' .
} $this->escape($this->listifyTagLookup($elements)),
null,
0
);
}
$ret .= $this->end('tr'); $ret .= $this->end('tr');
return $ret; return $ret;
} }
/** /**
* Listifies a tag lookup table. * Listifies a tag lookup table.
* @param $array Tag lookup array in form of array('tagname' => true) * @param array $array Tag lookup array in form of array('tagname' => true)
* @return string
*/ */
protected function listifyTagLookup($array) { protected function listifyTagLookup($array)
{
ksort($array); ksort($array);
$list = array(); $list = array();
foreach ($array as $name => $discard) { foreach ($array as $name => $discard) {
if ($name !== '#PCDATA' && !isset($this->def->info[$name])) continue; if ($name !== '#PCDATA' && !isset($this->def->info[$name])) {
continue;
}
$list[] = $name; $list[] = $name;
} }
return $this->listify($list); return $this->listify($list);
@ -230,13 +273,15 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/** /**
* Listifies a list of objects by retrieving class names and internal state * Listifies a list of objects by retrieving class names and internal state
* @param $array List of objects * @param array $array List of objects
* @return string
* @todo Also add information about internal state * @todo Also add information about internal state
*/ */
protected function listifyObjectList($array) { protected function listifyObjectList($array)
{
ksort($array); ksort($array);
$list = array(); $list = array();
foreach ($array as $discard => $obj) { foreach ($array as $obj) {
$list[] = $this->getClass($obj, 'AttrTransform_'); $list[] = $this->getClass($obj, 'AttrTransform_');
} }
return $this->listify($list); return $this->listify($list);
@ -244,13 +289,17 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/** /**
* Listifies a hash of attributes to AttrDef classes * Listifies a hash of attributes to AttrDef classes
* @param $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef) * @param array $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef)
* @return string
*/ */
protected function listifyAttr($array) { protected function listifyAttr($array)
{
ksort($array); ksort($array);
$list = array(); $list = array();
foreach ($array as $name => $obj) { foreach ($array as $name => $obj) {
if ($obj === false) continue; if ($obj === false) {
continue;
}
$list[] = "$name&nbsp;=&nbsp;<i>" . $this->getClass($obj, 'AttrDef_') . '</i>'; $list[] = "$name&nbsp;=&nbsp;<i>" . $this->getClass($obj, 'AttrDef_') . '</i>';
} }
return $this->listify($list); return $this->listify($list);
@ -258,15 +307,18 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/** /**
* Creates a heavy header row * Creates a heavy header row
* @param string $text
* @param int $num
* @return string
*/ */
protected function heavyHeader($text, $num = 1) { protected function heavyHeader($text, $num = 1)
{
$ret = ''; $ret = '';
$ret .= $this->start('tr'); $ret .= $this->start('tr');
$ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy')); $ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy'));
$ret .= $this->end('tr'); $ret .= $this->end('tr');
return $ret; return $ret;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4