Make extractBody not terminate prematurely on first </body>.
[htmlpurifier.git] / library / HTMLPurifier / AttrCollections.php
blob555b86d0428d7e3770ea58d1745d80d0bd2f73cf
1 <?php
3 /**
4 * Defines common attribute collections that modules reference
5 */
7 class HTMLPurifier_AttrCollections
10 /**
11 * Associative array of attribute collections, indexed by name
13 public $info = array();
15 /**
16 * Performs all expansions on internal data for use by other inclusions
17 * It also collects all attribute collection extensions from
18 * modules
19 * @param $attr_types HTMLPurifier_AttrTypes instance
20 * @param $modules Hash array of HTMLPurifier_HTMLModule members
22 public function __construct($attr_types, $modules) {
23 // load extensions from the modules
24 foreach ($modules as $module) {
25 foreach ($module->attr_collections as $coll_i => $coll) {
26 if (!isset($this->info[$coll_i])) {
27 $this->info[$coll_i] = array();
29 foreach ($coll as $attr_i => $attr) {
30 if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
31 // merge in includes
32 $this->info[$coll_i][$attr_i] = array_merge(
33 $this->info[$coll_i][$attr_i], $attr);
34 continue;
36 $this->info[$coll_i][$attr_i] = $attr;
40 // perform internal expansions and inclusions
41 foreach ($this->info as $name => $attr) {
42 // merge attribute collections that include others
43 $this->performInclusions($this->info[$name]);
44 // replace string identifiers with actual attribute objects
45 $this->expandIdentifiers($this->info[$name], $attr_types);
49 /**
50 * Takes a reference to an attribute associative array and performs
51 * all inclusions specified by the zero index.
52 * @param &$attr Reference to attribute array
54 public function performInclusions(&$attr) {
55 if (!isset($attr[0])) return;
56 $merge = $attr[0];
57 $seen = array(); // recursion guard
58 // loop through all the inclusions
59 for ($i = 0; isset($merge[$i]); $i++) {
60 if (isset($seen[$merge[$i]])) continue;
61 $seen[$merge[$i]] = true;
62 // foreach attribute of the inclusion, copy it over
63 if (!isset($this->info[$merge[$i]])) continue;
64 foreach ($this->info[$merge[$i]] as $key => $value) {
65 if (isset($attr[$key])) continue; // also catches more inclusions
66 $attr[$key] = $value;
68 if (isset($this->info[$merge[$i]][0])) {
69 // recursion
70 $merge = array_merge($merge, $this->info[$merge[$i]][0]);
73 unset($attr[0]);
76 /**
77 * Expands all string identifiers in an attribute array by replacing
78 * them with the appropriate values inside HTMLPurifier_AttrTypes
79 * @param &$attr Reference to attribute array
80 * @param $attr_types HTMLPurifier_AttrTypes instance
82 public function expandIdentifiers(&$attr, $attr_types) {
84 // because foreach will process new elements we add, make sure we
85 // skip duplicates
86 $processed = array();
88 foreach ($attr as $def_i => $def) {
89 // skip inclusions
90 if ($def_i === 0) continue;
92 if (isset($processed[$def_i])) continue;
94 // determine whether or not attribute is required
95 if ($required = (strpos($def_i, '*') !== false)) {
96 // rename the definition
97 unset($attr[$def_i]);
98 $def_i = trim($def_i, '*');
99 $attr[$def_i] = $def;
102 $processed[$def_i] = true;
104 // if we've already got a literal object, move on
105 if (is_object($def)) {
106 // preserve previous required
107 $attr[$def_i]->required = ($required || $attr[$def_i]->required);
108 continue;
111 if ($def === false) {
112 unset($attr[$def_i]);
113 continue;
116 if ($t = $attr_types->get($def)) {
117 $attr[$def_i] = $t;
118 $attr[$def_i]->required = $required;
119 } else {
120 unset($attr[$def_i]);
128 // vim: et sw=4 sts=4