128 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * Defines common attribute collections that modules reference
 | |
|  */
 | |
| 
 | |
| class HTMLPurifier_AttrCollections
 | |
| {
 | |
| 
 | |
|     /**
 | |
|      * Associative array of attribute collections, indexed by name
 | |
|      */
 | |
|     public $info = array();
 | |
| 
 | |
|     /**
 | |
|      * Performs all expansions on internal data for use by other inclusions
 | |
|      * It also collects all attribute collection extensions from
 | |
|      * modules
 | |
|      * @param $attr_types HTMLPurifier_AttrTypes instance
 | |
|      * @param $modules Hash array of HTMLPurifier_HTMLModule members
 | |
|      */
 | |
|     public function __construct($attr_types, $modules) {
 | |
|         // load extensions from the modules
 | |
|         foreach ($modules as $module) {
 | |
|             foreach ($module->attr_collections as $coll_i => $coll) {
 | |
|                 if (!isset($this->info[$coll_i])) {
 | |
|                     $this->info[$coll_i] = array();
 | |
|                 }
 | |
|                 foreach ($coll as $attr_i => $attr) {
 | |
|                     if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
 | |
|                         // merge in includes
 | |
|                         $this->info[$coll_i][$attr_i] = array_merge(
 | |
|                             $this->info[$coll_i][$attr_i], $attr);
 | |
|                         continue;
 | |
|                     }
 | |
|                     $this->info[$coll_i][$attr_i] = $attr;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         // perform internal expansions and inclusions
 | |
|         foreach ($this->info as $name => $attr) {
 | |
|             // merge attribute collections that include others
 | |
|             $this->performInclusions($this->info[$name]);
 | |
|             // replace string identifiers with actual attribute objects
 | |
|             $this->expandIdentifiers($this->info[$name], $attr_types);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Takes a reference to an attribute associative array and performs
 | |
|      * all inclusions specified by the zero index.
 | |
|      * @param &$attr Reference to attribute array
 | |
|      */
 | |
|     public function performInclusions(&$attr) {
 | |
|         if (!isset($attr[0])) return;
 | |
|         $merge = $attr[0];
 | |
|         $seen  = array(); // recursion guard
 | |
|         // loop through all the inclusions
 | |
|         for ($i = 0; isset($merge[$i]); $i++) {
 | |
|             if (isset($seen[$merge[$i]])) continue;
 | |
|             $seen[$merge[$i]] = true;
 | |
|             // foreach attribute of the inclusion, copy it over
 | |
|             if (!isset($this->info[$merge[$i]])) continue;
 | |
|             foreach ($this->info[$merge[$i]] as $key => $value) {
 | |
|                 if (isset($attr[$key])) continue; // also catches more inclusions
 | |
|                 $attr[$key] = $value;
 | |
|             }
 | |
|             if (isset($this->info[$merge[$i]][0])) {
 | |
|                 // recursion
 | |
|                 $merge = array_merge($merge, $this->info[$merge[$i]][0]);
 | |
|             }
 | |
|         }
 | |
|         unset($attr[0]);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Expands all string identifiers in an attribute array by replacing
 | |
|      * them with the appropriate values inside HTMLPurifier_AttrTypes
 | |
|      * @param &$attr Reference to attribute array
 | |
|      * @param $attr_types HTMLPurifier_AttrTypes instance
 | |
|      */
 | |
|     public function expandIdentifiers(&$attr, $attr_types) {
 | |
| 
 | |
|         // because foreach will process new elements we add, make sure we
 | |
|         // skip duplicates
 | |
|         $processed = array();
 | |
| 
 | |
|         foreach ($attr as $def_i => $def) {
 | |
|             // skip inclusions
 | |
|             if ($def_i === 0) continue;
 | |
| 
 | |
|             if (isset($processed[$def_i])) continue;
 | |
| 
 | |
|             // determine whether or not attribute is required
 | |
|             if ($required = (strpos($def_i, '*') !== false)) {
 | |
|                 // rename the definition
 | |
|                 unset($attr[$def_i]);
 | |
|                 $def_i = trim($def_i, '*');
 | |
|                 $attr[$def_i] = $def;
 | |
|             }
 | |
| 
 | |
|             $processed[$def_i] = true;
 | |
| 
 | |
|             // if we've already got a literal object, move on
 | |
|             if (is_object($def)) {
 | |
|                 // preserve previous required
 | |
|                 $attr[$def_i]->required = ($required || $attr[$def_i]->required);
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             if ($def === false) {
 | |
|                 unset($attr[$def_i]);
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             if ($t = $attr_types->get($def)) {
 | |
|                 $attr[$def_i] = $t;
 | |
|                 $attr[$def_i]->required = $required;
 | |
|             } else {
 | |
|                 unset($attr[$def_i]);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| // vim: et sw=4 sts=4
 |