1: <?php
2:
3: /**
4: * Defines common attribute collections that modules reference
5: */
6:
7: class HTMLPurifier_AttrCollections
8: {
9:
10: /**
11: * Associative array of attribute collections, indexed by name.
12: * @type array
13: */
14: public $info = array();
15:
16: /**
17: * Performs all expansions on internal data for use by other inclusions
18: * It also collects all attribute collection extensions from
19: * modules
20: * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
21: * @param HTMLPurifier_HTMLModule[] $modules Hash array of HTMLPurifier_HTMLModule members
22: */
23: public function __construct($attr_types, $modules)
24: {
25: $this->doConstruct($attr_types, $modules);
26: }
27:
28: public function doConstruct($attr_types, $modules)
29: {
30: // load extensions from the modules
31: foreach ($modules as $module) {
32: foreach ($module->attr_collections as $coll_i => $coll) {
33: if (!isset($this->info[$coll_i])) {
34: $this->info[$coll_i] = array();
35: }
36: foreach ($coll as $attr_i => $attr) {
37: if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
38: // merge in includes
39: $this->info[$coll_i][$attr_i] = array_merge(
40: $this->info[$coll_i][$attr_i],
41: $attr
42: );
43: continue;
44: }
45: $this->info[$coll_i][$attr_i] = $attr;
46: }
47: }
48: }
49: // perform internal expansions and inclusions
50: foreach ($this->info as $name => $attr) {
51: // merge attribute collections that include others
52: $this->performInclusions($this->info[$name]);
53: // replace string identifiers with actual attribute objects
54: $this->expandIdentifiers($this->info[$name], $attr_types);
55: }
56: }
57:
58: /**
59: * Takes a reference to an attribute associative array and performs
60: * all inclusions specified by the zero index.
61: * @param array &$attr Reference to attribute array
62: */
63: public function performInclusions(&$attr)
64: {
65: if (!isset($attr[0])) {
66: return;
67: }
68: $merge = $attr[0];
69: $seen = array(); // recursion guard
70: // loop through all the inclusions
71: for ($i = 0; isset($merge[$i]); $i++) {
72: if (isset($seen[$merge[$i]])) {
73: continue;
74: }
75: $seen[$merge[$i]] = true;
76: // foreach attribute of the inclusion, copy it over
77: if (!isset($this->info[$merge[$i]])) {
78: continue;
79: }
80: foreach ($this->info[$merge[$i]] as $key => $value) {
81: if (isset($attr[$key])) {
82: continue;
83: } // also catches more inclusions
84: $attr[$key] = $value;
85: }
86: if (isset($this->info[$merge[$i]][0])) {
87: // recursion
88: $merge = array_merge($merge, $this->info[$merge[$i]][0]);
89: }
90: }
91: unset($attr[0]);
92: }
93:
94: /**
95: * Expands all string identifiers in an attribute array by replacing
96: * them with the appropriate values inside HTMLPurifier_AttrTypes
97: * @param array &$attr Reference to attribute array
98: * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
99: */
100: public function expandIdentifiers(&$attr, $attr_types)
101: {
102: // because foreach will process new elements we add, make sure we
103: // skip duplicates
104: $processed = array();
105:
106: foreach ($attr as $def_i => $def) {
107: // skip inclusions
108: if ($def_i === 0) {
109: continue;
110: }
111:
112: if (isset($processed[$def_i])) {
113: continue;
114: }
115:
116: // determine whether or not attribute is required
117: if ($required = (strpos($def_i, '*') !== false)) {
118: // rename the definition
119: unset($attr[$def_i]);
120: $def_i = trim($def_i, '*');
121: $attr[$def_i] = $def;
122: }
123:
124: $processed[$def_i] = true;
125:
126: // if we've already got a literal object, move on
127: if (is_object($def)) {
128: // preserve previous required
129: $attr[$def_i]->required = ($required || $attr[$def_i]->required);
130: continue;
131: }
132:
133: if ($def === false) {
134: unset($attr[$def_i]);
135: continue;
136: }
137:
138: if ($t = $attr_types->get($def)) {
139: $attr[$def_i] = $t;
140: $attr[$def_i]->required = $required;
141: } else {
142: unset($attr[$def_i]);
143: }
144: }
145: }
146: }
147:
148: // vim: et sw=4 sts=4
149: