Yaffs site version 1.1
[yaffs-website] / vendor / ezyang / htmlpurifier / library / HTMLPurifier / AttrCollections.php
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