1 <?php 2 3 /** 4 * @todo Unit test 5 */ 6 class HTMLPurifier_ContentSets 7 { 8 9 /** 10 * List of content set strings (pipe separators) indexed by name. 11 * @type array 12 */ 13 public $info = array(); 14 15 /** 16 * List of content set lookups (element => true) indexed by name. 17 * @type array 18 * @note This is in HTMLPurifier_HTMLDefinition->info_content_sets 19 */ 20 public $lookup = array(); 21 22 /** 23 * Synchronized list of defined content sets (keys of info). 24 * @type array 25 */ 26 protected $keys = array(); 27 /** 28 * Synchronized list of defined content values (values of info). 29 * @type array 30 */ 31 protected $values = array(); 32 33 /** 34 * Merges in module's content sets, expands identifiers in the content 35 * sets and populates the keys, values and lookup member variables. 36 * @param HTMLPurifier_HTMLModule[] $modules List of HTMLPurifier_HTMLModule 37 */ 38 public function __construct($modules) 39 { 40 if (!is_array($modules)) { 41 $modules = array($modules); 42 } 43 // populate content_sets based on module hints 44 // sorry, no way of overloading 45 foreach ($modules as $module) { 46 foreach ($module->content_sets as $key => $value) { 47 $temp = $this->convertToLookup($value); 48 if (isset($this->lookup[$key])) { 49 // add it into the existing content set 50 $this->lookup[$key] = array_merge($this->lookup[$key], $temp); 51 } else { 52 $this->lookup[$key] = $temp; 53 } 54 } 55 } 56 $old_lookup = false; 57 while ($old_lookup !== $this->lookup) { 58 $old_lookup = $this->lookup; 59 foreach ($this->lookup as $i => $set) { 60 $add = array(); 61 foreach ($set as $element => $x) { 62 if (isset($this->lookup[$element])) { 63 $add += $this->lookup[$element]; 64 unset($this->lookup[$i][$element]); 65 } 66 } 67 $this->lookup[$i] += $add; 68 } 69 } 70 71 foreach ($this->lookup as $key => $lookup) { 72 $this->info[$key] = implode(' | ', array_keys($lookup)); 73 } 74 $this->keys = array_keys($this->info); 75 $this->values = array_values($this->info); 76 } 77 78 /** 79 * Accepts a definition; generates and assigns a ChildDef for it 80 * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef reference 81 * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef 82 */ 83 public function generateChildDef(&$def, $module) 84 { 85 if (!empty($def->child)) { // already done! 86 return; 87 } 88 $content_model = $def->content_model; 89 if (is_string($content_model)) { 90 // Assume that $this->keys is alphanumeric 91 $def->content_model = preg_replace_callback( 92 '/\b(' . implode('|', $this->keys) . ')\b/', 93 array($this, 'generateChildDefCallback'), 94 $content_model 95 ); 96 //$def->content_model = str_replace( 97 // $this->keys, $this->values, $content_model); 98 } 99 $def->child = $this->getChildDef($def, $module); 100 } 101 102 public function generateChildDefCallback($matches) 103 { 104 return $this->info[$matches[0]]; 105 } 106 107 /** 108 * Instantiates a ChildDef based on content_model and content_model_type 109 * member variables in HTMLPurifier_ElementDef 110 * @note This will also defer to modules for custom HTMLPurifier_ChildDef 111 * subclasses that need content set expansion 112 * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef to have ChildDef extracted 113 * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef 114 * @return HTMLPurifier_ChildDef corresponding to ElementDef 115 */ 116 public function getChildDef($def, $module) 117 { 118 $value = $def->content_model; 119 if (is_object($value)) { 120 trigger_error( 121 'Literal object child definitions should be stored in '. 122 'ElementDef->child not ElementDef->content_model', 123 E_USER_NOTICE 124 ); 125 return $value; 126 } 127 switch ($def->content_model_type) { 128 case 'required': 129 return new HTMLPurifier_ChildDef_Required($value); 130 case 'optional': 131 return new HTMLPurifier_ChildDef_Optional($value); 132 case 'empty': 133 return new HTMLPurifier_ChildDef_Empty(); 134 case 'custom': 135 return new HTMLPurifier_ChildDef_Custom($value); 136 } 137 // defer to its module 138 $return = false; 139 if ($module->defines_child_def) { // save a func call 140 $return = $module->getChildDef($def); 141 } 142 if ($return !== false) { 143 return $return; 144 } 145 // error-out 146 trigger_error( 147 'Could not determine which ChildDef class to instantiate', 148 E_USER_ERROR 149 ); 150 return false; 151 } 152 153 /** 154 * Converts a string list of elements separated by pipes into 155 * a lookup array. 156 * @param string $string List of elements 157 * @return array Lookup array of elements 158 */ 159 protected function convertToLookup($string) 160 { 161 $array = explode('|', str_replace(' ', '', $string)); 162 $ret = array(); 163 foreach ($array as $k) { 164 $ret[$k] = true; 165 } 166 return $ret; 167 } 168 } 169 170 // vim: et sw=4 sts=4
title
Description
Body
title
Description
Body
title
Description
Body
title
Body