1
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2025-07-31 19:30:21 +02:00
- Printer adheres to configuration's directives on output format
- Fix improperly named form field in ConfigForm printer
. HTMLPurifier_Config::getAllowedDirectivesForForm implemented, allows much easier selective embedding of configuration values
. Doctype objects now accept public and system DTD identifiers
. %HTML.Doctype is now constrained by specific values, to specify a custom doctype use new %HTML.CustomDoctype
. ConfigForm truncates long directives to keep the form small, and does not re-output namespaces

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1232 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang
2007-06-25 18:38:39 +00:00
parent 96b571d236
commit 9f996b125a
11 changed files with 275 additions and 73 deletions

View File

@@ -341,25 +341,78 @@ class HTMLPurifier_Config
}
}
/**
* Returns a list of array(namespace, directive) for all directives
* that are allowed in a web-form context as per an allowed
* namespaces/directives list.
* @param $allowed List of allowed namespaces/directives
* @static
*/
function getAllowedDirectivesForForm($allowed) {
$schema = HTMLPurifier_ConfigSchema::instance();
if ($allowed !== true) {
if (is_string($allowed)) $allowed = array($allowed);
$allowed_ns = array();
$allowed_directives = array();
$blacklisted_directives = array();
foreach ($allowed as $ns_or_directive) {
if (strpos($ns_or_directive, '.') !== false) {
// directive
if ($ns_or_directive[0] == '-') {
$blacklisted_directives[substr($ns_or_directive, 1)] = true;
} else {
$allowed_directives[$ns_or_directive] = true;
}
} else {
// namespace
$allowed_ns[$ns_or_directive] = true;
}
}
}
$ret = array();
foreach ($schema->info as $ns => $keypairs) {
foreach ($keypairs as $directive => $def) {
if ($allowed !== true) {
if (isset($blacklisted_directives["$ns.$directive"])) continue;
if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue;
}
if ($def->class == 'alias') continue;
if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue;
$ret[] = array($ns, $directive);
}
}
return $ret;
}
/**
* Loads configuration values from $_GET/$_POST that were posted
* via ConfigForm
* @param $array $_GET or $_POST array to import
* @param $index Index/name that the config variables are in
* @param $allowed List of allowed namespaces/directives
* @param $mq_fix Boolean whether or not to enable magic quotes fix
* @static
*/
function loadArrayFromForm($array, $index, $mq_fix = true) {
function loadArrayFromForm($array, $index, $allowed = true, $mq_fix = true) {
$array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
$mq = get_magic_quotes_gpc() && $mq_fix;
foreach ($array as $key => $value) {
if (!strncmp($key, 'Null_', 5) && !empty($value)) {
unset($array[substr($key, 5)]);
unset($array[$key]);
$allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed);
$ret = array();
foreach ($allowed as $key) {
list($ns, $directive) = $key;
$skey = "$ns.$directive";
if (!empty($array["Null_$skey"])) {
$ret[$ns][$directive] = null;
continue;
}
if ($mq) $array[$key] = stripslashes($value);
if (!isset($array[$skey])) continue;
$value = $mq ? stripslashes($array[$skey]) : $array[$skey];
$ret[$ns][$directive] = $value;
}
return @HTMLPurifier_Config::create($array);
$config = HTMLPurifier_Config::create($ret);
return $config;
}
/**

View File

@@ -34,23 +34,33 @@ class HTMLPurifier_Doctype
*/
var $aliases = array();
/**
* Public DTD identifier
*/
var $dtdPublic;
/**
* System DTD identifier
*/
var $dtdSystem;
function HTMLPurifier_Doctype($name = null, $xml = true, $modules = array(),
$tidyModules = array(), $aliases = array()
$tidyModules = array(), $aliases = array(), $dtd_public = null, $dtd_system = null
) {
$this->name = $name;
$this->xml = $xml;
$this->modules = $modules;
$this->tidyModules = $tidyModules;
$this->aliases = $aliases;
$this->dtdPublic = $dtd_public;
$this->dtdSystem = $dtd_system;
}
/**
* Clones the doctype, use before resolving modes and the like
*/
function copy() {
return new HTMLPurifier_Doctype(
$this->name, $this->xml, $this->modules, $this->tidyModules, $this->aliases
);
return unserialize(serialize($this));
}
}

View File

@@ -44,14 +44,14 @@ class HTMLPurifier_DoctypeRegistry
* @return Reference to registered doctype (usable for further editing)
*/
function &register($doctype, $xml = true, $modules = array(),
$tidy_modules = array(), $aliases = array()
$tidy_modules = array(), $aliases = array(), $dtd_public = null, $dtd_system = null
) {
if (!is_array($modules)) $modules = array($modules);
if (!is_array($tidy_modules)) $tidy_modules = array($tidy_modules);
if (!is_array($aliases)) $aliases = array($aliases);
if (!is_object($doctype)) {
$doctype = new HTMLPurifier_Doctype(
$doctype, $xml, $modules, $tidy_modules, $aliases
$doctype, $xml, $modules, $tidy_modules, $aliases, $dtd_public, $dtd_system
);
}
$this->doctypes[$doctype->name] =& $doctype;
@@ -76,7 +76,7 @@ class HTMLPurifier_DoctypeRegistry
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');
trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist', E_USER_ERROR);
$anon = new HTMLPurifier_Doctype($doctype);
return $anon;
}
@@ -103,9 +103,9 @@ class HTMLPurifier_DoctypeRegistry
function getDoctypeFromConfig($config) {
// recommended test
$doctype = $config->get('HTML', 'Doctype');
if ($doctype !== null) {
return $doctype;
}
if (!empty($doctype)) return $doctype;
$doctype = $config->get('HTML', 'CustomDoctype');
if (!empty($doctype)) return $doctype;
// backwards-compatibility
if ($config->get('HTML', 'XHTML')) {
$doctype = 'XHTML 1.0';

View File

@@ -37,14 +37,27 @@ require_once 'HTMLPurifier/HTMLModule/Tidy/XHTMLStrict.php';
require_once 'HTMLPurifier/HTMLModule/Tidy/Proprietary.php';
HTMLPurifier_ConfigSchema::define(
'HTML', 'Doctype', null, 'string/null',
'Doctype to use, pre-defined values are HTML 4.01 Transitional, HTML 4.01 '.
'Strict, XHTML 1.0 Transitional, XHTML 1.0 Strict, XHTML 1.1. '.
'HTML', 'Doctype', '', 'string',
'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. This will override any older directives '.
'for sake of simplicity. When non-blank, this will override any older directives '.
'like %HTML.XHTML or %HTML.Strict.'
);
HTMLPurifier_ConfigSchema::defineAllowedValues('HTML', 'Doctype', array(
'', 'HTML 4.01 Transitional', 'HTML 4.01 Strict',
'XHTML 1.0 Transitional', 'XHTML 1.0 Strict',
'XHTML 1.1'
));
HTMLPurifier_ConfigSchema::define(
'HTML', 'CustomDoctype', null, 'string/null',
'
A custom doctype for power-users who defined there own document
type. This directive only applies when %HTML.Doctype is blank.
This directive has been available since 2.0.1.
'
);
HTMLPurifier_ConfigSchema::define(
'HTML', 'Trusted', false, 'bool',
@@ -167,31 +180,46 @@ class HTMLPurifier_HTMLModuleManager
$this->doctypes->register(
'HTML 4.01 Transitional', false,
array_merge($common, $transitional, $non_xml),
array('Tidy_Transitional', 'Tidy_Proprietary')
array('Tidy_Transitional', 'Tidy_Proprietary'),
array(),
'-//W3C//DTD HTML 4.01 Transitional//EN',
'http://www.w3.org/TR/html4/loose.dtd'
);
$this->doctypes->register(
'HTML 4.01 Strict', false,
array_merge($common, $non_xml),
array('Tidy_Strict', 'Tidy_Proprietary')
array('Tidy_Strict', 'Tidy_Proprietary'),
array(),
'-//W3C//DTD HTML 4.01//EN',
'http://www.w3.org/TR/html4/strict.dtd'
);
$this->doctypes->register(
'XHTML 1.0 Transitional', true,
array_merge($common, $transitional, $xml, $non_xml),
array('Tidy_Transitional', 'Tidy_XHTML', 'Tidy_Proprietary')
array('Tidy_Transitional', 'Tidy_XHTML', 'Tidy_Proprietary'),
array(),
'-//W3C//DTD XHTML 1.0 Transitional//EN',
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'
);
$this->doctypes->register(
'XHTML 1.0 Strict', true,
array_merge($common, $xml, $non_xml),
array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_XHTMLStrict', 'Tidy_Proprietary')
array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_XHTMLStrict', 'Tidy_Proprietary'),
array(),
'-//W3C//DTD XHTML 1.0 Strict//EN',
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
);
$this->doctypes->register(
'XHTML 1.1', true,
array_merge($common, $xml),
array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Proprietary') // Tidy_XHTML1_1
array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Proprietary'), // Tidy_XHTML1_1
array(),
'-//W3C//DTD XHTML 1.1//EN',
'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'
);
}

View File

@@ -26,6 +26,16 @@ class HTMLPurifier_Printer
$this->generator = new HTMLPurifier_Generator();
}
/**
* Give generator necessary configuration if possible
*/
function prepareGenerator($config) {
// hack for smoketests/configForm.php
if (empty($config->conf['HTML'])) return;
$context = new HTMLPurifier_Context();
$this->generator->generateFromTokens(array(), $config, $context);
}
/**
* Main function that renders object or aspect of that object
* @note Parameters vary depending on printer

View File

@@ -38,18 +38,19 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
/**
* Returns HTML output for a configuration form
* @param $config Configuration object of current form state
* @param $ns Optional namespace(s) to restrict form to
* @param $allowed Optional namespace(s) and directives to restrict form to.
*/
function render($config, $ns = true) {
function render($config, $allowed = true, $render_controls = true) {
$this->config = $config;
if ($ns === true) {
$all = $config->getAll();
} else {
if (is_string($ns)) $ns = array($ns);
foreach ($ns as $n) {
$all = array($n => $config->getBatch($n));
}
$this->prepareGenerator($config);
$allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed);
$all = array();
foreach ($allowed as $key) {
list($ns, $directive) = $key;
$all[$ns][$directive] = $config->get($ns, $directive);
}
$ret = '';
$ret .= $this->start('table', array('class' => 'hp-config'));
$ret .= $this->start('thead');
@@ -61,13 +62,16 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
foreach ($all as $ns => $directives) {
$ret .= $this->renderNamespace($ns, $directives);
}
$ret .= $this->start('tfoot');
$ret .= $this->start('tr');
$ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls'));
$ret .= '<input type="submit" value="Submit" /> [<a href="?">Reset</a>]';
$ret .= $this->end('td');
$ret .= $this->end('tr');
$ret .= $this->end('tfoot');
if ($render_controls) {
$ret .= $this->start('tfoot');
$ret .= $this->start('tr');
$ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls'));
$ret .= $this->elementEmpty('input', array('type' => 'Submit', 'value' => 'Submit'));
$ret .= '[<a href="?">Reset</a>]';
$ret .= $this->end('td');
$ret .= $this->end('tr');
$ret .= $this->end('tfoot');
}
$ret .= $this->end('table');
return $ret;
}
@@ -93,11 +97,20 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
$url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL);
$ret .= $this->start('a', array('href' => $url));
}
$attr = array('for' => "{$this->name}:$ns.$directive");
// crop directive name if it's too long
if (strlen($directive) < 14) {
$directive_disp = $directive;
} else {
$directive_disp = substr($directive, 0, 12) . '...';
$attr['title'] = $directive;
}
$ret .= $this->element(
'label',
"%$ns.$directive",
$directive_disp,
// component printers must create an element with this id
array('for' => "{$this->name}:$ns.$directive")
$attr
);
if ($this->docURL) $ret .= $this->end('a');
$ret .= $this->end('th');
@@ -136,6 +149,7 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer
$this->obj = $obj;
}
function render($ns, $directive, $value, $name, $config) {
$this->prepareGenerator($config);
$ret = '';
$ret .= $this->start('label', array('for' => "$name:Null_$ns.$directive"));
$ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose'));
@@ -145,7 +159,7 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer
'type' => 'checkbox',
'value' => '1',
'class' => 'null-toggle',
'name' => "$name:Null_$ns.$directive",
'name' => "$name"."[Null_$ns.$directive]",
'id' => "$name:Null_$ns.$directive",
'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!!
);
@@ -163,6 +177,7 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer
*/
class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer {
function render($ns, $directive, $value, $name, $config) {
$this->prepareGenerator($config);
// this should probably be split up a little
$ret = '';
$def = $config->def->info[$ns][$directive];
@@ -193,7 +208,6 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer {
$value = serialize($value);
}
$attr = array(
'type' => 'text',
'name' => "$name"."[$ns.$directive]",
'id' => "$name:$ns.$directive"
);
@@ -208,6 +222,7 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer {
$ret .= $this->end('select');
} else {
$attr['value'] = $value;
$attr['type'] = 'text';
$ret .= $this->elementEmpty('input', $attr);
}
return $ret;
@@ -219,8 +234,8 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer {
*/
class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer {
function render($ns, $directive, $value, $name, $config) {
$this->prepareGenerator($config);
$ret = '';
$ret .= $this->start('div', array('id' => "$name:$ns.$directive"));
$ret .= $this->start('label', array('for' => "$name:Yes_$ns.$directive"));