2010-09-08 23:14:17 -04:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Defines common attribute collections that modules reference
|
|
|
|
*/
|
|
|
|
|
|
|
|
class HTMLPurifier_AttrCollections
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
2016-02-09 05:06:17 -05:00
|
|
|
* Associative array of attribute collections, indexed by name.
|
|
|
|
* @type array
|
2010-09-08 23:14:17 -04:00
|
|
|
*/
|
|
|
|
public $info = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Performs all expansions on internal data for use by other inclusions
|
|
|
|
* It also collects all attribute collection extensions from
|
|
|
|
* modules
|
2016-02-09 05:06:17 -05:00
|
|
|
* @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
|
|
|
|
* @param HTMLPurifier_HTMLModule[] $modules Hash array of HTMLPurifier_HTMLModule members
|
2010-09-08 23:14:17 -04:00
|
|
|
*/
|
2016-02-09 05:06:17 -05:00
|
|
|
public function __construct($attr_types, $modules)
|
|
|
|
{
|
2010-09-08 23:14:17 -04:00
|
|
|
// load extensions from the modules
|
|
|
|
foreach ($modules as $module) {
|
|
|
|
foreach ($module->attr_collections as $coll_i => $coll) {
|
|
|
|
if (!isset($this->info[$coll_i])) {
|
|
|
|
$this->info[$coll_i] = array();
|
|
|
|
}
|
|
|
|
foreach ($coll as $attr_i => $attr) {
|
|
|
|
if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
|
|
|
|
// merge in includes
|
|
|
|
$this->info[$coll_i][$attr_i] = array_merge(
|
2016-02-09 05:06:17 -05:00
|
|
|
$this->info[$coll_i][$attr_i],
|
|
|
|
$attr
|
|
|
|
);
|
2010-09-08 23:14:17 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$this->info[$coll_i][$attr_i] = $attr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// perform internal expansions and inclusions
|
|
|
|
foreach ($this->info as $name => $attr) {
|
|
|
|
// merge attribute collections that include others
|
|
|
|
$this->performInclusions($this->info[$name]);
|
|
|
|
// replace string identifiers with actual attribute objects
|
|
|
|
$this->expandIdentifiers($this->info[$name], $attr_types);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Takes a reference to an attribute associative array and performs
|
|
|
|
* all inclusions specified by the zero index.
|
2016-02-09 05:06:17 -05:00
|
|
|
* @param array &$attr Reference to attribute array
|
2010-09-08 23:14:17 -04:00
|
|
|
*/
|
2016-02-09 05:06:17 -05:00
|
|
|
public function performInclusions(&$attr)
|
|
|
|
{
|
|
|
|
if (!isset($attr[0])) {
|
|
|
|
return;
|
|
|
|
}
|
2010-09-08 23:14:17 -04:00
|
|
|
$merge = $attr[0];
|
|
|
|
$seen = array(); // recursion guard
|
|
|
|
// loop through all the inclusions
|
|
|
|
for ($i = 0; isset($merge[$i]); $i++) {
|
2016-02-09 05:06:17 -05:00
|
|
|
if (isset($seen[$merge[$i]])) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-09-08 23:14:17 -04:00
|
|
|
$seen[$merge[$i]] = true;
|
|
|
|
// foreach attribute of the inclusion, copy it over
|
2016-02-09 05:06:17 -05:00
|
|
|
if (!isset($this->info[$merge[$i]])) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-09-08 23:14:17 -04:00
|
|
|
foreach ($this->info[$merge[$i]] as $key => $value) {
|
2016-02-09 05:06:17 -05:00
|
|
|
if (isset($attr[$key])) {
|
|
|
|
continue;
|
|
|
|
} // also catches more inclusions
|
2010-09-08 23:14:17 -04:00
|
|
|
$attr[$key] = $value;
|
|
|
|
}
|
|
|
|
if (isset($this->info[$merge[$i]][0])) {
|
|
|
|
// recursion
|
|
|
|
$merge = array_merge($merge, $this->info[$merge[$i]][0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unset($attr[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Expands all string identifiers in an attribute array by replacing
|
|
|
|
* them with the appropriate values inside HTMLPurifier_AttrTypes
|
2016-02-09 05:06:17 -05:00
|
|
|
* @param array &$attr Reference to attribute array
|
|
|
|
* @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
|
2010-09-08 23:14:17 -04:00
|
|
|
*/
|
2016-02-09 05:06:17 -05:00
|
|
|
public function expandIdentifiers(&$attr, $attr_types)
|
|
|
|
{
|
2010-09-08 23:14:17 -04:00
|
|
|
// because foreach will process new elements we add, make sure we
|
|
|
|
// skip duplicates
|
|
|
|
$processed = array();
|
|
|
|
|
|
|
|
foreach ($attr as $def_i => $def) {
|
|
|
|
// skip inclusions
|
2016-02-09 05:06:17 -05:00
|
|
|
if ($def_i === 0) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-09-08 23:14:17 -04:00
|
|
|
|
2016-02-09 05:06:17 -05:00
|
|
|
if (isset($processed[$def_i])) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-09-08 23:14:17 -04:00
|
|
|
|
|
|
|
// determine whether or not attribute is required
|
|
|
|
if ($required = (strpos($def_i, '*') !== false)) {
|
|
|
|
// rename the definition
|
|
|
|
unset($attr[$def_i]);
|
|
|
|
$def_i = trim($def_i, '*');
|
|
|
|
$attr[$def_i] = $def;
|
|
|
|
}
|
|
|
|
|
|
|
|
$processed[$def_i] = true;
|
|
|
|
|
|
|
|
// if we've already got a literal object, move on
|
|
|
|
if (is_object($def)) {
|
|
|
|
// preserve previous required
|
|
|
|
$attr[$def_i]->required = ($required || $attr[$def_i]->required);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($def === false) {
|
|
|
|
unset($attr[$def_i]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($t = $attr_types->get($def)) {
|
|
|
|
$attr[$def_i] = $t;
|
|
|
|
$attr[$def_i]->required = $required;
|
|
|
|
} else {
|
|
|
|
unset($attr[$def_i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// vim: et sw=4 sts=4
|