File indexing completed on 2024-12-22 05:36:21
0001 <?php 0002 0003 /** 0004 * @todo Unit test 0005 */ 0006 class HTMLPurifier_ContentSets 0007 { 0008 0009 /** 0010 * List of content set strings (pipe separators) indexed by name. 0011 * @type array 0012 */ 0013 public $info = array(); 0014 0015 /** 0016 * List of content set lookups (element => true) indexed by name. 0017 * @type array 0018 * @note This is in HTMLPurifier_HTMLDefinition->info_content_sets 0019 */ 0020 public $lookup = array(); 0021 0022 /** 0023 * Synchronized list of defined content sets (keys of info). 0024 * @type array 0025 */ 0026 protected $keys = array(); 0027 /** 0028 * Synchronized list of defined content values (values of info). 0029 * @type array 0030 */ 0031 protected $values = array(); 0032 0033 /** 0034 * Merges in module's content sets, expands identifiers in the content 0035 * sets and populates the keys, values and lookup member variables. 0036 * @param HTMLPurifier_HTMLModule[] $modules List of HTMLPurifier_HTMLModule 0037 */ 0038 public function __construct($modules) 0039 { 0040 if (!is_array($modules)) { 0041 $modules = array($modules); 0042 } 0043 // populate content_sets based on module hints 0044 // sorry, no way of overloading 0045 foreach ($modules as $module) { 0046 foreach ($module->content_sets as $key => $value) { 0047 $temp = $this->convertToLookup($value); 0048 if (isset($this->lookup[$key])) { 0049 // add it into the existing content set 0050 $this->lookup[$key] = array_merge($this->lookup[$key], $temp); 0051 } else { 0052 $this->lookup[$key] = $temp; 0053 } 0054 } 0055 } 0056 $old_lookup = false; 0057 while ($old_lookup !== $this->lookup) { 0058 $old_lookup = $this->lookup; 0059 foreach ($this->lookup as $i => $set) { 0060 $add = array(); 0061 foreach ($set as $element => $x) { 0062 if (isset($this->lookup[$element])) { 0063 $add += $this->lookup[$element]; 0064 unset($this->lookup[$i][$element]); 0065 } 0066 } 0067 $this->lookup[$i] += $add; 0068 } 0069 } 0070 0071 foreach ($this->lookup as $key => $lookup) { 0072 $this->info[$key] = implode(' | ', array_keys($lookup)); 0073 } 0074 $this->keys = array_keys($this->info); 0075 $this->values = array_values($this->info); 0076 } 0077 0078 /** 0079 * Accepts a definition; generates and assigns a ChildDef for it 0080 * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef reference 0081 * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef 0082 */ 0083 public function generateChildDef(&$def, $module) 0084 { 0085 if (!empty($def->child)) { // already done! 0086 return; 0087 } 0088 $content_model = $def->content_model; 0089 if (is_string($content_model)) { 0090 // Assume that $this->keys is alphanumeric 0091 $def->content_model = preg_replace_callback( 0092 '/\b(' . implode('|', $this->keys) . ')\b/', 0093 array($this, 'generateChildDefCallback'), 0094 $content_model 0095 ); 0096 //$def->content_model = str_replace( 0097 // $this->keys, $this->values, $content_model); 0098 } 0099 $def->child = $this->getChildDef($def, $module); 0100 } 0101 0102 public function generateChildDefCallback($matches) 0103 { 0104 return $this->info[$matches[0]]; 0105 } 0106 0107 /** 0108 * Instantiates a ChildDef based on content_model and content_model_type 0109 * member variables in HTMLPurifier_ElementDef 0110 * @note This will also defer to modules for custom HTMLPurifier_ChildDef 0111 * subclasses that need content set expansion 0112 * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef to have ChildDef extracted 0113 * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef 0114 * @return HTMLPurifier_ChildDef corresponding to ElementDef 0115 */ 0116 public function getChildDef($def, $module) 0117 { 0118 $value = $def->content_model; 0119 if (is_object($value)) { 0120 trigger_error( 0121 'Literal object child definitions should be stored in '. 0122 'ElementDef->child not ElementDef->content_model', 0123 E_USER_NOTICE 0124 ); 0125 return $value; 0126 } 0127 switch ($def->content_model_type) { 0128 case 'required': 0129 return new HTMLPurifier_ChildDef_Required($value); 0130 case 'optional': 0131 return new HTMLPurifier_ChildDef_Optional($value); 0132 case 'empty': 0133 return new HTMLPurifier_ChildDef_Empty(); 0134 case 'custom': 0135 return new HTMLPurifier_ChildDef_Custom($value); 0136 } 0137 // defer to its module 0138 $return = false; 0139 if ($module->defines_child_def) { // save a func call 0140 $return = $module->getChildDef($def); 0141 } 0142 if ($return !== false) { 0143 return $return; 0144 } 0145 // error-out 0146 trigger_error( 0147 'Could not determine which ChildDef class to instantiate', 0148 E_USER_ERROR 0149 ); 0150 return false; 0151 } 0152 0153 /** 0154 * Converts a string list of elements separated by pipes into 0155 * a lookup array. 0156 * @param string $string List of elements 0157 * @return array Lookup array of elements 0158 */ 0159 protected function convertToLookup($string) 0160 { 0161 $array = explode('|', str_replace(' ', '', $string)); 0162 $ret = array(); 0163 foreach ($array as $k) { 0164 $ret[$k] = true; 0165 } 0166 return $ret; 0167 } 0168 } 0169 0170 // vim: et sw=4 sts=4