1 : <?php
2 :
3 : /**
4 : * Defines common attribute collections that modules reference
5 : */
6 :
7 : class HTMLPurifier_AttrCollections
8 1 : {
9 :
10 : /**
11 : * Associative array of attribute collections, indexed by name
12 : */
13 : public $info = array();
14 :
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
21 : */
22 : public function __construct($attr_types, $modules) {
23 : // load extensions from the modules
24 1 : foreach ($modules as $module) {
25 1 : foreach ($module->attr_collections as $coll_i => $coll) {
26 1 : if (!isset($this->info[$coll_i])) {
27 1 : $this->info[$coll_i] = array();
28 1 : }
29 1 : foreach ($coll as $attr_i => $attr) {
30 1 : if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
31 : // merge in includes
32 1 : $this->info[$coll_i][$attr_i] = array_merge(
33 1 : $this->info[$coll_i][$attr_i], $attr);
34 1 : continue;
35 : }
36 1 : $this->info[$coll_i][$attr_i] = $attr;
37 1 : }
38 1 : }
39 1 : }
40 : // perform internal expansions and inclusions
41 1 : foreach ($this->info as $name => $attr) {
42 : // merge attribute collections that include others
43 1 : $this->performInclusions($this->info[$name]);
44 : // replace string identifiers with actual attribute objects
45 1 : $this->expandIdentifiers($this->info[$name], $attr_types);
46 1 : }
47 1 : }
48 :
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
53 : */
54 : public function performInclusions(&$attr) {
55 1 : if (!isset($attr[0])) return;
56 1 : $merge = $attr[0];
57 1 : $seen = array(); // recursion guard
58 : // loop through all the inclusions
59 1 : for ($i = 0; isset($merge[$i]); $i++) {
60 1 : if (isset($seen[$merge[$i]])) continue;
61 1 : $seen[$merge[$i]] = true;
62 : // foreach attribute of the inclusion, copy it over
63 1 : if (!isset($this->info[$merge[$i]])) continue;
64 1 : foreach ($this->info[$merge[$i]] as $key => $value) {
65 1 : if (isset($attr[$key])) continue; // also catches more inclusions
66 1 : $attr[$key] = $value;
67 1 : }
68 1 : if (isset($this->info[$merge[$i]][0])) {
69 : // recursion
70 0 : $merge = array_merge($merge, $this->info[$merge[$i]][0]);
71 0 : }
72 1 : }
73 1 : unset($attr[0]);
74 1 : }
75 :
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
81 : */
82 : public function expandIdentifiers(&$attr, $attr_types) {
83 :
84 : // because foreach will process new elements we add, make sure we
85 : // skip duplicates
86 1 : $processed = array();
87 :
88 1 : foreach ($attr as $def_i => $def) {
89 : // skip inclusions
90 1 : if ($def_i === 0) continue;
91 :
92 1 : if (isset($processed[$def_i])) continue;
93 :
94 : // determine whether or not attribute is required
95 1 : if ($required = (strpos($def_i, '*') !== false)) {
96 : // rename the definition
97 1 : unset($attr[$def_i]);
98 1 : $def_i = trim($def_i, '*');
99 1 : $attr[$def_i] = $def;
100 1 : }
101 :
102 1 : $processed[$def_i] = true;
103 :
104 : // if we've already got a literal object, move on
105 1 : if (is_object($def)) {
106 : // preserve previous required
107 1 : $attr[$def_i]->required = ($required || $attr[$def_i]->required);
108 1 : continue;
109 : }
110 :
111 1 : if ($def === false) {
112 0 : unset($attr[$def_i]);
113 0 : continue;
114 : }
115 :
116 1 : if ($t = $attr_types->get($def)) {
117 1 : $attr[$def_i] = $t;
118 1 : $attr[$def_i]->required = $required;
119 1 : } else {
120 0 : unset($attr[$def_i]);
121 : }
122 1 : }
123 :
124 1 : }
125 :
126 : }
127 :
|