Release 2.0.1, merged in 1181 to HEAD.
[htmlpurifier.git] / library / HTMLPurifier / AttrCollections.php
blob0aa55f128f134e18728b11ce8295cbd731031d3b
1 <?php
3 require_once 'HTMLPurifier/AttrTypes.php';
5 /**
6 * Defines common attribute collections that modules reference
7 */
9 class HTMLPurifier_AttrCollections
12 /**
13 * Associative array of attribute collections, indexed by name
15 var $info = array();
17 /**
18 * Performs all expansions on internal data for use by other inclusions
19 * It also collects all attribute collection extensions from
20 * modules
21 * @param $attr_types HTMLPurifier_AttrTypes instance
22 * @param $modules Hash array of HTMLPurifier_HTMLModule members
24 function HTMLPurifier_AttrCollections($attr_types, $modules) {
25 // load extensions from the modules
26 foreach ($modules as $module) {
27 foreach ($module->attr_collections as $coll_i => $coll) {
28 if (!isset($this->info[$coll_i])) {
29 $this->info[$coll_i] = array();
31 foreach ($coll as $attr_i => $attr) {
32 if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
33 // merge in includes
34 $this->info[$coll_i][$attr_i] = array_merge(
35 $this->info[$coll_i][$attr_i], $attr);
36 continue;
38 $this->info[$coll_i][$attr_i] = $attr;
42 // perform internal expansions and inclusions
43 foreach ($this->info as $name => $attr) {
44 // merge attribute collections that include others
45 $this->performInclusions($this->info[$name]);
46 // replace string identifiers with actual attribute objects
47 $this->expandIdentifiers($this->info[$name], $attr_types);
51 /**
52 * Takes a reference to an attribute associative array and performs
53 * all inclusions specified by the zero index.
54 * @param &$attr Reference to attribute array
56 function performInclusions(&$attr) {
57 if (!isset($attr[0])) return;
58 $merge = $attr[0];
59 $seen = array(); // recursion guard
60 // loop through all the inclusions
61 for ($i = 0; isset($merge[$i]); $i++) {
62 if (isset($seen[$merge[$i]])) continue;
63 $seen[$merge[$i]] = true;
64 // foreach attribute of the inclusion, copy it over
65 if (!isset($this->info[$merge[$i]])) continue;
66 foreach ($this->info[$merge[$i]] as $key => $value) {
67 if (isset($attr[$key])) continue; // also catches more inclusions
68 $attr[$key] = $value;
70 if (isset($this->info[$merge[$i]][0])) {
71 // recursion
72 $merge = array_merge($merge, $this->info[$merge[$i]][0]);
75 unset($attr[0]);
78 /**
79 * Expands all string identifiers in an attribute array by replacing
80 * them with the appropriate values inside HTMLPurifier_AttrTypes
81 * @param &$attr Reference to attribute array
82 * @param $attr_types HTMLPurifier_AttrTypes instance
84 function expandIdentifiers(&$attr, $attr_types) {
86 // because foreach will process new elements we add, make sure we
87 // skip duplicates
88 $processed = array();
90 foreach ($attr as $def_i => $def) {
91 // skip inclusions
92 if ($def_i === 0) continue;
94 if (isset($processed[$def_i])) continue;
96 // determine whether or not attribute is required
97 if ($required = (strpos($def_i, '*') !== false)) {
98 // rename the definition
99 unset($attr[$def_i]);
100 $def_i = trim($def_i, '*');
101 $attr[$def_i] = $def;
104 $processed[$def_i] = true;
106 // if we've already got a literal object, move on
107 if (is_object($def)) {
108 // preserve previous required
109 $attr[$def_i]->required = ($required || $attr[$def_i]->required);
110 continue;
113 if ($def === false) {
114 unset($attr[$def_i]);
115 continue;
118 if ($t = $attr_types->get($def)) {
119 $attr[$def_i] = $t;
120 $attr[$def_i]->required = $required;
121 } else {
122 unset($attr[$def_i]);