Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/htmlpurifier/HTMLPurifier/HTMLModuleManager.php
Go to the documentation of this file.
00001 <?php
00002 
00003 class HTMLPurifier_HTMLModuleManager
00004 {
00005 
00009     public $doctypes;
00010 
00014     public $doctype;
00015 
00019     public $attrTypes;
00020 
00025     public $modules = array();
00026 
00032     public $registeredModules = array();
00033 
00039     public $userModules = array();
00040 
00045     public $elementLookup = array();
00046 
00048     public $prefixes = array('HTMLPurifier_HTMLModule_');
00049 
00050     public $contentSets;     
00051     public $attrCollections; 
00054     public $trusted = false;
00055 
00056     public function __construct() {
00057 
00058         // editable internal objects
00059         $this->attrTypes = new HTMLPurifier_AttrTypes();
00060         $this->doctypes  = new HTMLPurifier_DoctypeRegistry();
00061 
00062         // setup basic modules
00063         $common = array(
00064             'CommonAttributes', 'Text', 'Hypertext', 'List',
00065             'Presentation', 'Edit', 'Bdo', 'Tables', 'Image',
00066             'StyleAttribute',
00067             // Unsafe:
00068             'Scripting', 'Object',  'Forms',
00069             // Sorta legacy, but present in strict:
00070             'Name',
00071         );
00072         $transitional = array('Legacy', 'Target');
00073         $xml = array('XMLCommonAttributes');
00074         $non_xml = array('NonXMLCommonAttributes');
00075 
00076         // setup basic doctypes
00077         $this->doctypes->register(
00078             'HTML 4.01 Transitional', false,
00079             array_merge($common, $transitional, $non_xml),
00080             array('Tidy_Transitional', 'Tidy_Proprietary'),
00081             array(),
00082             '-//W3C//DTD HTML 4.01 Transitional//EN',
00083             'http://www.w3.org/TR/html4/loose.dtd'
00084         );
00085 
00086         $this->doctypes->register(
00087             'HTML 4.01 Strict', false,
00088             array_merge($common, $non_xml),
00089             array('Tidy_Strict', 'Tidy_Proprietary', 'Tidy_Name'),
00090             array(),
00091             '-//W3C//DTD HTML 4.01//EN',
00092             'http://www.w3.org/TR/html4/strict.dtd'
00093         );
00094 
00095         $this->doctypes->register(
00096             'XHTML 1.0 Transitional', true,
00097             array_merge($common, $transitional, $xml, $non_xml),
00098             array('Tidy_Transitional', 'Tidy_XHTML', 'Tidy_Proprietary', 'Tidy_Name'),
00099             array(),
00100             '-//W3C//DTD XHTML 1.0 Transitional//EN',
00101             'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'
00102         );
00103 
00104         $this->doctypes->register(
00105             'XHTML 1.0 Strict', true,
00106             array_merge($common, $xml, $non_xml),
00107             array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Strict', 'Tidy_Proprietary', 'Tidy_Name'),
00108             array(),
00109             '-//W3C//DTD XHTML 1.0 Strict//EN',
00110             'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
00111         );
00112 
00113         $this->doctypes->register(
00114             'XHTML 1.1', true,
00115             array_merge($common, $xml, array('Ruby')),
00116             array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Proprietary', 'Tidy_Strict', 'Tidy_Name'), // Tidy_XHTML1_1
00117             array(),
00118             '-//W3C//DTD XHTML 1.1//EN',
00119             'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'
00120         );
00121 
00122     }
00123 
00145     public function registerModule($module, $overload = false) {
00146         if (is_string($module)) {
00147             // attempt to load the module
00148             $original_module = $module;
00149             $ok = false;
00150             foreach ($this->prefixes as $prefix) {
00151                 $module = $prefix . $original_module;
00152                 if (class_exists($module)) {
00153                     $ok = true;
00154                     break;
00155                 }
00156             }
00157             if (!$ok) {
00158                 $module = $original_module;
00159                 if (!class_exists($module)) {
00160                     trigger_error($original_module . ' module does not exist',
00161                         E_USER_ERROR);
00162                     return;
00163                 }
00164             }
00165             $module = new $module();
00166         }
00167         if (empty($module->name)) {
00168             trigger_error('Module instance of ' . get_class($module) . ' must have name');
00169             return;
00170         }
00171         if (!$overload && isset($this->registeredModules[$module->name])) {
00172             trigger_error('Overloading ' . $module->name . ' without explicit overload parameter', E_USER_WARNING);
00173         }
00174         $this->registeredModules[$module->name] = $module;
00175     }
00176 
00181     public function addModule($module) {
00182         $this->registerModule($module);
00183         if (is_object($module)) $module = $module->name;
00184         $this->userModules[] = $module;
00185     }
00186 
00191     public function addPrefix($prefix) {
00192         $this->prefixes[] = $prefix;
00193     }
00194 
00200     public function setup($config) {
00201 
00202         $this->trusted = $config->get('HTML.Trusted');
00203 
00204         // generate
00205         $this->doctype = $this->doctypes->make($config);
00206         $modules = $this->doctype->modules;
00207 
00208         // take out the default modules that aren't allowed
00209         $lookup = $config->get('HTML.AllowedModules');
00210         $special_cases = $config->get('HTML.CoreModules');
00211 
00212         if (is_array($lookup)) {
00213             foreach ($modules as $k => $m) {
00214                 if (isset($special_cases[$m])) continue;
00215                 if (!isset($lookup[$m])) unset($modules[$k]);
00216             }
00217         }
00218 
00219         // custom modules
00220         if ($config->get('HTML.Proprietary')) {
00221             $modules[] = 'Proprietary';
00222         }
00223         if ($config->get('HTML.SafeObject')) {
00224             $modules[] = 'SafeObject';
00225         }
00226         if ($config->get('HTML.SafeEmbed')) {
00227             $modules[] = 'SafeEmbed';
00228         }
00229         if ($config->get('HTML.Nofollow')) {
00230             $modules[] = 'Nofollow';
00231         }
00232 
00233         // merge in custom modules
00234         $modules = array_merge($modules, $this->userModules);
00235 
00236         foreach ($modules as $module) {
00237             $this->processModule($module);
00238             $this->modules[$module]->setup($config);
00239         }
00240 
00241         foreach ($this->doctype->tidyModules as $module) {
00242             $this->processModule($module);
00243             $this->modules[$module]->setup($config);
00244         }
00245 
00246         // prepare any injectors
00247         foreach ($this->modules as $module) {
00248             $n = array();
00249             foreach ($module->info_injector as $i => $injector) {
00250                 if (!is_object($injector)) {
00251                     $class = "HTMLPurifier_Injector_$injector";
00252                     $injector = new $class;
00253                 }
00254                 $n[$injector->name] = $injector;
00255             }
00256             $module->info_injector = $n;
00257         }
00258 
00259         // setup lookup table based on all valid modules
00260         foreach ($this->modules as $module) {
00261             foreach ($module->info as $name => $def) {
00262                 if (!isset($this->elementLookup[$name])) {
00263                     $this->elementLookup[$name] = array();
00264                 }
00265                 $this->elementLookup[$name][] = $module->name;
00266             }
00267         }
00268 
00269         // note the different choice
00270         $this->contentSets = new HTMLPurifier_ContentSets(
00271             // content set assembly deals with all possible modules,
00272             // not just ones deemed to be "safe"
00273             $this->modules
00274         );
00275         $this->attrCollections = new HTMLPurifier_AttrCollections(
00276             $this->attrTypes,
00277             // there is no way to directly disable a global attribute,
00278             // but using AllowedAttributes or simply not including
00279             // the module in your custom doctype should be sufficient
00280             $this->modules
00281         );
00282     }
00283 
00288     public function processModule($module) {
00289         if (!isset($this->registeredModules[$module]) || is_object($module)) {
00290             $this->registerModule($module);
00291         }
00292         $this->modules[$module] = $this->registeredModules[$module];
00293     }
00294 
00299     public function getElements() {
00300 
00301         $elements = array();
00302         foreach ($this->modules as $module) {
00303             if (!$this->trusted && !$module->safe) continue;
00304             foreach ($module->info as $name => $v) {
00305                 if (isset($elements[$name])) continue;
00306                 $elements[$name] = $this->getElement($name);
00307             }
00308         }
00309 
00310         // remove dud elements, this happens when an element that
00311         // appeared to be safe actually wasn't
00312         foreach ($elements as $n => $v) {
00313             if ($v === false) unset($elements[$n]);
00314         }
00315 
00316         return $elements;
00317 
00318     }
00319 
00330     public function getElement($name, $trusted = null) {
00331 
00332         if (!isset($this->elementLookup[$name])) {
00333             return false;
00334         }
00335 
00336         // setup global state variables
00337         $def = false;
00338         if ($trusted === null) $trusted = $this->trusted;
00339 
00340         // iterate through each module that has registered itself to this
00341         // element
00342         foreach($this->elementLookup[$name] as $module_name) {
00343 
00344             $module = $this->modules[$module_name];
00345 
00346             // refuse to create/merge from a module that is deemed unsafe--
00347             // pretend the module doesn't exist--when trusted mode is not on.
00348             if (!$trusted && !$module->safe) {
00349                 continue;
00350             }
00351 
00352             // clone is used because, ideally speaking, the original
00353             // definition should not be modified. Usually, this will
00354             // make no difference, but for consistency's sake
00355             $new_def = clone $module->info[$name];
00356 
00357             if (!$def && $new_def->standalone) {
00358                 $def = $new_def;
00359             } elseif ($def) {
00360                 // This will occur even if $new_def is standalone. In practice,
00361                 // this will usually result in a full replacement.
00362                 $def->mergeIn($new_def);
00363             } else {
00364                 // :TODO:
00365                 // non-standalone definitions that don't have a standalone
00366                 // to merge into could be deferred to the end
00367                 continue;
00368             }
00369 
00370             // attribute value expansions
00371             $this->attrCollections->performInclusions($def->attr);
00372             $this->attrCollections->expandIdentifiers($def->attr, $this->attrTypes);
00373 
00374             // descendants_are_inline, for ChildDef_Chameleon
00375             if (is_string($def->content_model) &&
00376                 strpos($def->content_model, 'Inline') !== false) {
00377                 if ($name != 'del' && $name != 'ins') {
00378                     // this is for you, ins/del
00379                     $def->descendants_are_inline = true;
00380                 }
00381             }
00382 
00383             $this->contentSets->generateChildDef($def, $module);
00384         }
00385 
00386         // This can occur if there is a blank definition, but no base to
00387         // mix it in with
00388         if (!$def) return false;
00389 
00390         // add information on required attributes
00391         foreach ($def->attr as $attr_name => $attr_def) {
00392             if ($attr_def->required) {
00393                 $def->required_attr[] = $attr_name;
00394             }
00395         }
00396 
00397         return $def;
00398 
00399     }
00400 
00401 }
00402 
00403 // vim: et sw=4 sts=4
 All Data Structures Namespaces Files Functions Variables Enumerations