104         if (!isset($module->info[$element_name])) {
 
  105             $element = $module->addBlankElement($element_name);
 
  107             $element = $module->info[$element_name];
 
  109         $element->attr[$attr_name] = $def;
 
  117     public function addElement($element_name, 
$type, $contents, $attr_collections, $attributes = array()) {
 
  121         $element = $module->addElement($element_name, 
$type, $contents, $attr_collections, $attributes);
 
  133         $element = $module->addBlankElement($element_name);
 
  143         if (!$this->_anonModule) {
 
  145             $this->_anonModule->name = 
'Anonymous';
 
  168         unset($this->manager);
 
  171         foreach ($this->info as $k => $v) {
 
  172             unset($this->info[$k]->content_model);
 
  173             unset($this->info[$k]->content_model_type);
 
  182         if ($this->_anonModule) {
 
  186             $this->manager->addModule($this->_anonModule);
 
  187             unset($this->_anonModule);
 
  190         $this->manager->setup(
$config);
 
  191         $this->doctype = $this->manager->doctype;
 
  193         foreach ($this->manager->modules as $module) {
 
  194             foreach($module->info_tag_transform as $k => $v) {
 
  195                 if ($v === 
false) unset($this->info_tag_transform[$k]);
 
  196                 else $this->info_tag_transform[$k] = $v;
 
  198             foreach($module->info_attr_transform_pre as $k => $v) {
 
  199                 if ($v === 
false) unset($this->info_attr_transform_pre[$k]);
 
  200                 else $this->info_attr_transform_pre[$k] = $v;
 
  202             foreach($module->info_attr_transform_post as $k => $v) {
 
  203                 if ($v === 
false) unset($this->info_attr_transform_post[$k]);
 
  204                 else $this->info_attr_transform_post[$k] = $v;
 
  206             foreach ($module->info_injector as $k => $v) {
 
  207                 if ($v === 
false) unset($this->info_injector[$k]);
 
  208                 else $this->info_injector[$k] = $v;
 
  212         $this->info = $this->manager->getElements();
 
  213         $this->info_content_sets = $this->manager->contentSets->lookup;
 
  222         $block_wrapper = 
$config->get(
'HTML.BlockWrapper');
 
  223         if (isset($this->info_content_sets[
'Block'][$block_wrapper])) {
 
  224             $this->info_block_wrapper = $block_wrapper;
 
  226             trigger_error(
'Cannot use non-block element as block wrapper',
 
  230         $parent = 
$config->get(
'HTML.Parent');
 
  231         $def = $this->manager->getElement($parent, 
true);
 
  233             $this->info_parent = $parent;
 
  234             $this->info_parent_def = $def;
 
  236             trigger_error(
'Cannot use unrecognized element as parent',
 
  238             $this->info_parent_def = $this->manager->getElement($this->info_parent, 
true);
 
  242         $support = 
"(for information on implementing this, see the ".
 
  247         $allowed_elements = 
$config->get(
'HTML.AllowedElements');
 
  248         $allowed_attributes = 
$config->get(
'HTML.AllowedAttributes'); 
 
  250         if (!is_array($allowed_elements) && !is_array($allowed_attributes)) {
 
  251             $allowed = 
$config->get(
'HTML.Allowed');
 
  252             if (is_string($allowed)) {
 
  257         if (is_array($allowed_elements)) {
 
  258             foreach ($this->info as $name => 
$d) {
 
  259                 if(!isset($allowed_elements[$name])) unset($this->info[$name]);
 
  260                 unset($allowed_elements[$name]);
 
  263             foreach ($allowed_elements as $element => 
$d) {
 
  264                 $element = htmlspecialchars($element); 
 
  265                 trigger_error(
"Element '$element' is not supported $support", E_USER_WARNING);
 
  271         $allowed_attributes_mutable = $allowed_attributes; 
 
  272         if (is_array($allowed_attributes)) {
 
  277             foreach ($this->info_global_attr as $attr => $x) {
 
  278                 $keys = array($attr, 
"*@$attr", 
"*.$attr");
 
  280                 foreach ($keys as $key) {
 
  281                     if ($delete && isset($allowed_attributes[$key])) {
 
  284                     if (isset($allowed_attributes_mutable[$key])) {
 
  285                         unset($allowed_attributes_mutable[$key]);
 
  288                 if ($delete) unset($this->info_global_attr[$attr]);
 
  291             foreach ($this->info as $tag => 
$info) {
 
  292                 foreach (
$info->attr as $attr => $x) {
 
  293                     $keys = array(
"$tag@$attr", $attr, 
"*@$attr", 
"$tag.$attr", 
"*.$attr");
 
  295                     foreach ($keys as $key) {
 
  296                         if ($delete && isset($allowed_attributes[$key])) {
 
  299                         if (isset($allowed_attributes_mutable[$key])) {
 
  300                             unset($allowed_attributes_mutable[$key]);
 
  304                         if ($this->info[$tag]->attr[$attr]->required) {
 
  305                             trigger_error(
"Required attribute '$attr' in element '$tag' was not allowed, which means '$tag' will not be allowed either", E_USER_WARNING);
 
  307                         unset($this->info[$tag]->attr[$attr]);
 
  312             foreach ($allowed_attributes_mutable as $elattr => 
$d) {
 
  313                 $bits = preg_split(
'/[.@]/', $elattr, 2);
 
  317                         if ($bits[0] !== 
'*') {
 
  318                             $element = htmlspecialchars($bits[0]);
 
  319                             $attribute = htmlspecialchars($bits[1]);
 
  320                             if (!isset($this->info[$element])) {
 
  321                                 trigger_error(
"Cannot allow attribute '$attribute' if element '$element' is not allowed/supported $support");
 
  323                                 trigger_error(
"Attribute '$attribute' in element '$element' not supported $support",
 
  330                         $attribute = htmlspecialchars($bits[0]);
 
  331                         trigger_error(
"Global attribute '$attribute' is not ".
 
  332                             "supported in any elements $support",
 
  342         $forbidden_elements   = 
$config->get(
'HTML.ForbiddenElements');
 
  343         $forbidden_attributes = 
$config->get(
'HTML.ForbiddenAttributes');
 
  345         foreach ($this->info as $tag => 
$info) {
 
  346             if (isset($forbidden_elements[$tag])) {
 
  347                 unset($this->info[$tag]);
 
  350             foreach (
$info->attr as $attr => $x) {
 
  352                     isset($forbidden_attributes[
"$tag@$attr"]) ||
 
  353                     isset($forbidden_attributes[
"*@$attr"]) ||
 
  354                     isset($forbidden_attributes[$attr])
 
  356                     unset($this->info[$tag]->attr[$attr]);
 
  359                 elseif (isset($forbidden_attributes[
"$tag.$attr"])) {
 
  361                     trigger_error(
"Error with $tag.$attr: tag.attr syntax not supported for HTML.ForbiddenAttributes; use tag@attr instead", E_USER_WARNING);
 
  365         foreach ($forbidden_attributes as $key => $v) {
 
  366             if (strlen($key) < 2) 
continue;
 
  367             if ($key[0] != 
'*') 
continue;
 
  368             if ($key[1] == 
'.') {
 
  369                 trigger_error(
"Error with $key: *.attr syntax not supported for HTML.ForbiddenAttributes; use attr instead", E_USER_WARNING);
 
  374         foreach ($this->info_injector as $i => $injector) {
 
  375             if ($injector->checkNeeded(
$config) !== 
false) {
 
  378                 unset($this->info_injector[$i]);
 
  394         $list = str_replace(array(
' ', 
"\t"), 
'', $list);
 
  397         $attributes = array();
 
  399         $chunks = preg_split(
'/(,|[\n\r]+)/', $list);
 
  400         foreach ($chunks as $chunk) {
 
  401             if (empty($chunk)) 
continue;
 
  403             if (!strpos($chunk, 
'[')) {
 
  407                 list($element, $attr) = explode(
'[', $chunk);
 
  409             if ($element !== 
'*') $elements[$element] = 
true;
 
  410             if (!$attr) 
continue;
 
  411             $attr = substr($attr, 0, strlen($attr) - 1); 
 
  412             $attr = explode(
'|', $attr);
 
  413             foreach ($attr as $key) {
 
  414                 $attributes[
"$element.$key"] = 
true;
 
  418         return array($elements, $attributes);