Advertisement
Guest User

Untitled

a guest
Dec 29th, 2011
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 69.10 KB | None | 0 0
  1. <?php
  2.  
  3. /**
  4.  * htmLawed 1.1.10, 22 October 2011
  5.  * Copyright Santosh Patnaik
  6.  * LGPL v3 license
  7.  * A PHP Labware internal utility; www.bioinformatics.org/phplabware/internal_utilities/htmLawed
  8.  * See htmLawed_README.txt/htm
  9.  */
  10.  
  11.  
  12. /**
  13.  * @param $t
  14.  * @param int $C
  15.  * @param array $S
  16.  * @return array|mixed|string
  17.  */
  18. function htmLawed($t, $C = 1, $S = array())
  19. {
  20.     $C = is_array($C) ? $C : array();
  21.     if (!empty($C['valid_xhtml'])) {
  22.         $C['elements']        = empty($C['elements']) ? '*-center-dir-font-isindex-menu-s-strike-u' : $C['elements'];
  23.         $C['make_tag_strict'] = isset($C['make_tag_strict']) ? $C['make_tag_strict'] : 2;
  24.         $C['xml:lang']        = isset($C['xml:lang']) ? $C['xml:lang'] : 2;
  25.     }
  26.     // config eles
  27.     $e = array(
  28.         'a' => 1,
  29.         'abbr' => 1,
  30.         'acronym' => 1,
  31.         'address' => 1,
  32.         'applet' => 1,
  33.         'area' => 1,
  34.         'b' => 1,
  35.         'bdo' => 1,
  36.         'big' => 1,
  37.         'blockquote' => 1,
  38.         'br' => 1,
  39.         'button' => 1,
  40.         'caption' => 1,
  41.         'center' => 1,
  42.         'cite' => 1,
  43.         'code' => 1,
  44.         'col' => 1,
  45.         'colgroup' => 1,
  46.         'dd' => 1,
  47.         'del' => 1,
  48.         'dfn' => 1,
  49.         'dir' => 1,
  50.         'div' => 1,
  51.         'dl' => 1,
  52.         'dt' => 1,
  53.         'em' => 1,
  54.         'embed' => 1,
  55.         'fieldset' => 1,
  56.         'font' => 1,
  57.         'form' => 1,
  58.         'h1' => 1,
  59.         'h2' => 1,
  60.         'h3' => 1,
  61.         'h4' => 1,
  62.         'h5' => 1,
  63.         'h6' => 1,
  64.         'hr' => 1,
  65.         'i' => 1,
  66.         'iframe' => 1,
  67.         'img' => 1,
  68.         'input' => 1,
  69.         'ins' => 1,
  70.         'isindex' => 1,
  71.         'kbd' => 1,
  72.         'label' => 1,
  73.         'legend' => 1,
  74.         'li' => 1,
  75.         'map' => 1,
  76.         'menu' => 1,
  77.         'noscript' => 1,
  78.         'object' => 1,
  79.         'ol' => 1,
  80.         'optgroup' => 1,
  81.         'option' => 1,
  82.         'p' => 1,
  83.         'param' => 1,
  84.         'pre' => 1,
  85.         'q' => 1,
  86.         'rb' => 1,
  87.         'rbc' => 1,
  88.         'rp' => 1,
  89.         'rt' => 1,
  90.         'rtc' => 1,
  91.         'ruby' => 1,
  92.         's' => 1,
  93.         'samp' => 1,
  94.         'script' => 1,
  95.         'select' => 1,
  96.         'small' => 1,
  97.         'span' => 1,
  98.         'strike' => 1,
  99.         'strong' => 1,
  100.         'sub' => 1,
  101.         'sup' => 1,
  102.         'table' => 1,
  103.         'tbody' => 1,
  104.         'td' => 1,
  105.         'textarea' => 1,
  106.         'tfoot' => 1,
  107.         'th' => 1,
  108.         'thead' => 1,
  109.         'tr' => 1,
  110.         'tt' => 1,
  111.         'u' => 1,
  112.         'ul' => 1,
  113.         'var' => 1
  114.     ); // 86/deprecated+embed+ruby
  115.     if (!empty($C['safe'])) {
  116.         unset($e['applet'], $e['embed'], $e['iframe'], $e['object'], $e['script']);
  117.     }
  118.     $x = !empty($C['elements']) ? str_replace(array(
  119.         "\n",
  120.         "\r",
  121.         "\t",
  122.         ' '
  123.     ), '', $C['elements']) : '*';
  124.     if ($x == '-*') {
  125.         $e = array();
  126.     } elseif (strpos($x, '*') === false) {
  127.         $e = array_flip(explode(',', $x));
  128.     } else {
  129.         if (isset($x[1])) {
  130.             preg_match_all('`(?:^|-|\+)[^\-+]+?(?=-|\+|$)`', $x, $m, PREG_SET_ORDER);
  131.             for ($i = count($m); --$i >= 0; ) {
  132.                 $m[$i] = $m[$i][0];
  133.             }
  134.             foreach ($m as $v) {
  135.                 if ($v[0] == '+') {
  136.                     $e[substr($v, 1)] = 1;
  137.                 }
  138.                 if ($v[0] == '-' && isset($e[($v = substr($v, 1))]) && !in_array('+' . $v, $m)) {
  139.                     unset($e[$v]);
  140.                 }
  141.             }
  142.         }
  143.     }
  144.     $C['elements'] =& $e;
  145.     // config attrs
  146.     $x = !empty($C['deny_attribute']) ? str_replace(array(
  147.         "\n",
  148.         "\r",
  149.         "\t",
  150.         ' '
  151.     ), '', $C['deny_attribute']) : '';
  152.     $x = array_flip((isset($x[0]) && $x[0] == '*') ? explode('-', $x) : explode(',', $x . (!empty($C['safe']) ? ',on*' : '')));
  153.     if (isset($x['on*'])) {
  154.         unset($x['on*']);
  155.         $x += array(
  156.             'onblur' => 1,
  157.             'onchange' => 1,
  158.             'onclick' => 1,
  159.             'ondblclick' => 1,
  160.             'onfocus' => 1,
  161.             'onkeydown' => 1,
  162.             'onkeypress' => 1,
  163.             'onkeyup' => 1,
  164.             'onmousedown' => 1,
  165.             'onmousemove' => 1,
  166.             'onmouseout' => 1,
  167.             'onmouseover' => 1,
  168.             'onmouseup' => 1,
  169.             'onreset' => 1,
  170.             'onselect' => 1,
  171.             'onsubmit' => 1
  172.         );
  173.     }
  174.     $C['deny_attribute'] = $x;
  175.     // config URL
  176.     $x                   = (isset($C['schemes'][2]) && strpos($C['schemes'], ':')) ? strtolower($C['schemes']) : 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; *:file, http, https';
  177.     $C['schemes']        = array();
  178.     foreach (explode(';', str_replace(array(
  179.         ' ',
  180.         "\t",
  181.         "\r",
  182.         "\n"
  183.     ), '', $x)) as $v) {
  184.         $x = $x2 = null;
  185.         list($x, $x2) = explode(':', $v, 2);
  186.         if ($x2) {
  187.             $C['schemes'][$x] = array_flip(explode(',', $x2));
  188.         }
  189.     }
  190.     if (!isset($C['schemes']['*'])) {
  191.         $C['schemes']['*'] = array(
  192.             'file' => 1,
  193.             'http' => 1,
  194.             'https' => 1
  195.         );
  196.     }
  197.     if (!empty($C['safe']) && empty($C['schemes']['style'])) {
  198.         $C['schemes']['style'] = array(
  199.             '!' => 1
  200.         );
  201.     }
  202.     $C['abs_url'] = isset($C['abs_url']) ? $C['abs_url'] : 0;
  203.     if (!isset($C['base_url']) or !preg_match('`^[a-zA-Z\d.+\-]+://[^/]+/(.+?/)?$`', $C['base_url'])) {
  204.         $C['base_url'] = $C['abs_url'] = 0;
  205.     }
  206.     // config rest
  207.     $C['and_mark']           = empty($C['and_mark']) ? 0 : 1;
  208.     $C['anti_link_spam']     = (isset($C['anti_link_spam']) && is_array($C['anti_link_spam']) && count($C['anti_link_spam']) == 2 && (empty($C['anti_link_spam'][0]) or hl_regex($C['anti_link_spam'][0])) && (empty($C['anti_link_spam'][1]) or hl_regex($C['anti_link_spam'][1]))) ? $C['anti_link_spam'] : 0;
  209.     $C['anti_mail_spam']     = isset($C['anti_mail_spam']) ? $C['anti_mail_spam'] : 0;
  210.     $C['balance']            = isset($C['balance']) ? (bool) $C['balance'] : 1;
  211.     $C['cdata']              = isset($C['cdata']) ? $C['cdata'] : (empty($C['safe']) ? 3 : 0);
  212.     $C['clean_ms_char']      = empty($C['clean_ms_char']) ? 0 : $C['clean_ms_char'];
  213.     $C['comment']            = isset($C['comment']) ? $C['comment'] : (empty($C['safe']) ? 3 : 0);
  214.     $C['css_expression']     = empty($C['css_expression']) ? 0 : 1;
  215.     $C['direct_list_nest']   = empty($C['direct_list_nest']) ? 0 : 1;
  216.     $C['hexdec_entity']      = isset($C['hexdec_entity']) ? $C['hexdec_entity'] : 1;
  217.     $C['hook']               = (!empty($C['hook']) && function_exists($C['hook'])) ? $C['hook'] : 0;
  218.     $C['hook_tag']           = (!empty($C['hook_tag']) && function_exists($C['hook_tag'])) ? $C['hook_tag'] : 0;
  219.     $C['keep_bad']           = isset($C['keep_bad']) ? $C['keep_bad'] : 6;
  220.     $C['lc_std_val']         = isset($C['lc_std_val']) ? (bool) $C['lc_std_val'] : 1;
  221.     $C['make_tag_strict']    = isset($C['make_tag_strict']) ? $C['make_tag_strict'] : 1;
  222.     $C['named_entity']       = isset($C['named_entity']) ? (bool) $C['named_entity'] : 1;
  223.     $C['no_deprecated_attr'] = isset($C['no_deprecated_attr']) ? $C['no_deprecated_attr'] : 1;
  224.     $C['parent']             = isset($C['parent'][0]) ? strtolower($C['parent']) : 'body';
  225.     $C['show_setting']       = !empty($C['show_setting']) ? $C['show_setting'] : 0;
  226.     $C['style_pass']         = empty($C['style_pass']) ? 0 : 1;
  227.     $C['tidy']               = empty($C['tidy']) ? 0 : $C['tidy'];
  228.     $C['unique_ids']         = isset($C['unique_ids']) ? $C['unique_ids'] : 1;
  229.     $C['xml:lang']           = isset($C['xml:lang']) ? $C['xml:lang'] : 0;
  230.    
  231.     if (isset($GLOBALS['C'])) {
  232.         $reC = $GLOBALS['C'];
  233.     }
  234.     $GLOBALS['C'] = $C;
  235.     $S            = is_array($S) ? $S : hl_spec($S);
  236.     if (isset($GLOBALS['S'])) {
  237.         $reS = $GLOBALS['S'];
  238.     }
  239.     $GLOBALS['S'] = $S;
  240.    
  241.     $t = preg_replace('`[\x00-\x08\x0b-\x0c\x0e-\x1f]`', '', $t);
  242.     if ($C['clean_ms_char']) {
  243.         $x = array(
  244.             "\x7f" => '',
  245.             "\x80" => '&#8364;',
  246.             "\x81" => '',
  247.             "\x83" => '&#402;',
  248.             "\x85" => '&#8230;',
  249.             "\x86" => '&#8224;',
  250.             "\x87" => '&#8225;',
  251.             "\x88" => '&#710;',
  252.             "\x89" => '&#8240;',
  253.             "\x8a" => '&#352;',
  254.             "\x8b" => '&#8249;',
  255.             "\x8c" => '&#338;',
  256.             "\x8d" => '',
  257.             "\x8e" => '&#381;',
  258.             "\x8f" => '',
  259.             "\x90" => '',
  260.             "\x95" => '&#8226;',
  261.             "\x96" => '&#8211;',
  262.             "\x97" => '&#8212;',
  263.             "\x98" => '&#732;',
  264.             "\x99" => '&#8482;',
  265.             "\x9a" => '&#353;',
  266.             "\x9b" => '&#8250;',
  267.             "\x9c" => '&#339;',
  268.             "\x9d" => '',
  269.             "\x9e" => '&#382;',
  270.             "\x9f" => '&#376;'
  271.         );
  272.         $x = $x + ($C['clean_ms_char'] == 1 ? array(
  273.             "\x82" => '&#8218;',
  274.             "\x84" => '&#8222;',
  275.             "\x91" => '&#8216;',
  276.             "\x92" => '&#8217;',
  277.             "\x93" => '&#8220;',
  278.             "\x94" => '&#8221;'
  279.         ) : array(
  280.             "\x82" => '\'',
  281.             "\x84" => '"',
  282.             "\x91" => '\'',
  283.             "\x92" => '\'',
  284.             "\x93" => '"',
  285.             "\x94" => '"'
  286.         ));
  287.         $t = strtr($t, $x);
  288.     }
  289.     if ($C['cdata'] or $C['comment']) {
  290.         $t = preg_replace_callback('`<!(?:(?:--.*?--)|(?:\[CDATA\[.*?\]\]))>`sm', 'hl_cmtcd', $t);
  291.     }
  292.     $t = preg_replace_callback('`&amp;([A-Za-z][A-Za-z0-9]{1,30}|#(?:[0-9]{1,8}|[Xx][0-9A-Fa-f]{1,7}));`', 'hl_ent', str_replace('&', '&amp;', $t));
  293.     if ($C['unique_ids'] && !isset($GLOBALS['hl_Ids'])) {
  294.         $GLOBALS['hl_Ids'] = array();
  295.     }
  296.     if ($C['hook']) {
  297.         $t = $C['hook']($t, $C, $S);
  298.     }
  299.     if ($C['show_setting'] && preg_match('`^[a-z][a-z0-9_]*$`i', $C['show_setting'])) {
  300.         $GLOBALS[$C['show_setting']] = array(
  301.             'config' => $C,
  302.             'spec' => $S,
  303.             'time' => microtime()
  304.         );
  305.     }
  306.     // main
  307.     $t = preg_replace_callback('`<(?:(?:\s|$)|(?:[^>]*(?:>|$)))|>`m', 'hl_tag', $t);
  308.     $t = $C['balance'] ? hl_bal($t, $C['keep_bad'], $C['parent']) : $t;
  309.     $t = (($C['cdata'] or $C['comment']) && strpos($t, "\x01") !== false) ? str_replace(array(
  310.         "\x01",
  311.         "\x02",
  312.         "\x03",
  313.         "\x04",
  314.         "\x05"
  315.     ), array(
  316.         '',
  317.         '',
  318.         '&',
  319.         '<',
  320.         '>'
  321.     ), $t) : $t;
  322.     $t = $C['tidy'] ? hl_tidy($t, $C['tidy'], $C['parent']) : $t;
  323.     unset($C, $e);
  324.     if (isset($reC)) {
  325.         $GLOBALS['C'] = $reC;
  326.     }
  327.     if (isset($reS)) {
  328.         $GLOBALS['S'] = $reS;
  329.     }
  330.     return $t;
  331.     // eof
  332. }
  333.  
  334.  
  335. /**
  336.  * @param $t
  337.  * @param $p
  338.  * @return int
  339.  */
  340. function hl_attrval($t, $p)
  341. {
  342.     // check attr val against $S
  343.     $o = 1;
  344.     $l = strlen($t);
  345.     foreach ($p as $k => $v) {
  346.         switch ($k) {
  347.             case 'maxlen':
  348.                 if ($l > $v) {
  349.                     $o = 0;
  350.                 }
  351.                 break;
  352.             case 'minlen':
  353.                 if ($l < $v) {
  354.                     $o = 0;
  355.                 }
  356.                 break;
  357.             case 'maxval':
  358.                 if ((float) ($t) > $v) {
  359.                     $o = 0;
  360.                 }
  361.                 break;
  362.             case 'minval':
  363.                 if ((float) ($t) < $v) {
  364.                     $o = 0;
  365.                 }
  366.                 break;
  367.             case 'match':
  368.                 if (!preg_match($v, $t)) {
  369.                     $o = 0;
  370.                 }
  371.                 break;
  372.             case 'nomatch':
  373.                 if (preg_match($v, $t)) {
  374.                     $o = 0;
  375.                 }
  376.                 break;
  377.             case 'oneof':
  378.                 $m = 0;
  379.                 foreach (explode('|', $v) as $n) {
  380.                     if ($t == $n) {
  381.                         $m = 1;
  382.                         break;
  383.                     }
  384.                 }
  385.                 $o = $m;
  386.                 break;
  387.             case 'noneof':
  388.                 $m = 1;
  389.                 foreach (explode('|', $v) as $n) {
  390.                     if ($t == $n) {
  391.                         $m = 0;
  392.                         break;
  393.                     }
  394.                 }
  395.                 $o = $m;
  396.                 break;
  397.             default:
  398.                 break;
  399.         }
  400.         if (!$o) {
  401.             break;
  402.         }
  403.     }
  404.     return ($o ? $t : (isset($p['default']) ? $p['default'] : 0));
  405.     // eof
  406. }
  407.  
  408.  
  409. /**
  410.  * @param $t
  411.  * @param int $do
  412.  * @param string $in
  413.  * @return mixed|string
  414.  */
  415. function hl_bal($t, $do = 1, $in = 'div')
  416. {
  417.     // balance tags
  418.     // by content
  419.     $cB  = array(
  420.         'blockquote' => 1,
  421.         'form' => 1,
  422.         'map' => 1,
  423.         'noscript' => 1
  424.     ); // Block
  425.     $cE  = array(
  426.         'area' => 1,
  427.         'br' => 1,
  428.         'col' => 1,
  429.         'embed' => 1,
  430.         'hr' => 1,
  431.         'img' => 1,
  432.         'input' => 1,
  433.         'isindex' => 1,
  434.         'param' => 1
  435.     ); // Empty
  436.     $cF  = array(
  437.         'button' => 1,
  438.         'del' => 1,
  439.         'div' => 1,
  440.         'dd' => 1,
  441.         'fieldset' => 1,
  442.         'iframe' => 1,
  443.         'ins' => 1,
  444.         'li' => 1,
  445.         'noscript' => 1,
  446.         'object' => 1,
  447.         'td' => 1,
  448.         'th' => 1
  449.     ); // Flow; later context-wise dynamic move of ins & del to $cI
  450.     $cI  = array(
  451.         'a' => 1,
  452.         'abbr' => 1,
  453.         'acronym' => 1,
  454.         'address' => 1,
  455.         'b' => 1,
  456.         'bdo' => 1,
  457.         'big' => 1,
  458.         'caption' => 1,
  459.         'cite' => 1,
  460.         'code' => 1,
  461.         'dfn' => 1,
  462.         'dt' => 1,
  463.         'em' => 1,
  464.         'font' => 1,
  465.         'h1' => 1,
  466.         'h2' => 1,
  467.         'h3' => 1,
  468.         'h4' => 1,
  469.         'h5' => 1,
  470.         'h6' => 1,
  471.         'i' => 1,
  472.         'kbd' => 1,
  473.         'label' => 1,
  474.         'legend' => 1,
  475.         'p' => 1,
  476.         'pre' => 1,
  477.         'q' => 1,
  478.         'rb' => 1,
  479.         'rt' => 1,
  480.         's' => 1,
  481.         'samp' => 1,
  482.         'small' => 1,
  483.         'span' => 1,
  484.         'strike' => 1,
  485.         'strong' => 1,
  486.         'sub' => 1,
  487.         'sup' => 1,
  488.         'tt' => 1,
  489.         'u' => 1,
  490.         'var' => 1
  491.     ); // Inline
  492.     $cN  = array(
  493.         'a' => array(
  494.             'a' => 1
  495.         ),
  496.         'button' => array(
  497.             'a' => 1,
  498.             'button' => 1,
  499.             'fieldset' => 1,
  500.             'form' => 1,
  501.             'iframe' => 1,
  502.             'input' => 1,
  503.             'label' => 1,
  504.             'select' => 1,
  505.             'textarea' => 1
  506.         ),
  507.         'fieldset' => array(
  508.             'fieldset' => 1
  509.         ),
  510.         'form' => array(
  511.             'form' => 1
  512.         ),
  513.         'label' => array(
  514.             'label' => 1
  515.         ),
  516.         'noscript' => array(
  517.             'script' => 1
  518.         ),
  519.         'pre' => array(
  520.             'big' => 1,
  521.             'font' => 1,
  522.             'img' => 1,
  523.             'object' => 1,
  524.             'script' => 1,
  525.             'small' => 1,
  526.             'sub' => 1,
  527.             'sup' => 1
  528.         ),
  529.         'rb' => array(
  530.             'ruby' => 1
  531.         ),
  532.         'rt' => array(
  533.             'ruby' => 1
  534.         )
  535.     ); // Illegal
  536.     $cN2 = array_keys($cN);
  537.     $cR  = array(
  538.         'blockquote' => 1,
  539.         'dir' => 1,
  540.         'dl' => 1,
  541.         'form' => 1,
  542.         'map' => 1,
  543.         'menu' => 1,
  544.         'noscript' => 1,
  545.         'ol' => 1,
  546.         'optgroup' => 1,
  547.         'rbc' => 1,
  548.         'rtc' => 1,
  549.         'ruby' => 1,
  550.         'select' => 1,
  551.         'table' => 1,
  552.         'tbody' => 1,
  553.         'tfoot' => 1,
  554.         'thead' => 1,
  555.         'tr' => 1,
  556.         'ul' => 1
  557.     );
  558.     $cS  = array(
  559.         'colgroup' => array(
  560.             'col' => 1
  561.         ),
  562.         'dir' => array(
  563.             'li' => 1
  564.         ),
  565.         'dl' => array(
  566.             'dd' => 1,
  567.             'dt' => 1
  568.         ),
  569.         'menu' => array(
  570.             'li' => 1
  571.         ),
  572.         'ol' => array(
  573.             'li' => 1
  574.         ),
  575.         'optgroup' => array(
  576.             'option' => 1
  577.         ),
  578.         'option' => array(
  579.             '#pcdata' => 1
  580.         ),
  581.         'rbc' => array(
  582.             'rb' => 1
  583.         ),
  584.         'rp' => array(
  585.             '#pcdata' => 1
  586.         ),
  587.         'rtc' => array(
  588.             'rt' => 1
  589.         ),
  590.         'ruby' => array(
  591.             'rb' => 1,
  592.             'rbc' => 1,
  593.             'rp' => 1,
  594.             'rt' => 1,
  595.             'rtc' => 1
  596.         ),
  597.         'select' => array(
  598.             'optgroup' => 1,
  599.             'option' => 1
  600.         ),
  601.         'script' => array(
  602.             '#pcdata' => 1
  603.         ),
  604.         'table' => array(
  605.             'caption' => 1,
  606.             'col' => 1,
  607.             'colgroup' => 1,
  608.             'tfoot' => 1,
  609.             'tbody' => 1,
  610.             'tr' => 1,
  611.             'thead' => 1
  612.         ),
  613.         'tbody' => array(
  614.             'tr' => 1
  615.         ),
  616.         'tfoot' => array(
  617.             'tr' => 1
  618.         ),
  619.         'textarea' => array(
  620.             '#pcdata' => 1
  621.         ),
  622.         'thead' => array(
  623.             'tr' => 1
  624.         ),
  625.         'tr' => array(
  626.             'td' => 1,
  627.             'th' => 1
  628.         ),
  629.         'ul' => array(
  630.             'li' => 1
  631.         )
  632.     ); // Specific - immediate parent-child
  633.     if ($GLOBALS['C']['direct_list_nest']) {
  634.         $cS['ol'] = $cS['ul'] += array(
  635.             'ol' => 1,
  636.             'ul' => 1
  637.         );
  638.     }
  639.     $cO = array(
  640.         'address' => array(
  641.             'p' => 1
  642.         ),
  643.         'applet' => array(
  644.             'param' => 1
  645.         ),
  646.         'blockquote' => array(
  647.             'script' => 1
  648.         ),
  649.         'fieldset' => array(
  650.             'legend' => 1,
  651.             '#pcdata' => 1
  652.         ),
  653.         'form' => array(
  654.             'script' => 1
  655.         ),
  656.         'map' => array(
  657.             'area' => 1
  658.         ),
  659.         'object' => array(
  660.             'param' => 1,
  661.             'embed' => 1
  662.         )
  663.     ); // Other
  664.     $cT = array(
  665.         'colgroup' => 1,
  666.         'dd' => 1,
  667.         'dt' => 1,
  668.         'li' => 1,
  669.         'option' => 1,
  670.         'p' => 1,
  671.         'td' => 1,
  672.         'tfoot' => 1,
  673.         'th' => 1,
  674.         'thead' => 1,
  675.         'tr' => 1
  676.     ); // Omitable closing
  677.     // block/inline type; ins & del both type; #pcdata: text
  678.     $eB = array(
  679.         'address' => 1,
  680.         'blockquote' => 1,
  681.         'center' => 1,
  682.         'del' => 1,
  683.         'dir' => 1,
  684.         'dl' => 1,
  685.         'div' => 1,
  686.         'fieldset' => 1,
  687.         'form' => 1,
  688.         'ins' => 1,
  689.         'h1' => 1,
  690.         'h2' => 1,
  691.         'h3' => 1,
  692.         'h4' => 1,
  693.         'h5' => 1,
  694.         'h6' => 1,
  695.         'hr' => 1,
  696.         'isindex' => 1,
  697.         'menu' => 1,
  698.         'noscript' => 1,
  699.         'ol' => 1,
  700.         'p' => 1,
  701.         'pre' => 1,
  702.         'table' => 1,
  703.         'ul' => 1
  704.     );
  705.     $eI = array(
  706.         '#pcdata' => 1,
  707.         'a' => 1,
  708.         'abbr' => 1,
  709.         'acronym' => 1,
  710.         'applet' => 1,
  711.         'b' => 1,
  712.         'bdo' => 1,
  713.         'big' => 1,
  714.         'br' => 1,
  715.         'button' => 1,
  716.         'cite' => 1,
  717.         'code' => 1,
  718.         'del' => 1,
  719.         'dfn' => 1,
  720.         'em' => 1,
  721.         'embed' => 1,
  722.         'font' => 1,
  723.         'i' => 1,
  724.         'iframe' => 1,
  725.         'img' => 1,
  726.         'input' => 1,
  727.         'ins' => 1,
  728.         'kbd' => 1,
  729.         'label' => 1,
  730.         'map' => 1,
  731.         'object' => 1,
  732.         'q' => 1,
  733.         'ruby' => 1,
  734.         's' => 1,
  735.         'samp' => 1,
  736.         'select' => 1,
  737.         'script' => 1,
  738.         'small' => 1,
  739.         'span' => 1,
  740.         'strike' => 1,
  741.         'strong' => 1,
  742.         'sub' => 1,
  743.         'sup' => 1,
  744.         'textarea' => 1,
  745.         'tt' => 1,
  746.         'u' => 1,
  747.         'var' => 1
  748.     );
  749.     $eN = array(
  750.         'a' => 1,
  751.         'big' => 1,
  752.         'button' => 1,
  753.         'fieldset' => 1,
  754.         'font' => 1,
  755.         'form' => 1,
  756.         'iframe' => 1,
  757.         'img' => 1,
  758.         'input' => 1,
  759.         'label' => 1,
  760.         'object' => 1,
  761.         'ruby' => 1,
  762.         'script' => 1,
  763.         'select' => 1,
  764.         'small' => 1,
  765.         'sub' => 1,
  766.         'sup' => 1,
  767.         'textarea' => 1
  768.     ); // Exclude from specific ele; $cN values
  769.     $eO = array(
  770.         'area' => 1,
  771.         'caption' => 1,
  772.         'col' => 1,
  773.         'colgroup' => 1,
  774.         'dd' => 1,
  775.         'dt' => 1,
  776.         'legend' => 1,
  777.         'li' => 1,
  778.         'optgroup' => 1,
  779.         'option' => 1,
  780.         'param' => 1,
  781.         'rb' => 1,
  782.         'rbc' => 1,
  783.         'rp' => 1,
  784.         'rt' => 1,
  785.         'rtc' => 1,
  786.         'script' => 1,
  787.         'tbody' => 1,
  788.         'td' => 1,
  789.         'tfoot' => 1,
  790.         'thead' => 1,
  791.         'th' => 1,
  792.         'tr' => 1
  793.     ); // Missing in $eB & $eI
  794.     $eF = $eB + $eI;
  795.    
  796.     // $in sets allowed child
  797.     $in = ((isset($eF[$in]) && $in != '#pcdata') or isset($eO[$in])) ? $in : 'div';
  798.     if (isset($cE[$in])) {
  799.         return (!$do ? '' : str_replace(array(
  800.             '<',
  801.             '>'
  802.         ), array(
  803.             '&lt;',
  804.             '&gt;'
  805.         ), $t));
  806.     }
  807.     if (isset($cS[$in])) {
  808.         $inOk = $cS[$in];
  809.     } elseif (isset($cI[$in])) {
  810.         $inOk      = $eI;
  811.         $cI['del'] = 1;
  812.         $cI['ins'] = 1;
  813.     } elseif (isset($cF[$in])) {
  814.         $inOk = $eF;
  815.         unset($cI['del'], $cI['ins']);
  816.     } elseif (isset($cB[$in])) {
  817.         $inOk = $eB;
  818.         unset($cI['del'], $cI['ins']);
  819.     }
  820.     if (isset($cO[$in])) {
  821.         $inOk = $inOk + $cO[$in];
  822.     }
  823.     if (isset($cN[$in])) {
  824.         $inOk = array_diff_assoc($inOk, $cN[$in]);
  825.     }
  826.    
  827.     $t  = explode('<', $t);
  828.     $ok = $q = array(); // $q seq list of open non-empty ele
  829.     ob_start();
  830.    
  831.     for ($i = -1, $ci = count($t); ++$i < $ci; ) {
  832.         // allowed $ok in parent $p
  833.         if ($ql = count($q)) {
  834.             $p   = array_pop($q);
  835.             $q[] = $p;
  836.             if (isset($cS[$p])) {
  837.                 $ok = $cS[$p];
  838.             } elseif (isset($cI[$p])) {
  839.                 $ok        = $eI;
  840.                 $cI['del'] = 1;
  841.                 $cI['ins'] = 1;
  842.             } elseif (isset($cF[$p])) {
  843.                 $ok = $eF;
  844.                 unset($cI['del'], $cI['ins']);
  845.             } elseif (isset($cB[$p])) {
  846.                 $ok = $eB;
  847.                 unset($cI['del'], $cI['ins']);
  848.             }
  849.             if (isset($cO[$p])) {
  850.                 $ok = $ok + $cO[$p];
  851.             }
  852.             if (isset($cN[$p])) {
  853.                 $ok = array_diff_assoc($ok, $cN[$p]);
  854.             }
  855.         } else {
  856.             $ok = $inOk;
  857.             unset($cI['del'], $cI['ins']);
  858.         }
  859.         // bad tags, & ele content
  860.         if (isset($e) && ($do == 1 or (isset($ok['#pcdata']) && ($do == 3 or $do == 5)))) {
  861.             echo '&lt;', $s, $e, $a, '&gt;';
  862.         }
  863.         if (isset($x[0])) {
  864.             if ($do < 3 or isset($ok['#pcdata'])) {
  865.                 echo $x;
  866.             } elseif (strpos($x, "\x02\x04")) {
  867.                 foreach (preg_split('`(\x01\x02[^\x01\x02]+\x02\x01)`', $x, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY) as $v) {
  868.                     echo (substr($v, 0, 2) == "\x01\x02" ? $v : ($do > 4 ? preg_replace('`\S`', '', $v) : ''));
  869.                 }
  870.             } elseif ($do > 4) {
  871.                 echo preg_replace('`\S`', '', $x);
  872.             }
  873.         }
  874.         // get markup
  875.         if (!preg_match('`^(/?)([a-zA-Z1-6]+)([^>]*)>(.*)`sm', $t[$i], $r)) {
  876.             $x = $t[$i];
  877.             continue;
  878.         }
  879.         $s = null;
  880.         $e = null;
  881.         $a = null;
  882.         $x = null;
  883.         list($all, $s, $e, $a, $x) = $r;
  884.         // close tag
  885.         if ($s) {
  886.             if (isset($cE[$e]) or !in_array($e, $q)) {
  887.                 continue;
  888.             } // Empty/unopen
  889.             if ($p == $e) {
  890.                 array_pop($q);
  891.                 echo '</', $e, '>';
  892.                 unset($e);
  893.                 continue;
  894.             } // Last open
  895.             $add = ''; // Nesting - close open tags that need to be
  896.             for ($j = -1, $cj = count($q); ++$j < $cj; ) {
  897.                 if (($d = array_pop($q)) == $e) {
  898.                     break;
  899.                 } else {
  900.                     $add .= "</{$d}>";
  901.                 }
  902.             }
  903.             echo $add, '</', $e, '>';
  904.             unset($e);
  905.             continue;
  906.         }
  907.         // open tag
  908.         // $cB ele needs $eB ele as child
  909.         if (isset($cB[$e]) && strlen(trim($x))) {
  910.             $t[$i] = "{$e}{$a}>";
  911.             array_splice($t, $i + 1, 0, 'div>' . $x);
  912.             unset($e, $x);
  913.             ++$ci;
  914.             --$i;
  915.             continue;
  916.         }
  917.         if ((($ql && isset($cB[$p])) or (isset($cB[$in]) && !$ql)) && !isset($eB[$e]) && !isset($ok[$e])) {
  918.             array_splice($t, $i, 0, 'div>');
  919.             unset($e, $x);
  920.             ++$ci;
  921.             --$i;
  922.             continue;
  923.         }
  924.         // if no open ele, $in = parent; mostly immediate parent-child relation should hold
  925.         if (!$ql or !isset($eN[$e]) or !array_intersect($q, $cN2)) {
  926.             if (!isset($ok[$e])) {
  927.                 if ($ql && isset($cT[$p])) {
  928.                     echo '</', array_pop($q), '>';
  929.                     unset($e, $x);
  930.                     --$i;
  931.                 }
  932.                 continue;
  933.             }
  934.             if (!isset($cE[$e])) {
  935.                 $q[] = $e;
  936.             }
  937.             echo '<', $e, $a, '>';
  938.             unset($e);
  939.             continue;
  940.         }
  941.         // specific parent-child
  942.         if (isset($cS[$p][$e])) {
  943.             if (!isset($cE[$e])) {
  944.                 $q[] = $e;
  945.             }
  946.             echo '<', $e, $a, '>';
  947.             unset($e);
  948.             continue;
  949.         }
  950.         // nesting
  951.         $add = '';
  952.         $q2  = array();
  953.         for ($k = -1, $kc = count($q); ++$k < $kc; ) {
  954.             $d   = $q[$k];
  955.             $ok2 = array();
  956.             if (isset($cS[$d])) {
  957.                 $q2[] = $d;
  958.                 continue;
  959.             }
  960.             $ok2 = isset($cI[$d]) ? $eI : $eF;
  961.             if (isset($cO[$d])) {
  962.                 $ok2 = $ok2 + $cO[$d];
  963.             }
  964.             if (isset($cN[$d])) {
  965.                 $ok2 = array_diff_assoc($ok2, $cN[$d]);
  966.             }
  967.             if (!isset($ok2[$e])) {
  968.                 if (!$k && !isset($inOk[$e])) {
  969.                     continue 2;
  970.                 }
  971.                 $add = "</{$d}>";
  972.                 for (; ++$k < $kc; ) {
  973.                     $add = "</{$q[$k]}>{$add}";
  974.                 }
  975.                 break;
  976.             } else {
  977.                 $q2[] = $d;
  978.             }
  979.         }
  980.         $q = $q2;
  981.         if (!isset($cE[$e])) {
  982.             $q[] = $e;
  983.         }
  984.         echo $add, '<', $e, $a, '>';
  985.         unset($e);
  986.         continue;
  987.     }
  988.    
  989.     // end
  990.     if ($ql = count($q)) {
  991.         $p   = array_pop($q);
  992.         $q[] = $p;
  993.         if (isset($cS[$p])) {
  994.             $ok = $cS[$p];
  995.         } elseif (isset($cI[$p])) {
  996.             $ok        = $eI;
  997.             $cI['del'] = 1;
  998.             $cI['ins'] = 1;
  999.         } elseif (isset($cF[$p])) {
  1000.             $ok = $eF;
  1001.             unset($cI['del'], $cI['ins']);
  1002.         } elseif (isset($cB[$p])) {
  1003.             $ok = $eB;
  1004.             unset($cI['del'], $cI['ins']);
  1005.         }
  1006.         if (isset($cO[$p])) {
  1007.             $ok = $ok + $cO[$p];
  1008.         }
  1009.         if (isset($cN[$p])) {
  1010.             $ok = array_diff_assoc($ok, $cN[$p]);
  1011.         }
  1012.     } else {
  1013.         $ok = $inOk;
  1014.         unset($cI['del'], $cI['ins']);
  1015.     }
  1016.     if (isset($e) && ($do == 1 or (isset($ok['#pcdata']) && ($do == 3 or $do == 5)))) {
  1017.         echo '&lt;', $s, $e, $a, '&gt;';
  1018.     }
  1019.     if (isset($x[0])) {
  1020.         if (strlen(trim($x)) && (($ql && isset($cB[$p])) or (isset($cB[$in]) && !$ql))) {
  1021.             echo '<div>', $x, '</div>';
  1022.         } elseif ($do < 3 or isset($ok['#pcdata'])) {
  1023.             echo $x;
  1024.         } elseif (strpos($x, "\x02\x04")) {
  1025.             foreach (preg_split('`(\x01\x02[^\x01\x02]+\x02\x01)`', $x, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY) as $v) {
  1026.                 echo (substr($v, 0, 2) == "\x01\x02" ? $v : ($do > 4 ? preg_replace('`\S`', '', $v) : ''));
  1027.             }
  1028.         } elseif ($do > 4) {
  1029.             echo preg_replace('`\S`', '', $x);
  1030.         }
  1031.     }
  1032.     while (!empty($q) && ($e = array_pop($q))) {
  1033.         echo '</', $e, '>';
  1034.     }
  1035.     $o = ob_get_contents();
  1036.     ob_end_clean();
  1037.     return $o;
  1038.     // eof
  1039. }
  1040.  
  1041.  
  1042.  
  1043. /**
  1044.  * @param $t
  1045.  * @return mixed|string
  1046.  */
  1047. function hl_cmtcd($t)
  1048. {
  1049.     // comment/CDATA sec handler
  1050.     $t = $t[0];
  1051.     global $C;
  1052.     if (!($v = $C[$n = $t[3] == '-' ? 'comment' : 'cdata'])) {
  1053.         return $t;
  1054.     }
  1055.     if ($v == 1) {
  1056.         return '';
  1057.     }
  1058.     if ($n == 'comment') {
  1059.         if (substr(($t = preg_replace('`--+`', '-', substr($t, 4, -3))), -1) != ' ') {
  1060.             $t .= ' ';
  1061.         }
  1062.     } else {
  1063.         $t = substr($t, 1, -1);
  1064.     }
  1065.     $t = $v == 2 ? str_replace(array(
  1066.         '&',
  1067.         '<',
  1068.         '>'
  1069.     ), array(
  1070.         '&amp;',
  1071.         '&lt;',
  1072.         '&gt;'
  1073.     ), $t) : $t;
  1074.     return str_replace(array(
  1075.         '&',
  1076.         '<',
  1077.         '>'
  1078.     ), array(
  1079.         "\x03",
  1080.         "\x04",
  1081.         "\x05"
  1082.     ), ($n == 'comment' ? "\x01\x02\x04!--$t--\x05\x02\x01" : "\x01\x01\x04$t\x05\x01\x01"));
  1083.     // eof
  1084. }
  1085.  
  1086.  
  1087. /**
  1088.  * @param $t
  1089.  * @return string
  1090.  */
  1091. function hl_ent($t)
  1092. {
  1093.     // entitity handler
  1094.     global $C;
  1095.     $t = $t[1];
  1096.     static $U = array('quot' => 1, 'amp' => 1, 'lt' => 1, 'gt' => 1);
  1097.     static $N = array('fnof' => '402', 'Alpha' => '913', 'Beta' => '914', 'Gamma' => '915', 'Delta' => '916', 'Epsilon' => '917', 'Zeta' => '918', 'Eta' => '919', 'Theta' => '920', 'Iota' => '921', 'Kappa' => '922', 'Lambda' => '923', 'Mu' => '924', 'Nu' => '925', 'Xi' => '926', 'Omicron' => '927', 'Pi' => '928', 'Rho' => '929', 'Sigma' => '931', 'Tau' => '932', 'Upsilon' => '933', 'Phi' => '934', 'Chi' => '935', 'Psi' => '936', 'Omega' => '937', 'alpha' => '945', 'beta' => '946', 'gamma' => '947', 'delta' => '948', 'epsilon' => '949', 'zeta' => '950', 'eta' => '951', 'theta' => '952', 'iota' => '953', 'kappa' => '954', 'lambda' => '955', 'mu' => '956', 'nu' => '957', 'xi' => '958', 'omicron' => '959', 'pi' => '960', 'rho' => '961', 'sigmaf' => '962', 'sigma' => '963', 'tau' => '964', 'upsilon' => '965', 'phi' => '966', 'chi' => '967', 'psi' => '968', 'omega' => '969', 'thetasym' => '977', 'upsih' => '978', 'piv' => '982', 'bull' => '8226', 'hellip' => '8230', 'prime' => '8242', 'Prime' => '8243', 'oline' => '8254', 'frasl' => '8260', 'weierp' => '8472', 'image' => '8465', 'real' => '8476', 'trade' => '8482', 'alefsym' => '8501', 'larr' => '8592', 'uarr' => '8593', 'rarr' => '8594', 'darr' => '8595', 'harr' => '8596', 'crarr' => '8629', 'lArr' => '8656', 'uArr' => '8657', 'rArr' => '8658', 'dArr' => '8659', 'hArr' => '8660', 'forall' => '8704', 'part' => '8706', 'exist' => '8707', 'empty' => '8709', 'nabla' => '8711', 'isin' => '8712', 'notin' => '8713', 'ni' => '8715', 'prod' => '8719', 'sum' => '8721', 'minus' => '8722', 'lowast' => '8727', 'radic' => '8730', 'prop' => '8733', 'infin' => '8734', 'ang' => '8736', 'and' => '8743', 'or' => '8744', 'cap' => '8745', 'cup' => '8746', 'int' => '8747', 'there4' => '8756', 'sim' => '8764', 'cong' => '8773', 'asymp' => '8776', 'ne' => '8800', 'equiv' => '8801', 'le' => '8804', 'ge' => '8805', 'sub' => '8834', 'sup' => '8835', 'nsub' => '8836', 'sube' => '8838', 'supe' => '8839', 'oplus' => '8853', 'otimes' => '8855', 'perp' => '8869', 'sdot' => '8901', 'lceil' => '8968', 'rceil' => '8969', 'lfloor' => '8970', 'rfloor' => '8971', 'lang' => '9001', 'rang' => '9002', 'loz' => '9674', 'spades' => '9824', 'clubs' => '9827', 'hearts' => '9829', 'diams' => '9830', 'apos' => '39', 'OElig' => '338', 'oelig' => '339', 'Scaron' => '352', 'scaron' => '353', 'Yuml' => '376', 'circ' => '710', 'tilde' => '732', 'ensp' => '8194', 'emsp' => '8195', 'thinsp' => '8201', 'zwnj' => '8204', 'zwj' => '8205', 'lrm' => '8206', 'rlm' => '8207', 'ndash' => '8211', 'mdash' => '8212', 'lsquo' => '8216', 'rsquo' => '8217', 'sbquo' => '8218', 'ldquo' => '8220', 'rdquo' => '8221', 'bdquo' => '8222', 'dagger' => '8224', 'Dagger' => '8225', 'permil' => '8240', 'lsaquo' => '8249', 'rsaquo' => '8250', 'euro' => '8364', 'nbsp' => '160', 'iexcl' => '161', 'cent' => '162', 'pound' => '163', 'curren' => '164', 'yen' => '165', 'brvbar' => '166', 'sect' => '167', 'uml' => '168', 'copy' => '169', 'ordf' => '170', 'laquo' => '171', 'not' => '172', 'shy' => '173', 'reg' => '174', 'macr' => '175', 'deg' => '176', 'plusmn' => '177', 'sup2' => '178', 'sup3' => '179', 'acute' => '180', 'micro' => '181', 'para' => '182', 'middot' => '183', 'cedil' => '184', 'sup1' => '185', 'ordm' => '186', 'raquo' => '187', 'frac14' => '188', 'frac12' => '189', 'frac34' => '190', 'iquest' => '191', 'Agrave' => '192', 'Aacute' => '193', 'Acirc' => '194', 'Atilde' => '195', 'Auml' => '196', 'Aring' => '197', 'AElig' => '198', 'Ccedil' => '199', 'Egrave' => '200', 'Eacute' => '201', 'Ecirc' => '202', 'Euml' => '203', 'Igrave' => '204', 'Iacute' => '205', 'Icirc' => '206', 'Iuml' => '207', 'ETH' => '208', 'Ntilde' => '209', 'Ograve' => '210', 'Oacute' => '211', 'Ocirc' => '212', 'Otilde' => '213', 'Ouml' => '214', 'times' => '215', 'Oslash' => '216', 'Ugrave' => '217', 'Uacute' => '218', 'Ucirc' => '219', 'Uuml' => '220', 'Yacute' => '221', 'THORN' => '222', 'szlig' => '223', 'agrave' => '224', 'aacute' => '225', 'acirc' => '226', 'atilde' => '227', 'auml' => '228', 'aring' => '229', 'aelig' => '230', 'ccedil' => '231', 'egrave' => '232', 'eacute' => '233', 'ecirc' => '234', 'euml' => '235', 'igrave' => '236', 'iacute' => '237', 'icirc' => '238', 'iuml' => '239', 'eth' => '240', 'ntilde' => '241', 'ograve' => '242', 'oacute' => '243', 'ocirc' => '244', 'otilde' => '245', 'ouml' => '246', 'divide' => '247', 'oslash' => '248', 'ugrave' => '249', 'uacute' => '250', 'ucirc' => '251', 'uuml' => '252', 'yacute' => '253', 'thorn' => '254', 'yuml' => '255');
  1098.     if ($t[0] != '#') {
  1099.         return ($C['and_mark'] ? "\x06" : '&') . (isset($U[$t]) ? $t : (isset($N[$t]) ? (!$C['named_entity'] ? '#' . ($C['hexdec_entity'] > 1 ? 'x' . dechex($N[$t]) : $N[$t]) : $t) : 'amp;' . $t)) . ';';
  1100.     }
  1101.     if (($n = ctype_digit($t = substr($t, 1)) ? intval($t) : hexdec(substr($t, 1))) < 9 or ($n > 13 && $n < 32) or $n == 11 or $n == 12 or ($n > 126 && $n < 160 && $n != 133) or ($n > 55295 && ($n < 57344 or ($n > 64975 && $n < 64992) or $n == 65534 or $n == 65535 or $n > 1114111))) {
  1102.         return ($C['and_mark'] ? "\x06" : '&') . "amp;#{$t};";
  1103.     }
  1104.     return ($C['and_mark'] ? "\x06" : '&') . '#' . (((ctype_digit($t) && $C['hexdec_entity'] < 2) or !$C['hexdec_entity']) ? $n : 'x' . dechex($n)) . ';';
  1105.     // eof
  1106. }
  1107.  
  1108.  
  1109. /**
  1110.  * @param $p
  1111.  * @param null $c
  1112.  * @return string
  1113.  */
  1114. function hl_prot($p, $c = null)
  1115. {
  1116.     // check URL scheme
  1117.     global $C;
  1118.     $b = $a = '';
  1119.     if ($c == null) {
  1120.         $c = 'style';
  1121.         $b = $p[1];
  1122.         $a = $p[3];
  1123.         $p = trim($p[2]);
  1124.     }
  1125.     $c = isset($C['schemes'][$c]) ? $C['schemes'][$c] : $C['schemes']['*'];
  1126.     static $d = 'denied:';
  1127.     if (isset($c['!']) && substr($p, 0, 7) != $d) {
  1128.         $p = "$d$p";
  1129.     }
  1130.     if (isset($c['*']) or !strcspn($p, '#?;') or (substr($p, 0, 7) == $d)) {
  1131.         return "{$b}{$p}{$a}";
  1132.     } // All ok, frag, query, param
  1133.     if (preg_match('`^([a-z\d\-+.&#; ]+?)(:|&#(58|x3a);|%3a|\\\\0{0,4}3a).`i', $p, $m) && !isset($c[strtolower($m[1])])) { // Denied prot
  1134.         return "{$b}{$d}{$p}{$a}";
  1135.     }
  1136.     if ($C['abs_url']) {
  1137.         if ($C['abs_url'] == -1 && strpos($p, $C['base_url']) === 0) { // Make url rel
  1138.             $p = substr($p, strlen($C['base_url']));
  1139.         } elseif (empty($m[1])) { // Make URL abs
  1140.             if (substr($p, 0, 2) == '//') {
  1141.                 $p = substr($C['base_url'], 0, strpos($C['base_url'], ':') + 1) . $p;
  1142.             } elseif ($p[0] == '/') {
  1143.                 $p = preg_replace('`(^.+?://[^/]+)(.*)`', '$1', $C['base_url']) . $p;
  1144.             } elseif (strcspn($p, './')) {
  1145.                 $p = $C['base_url'] . $p;
  1146.             } else {
  1147.                 preg_match('`^([a-zA-Z\d\-+.]+://[^/]+)(.*)`', $C['base_url'], $m);
  1148.                 $p = preg_replace('`(?<=/)\./`', '', $m[2] . $p);
  1149.                 while (preg_match('`(?<=/)([^/]{3,}|[^/.]+?|\.[^/.]|[^/.]\.)/\.\./`', $p)) {
  1150.                     $p = preg_replace('`(?<=/)([^/]{3,}|[^/.]+?|\.[^/.]|[^/.]\.)/\.\./`', '', $p);
  1151.                 }
  1152.                 $p = $m[1] . $p;
  1153.             }
  1154.         }
  1155.     }
  1156.     return "{$b}{$p}{$a}";
  1157.     // eof
  1158. }
  1159.  
  1160.  
  1161. /**
  1162.  * @param $p
  1163.  * @return int
  1164.  */
  1165. function hl_regex($p)
  1166. {
  1167.     // ?regex
  1168.     if (empty($p)) {
  1169.         return 0;
  1170.     }
  1171.     if ($t = ini_get('track_errors')) {
  1172.         $o = isset($php_errormsg) ? $php_errormsg : null;
  1173.     } else {
  1174.         ini_set('track_errors', 1);
  1175.     }
  1176.     unset($php_errormsg);
  1177.     if (($d = ini_get('display_errors'))) {
  1178.         ini_set('display_errors', 0);
  1179.     }
  1180.     preg_match($p, '');
  1181.     if ($d) {
  1182.         ini_set('display_errors', 1);
  1183.     }
  1184.     $r = isset($php_errormsg) ? 0 : 1;
  1185.     if ($t) {
  1186.         $php_errormsg = isset($o) ? $o : null;
  1187.     } else {
  1188.         ini_set('track_errors', 0);
  1189.     }
  1190.     return $r;
  1191.     // eof
  1192. }
  1193.  
  1194.  
  1195. /**
  1196.  * @param $t
  1197.  * @return array
  1198.  */
  1199. function hl_spec($t)
  1200. {
  1201.     // final $spec
  1202.     $s = array();
  1203.     $t = str_replace(array(
  1204.         "\t",
  1205.         "\r",
  1206.         "\n",
  1207.         ' '
  1208.     ), '', preg_replace('/"(?>(`.|[^"])*)"/sme', 'substr(str_replace(array(";", "|", "~", " ", ",", "/", "(", ")", \'`"\'), array("\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\""), "$0"), 1, -1)', trim($t)));
  1209.     for ($i = count(($t = explode(';', $t))); --$i >= 0; ) {
  1210.         $w = $t[$i];
  1211.         if (empty($w) or ($e = strpos($w, '=')) === false or !strlen(($a = substr($w, $e + 1)))) {
  1212.             continue;
  1213.         }
  1214.         $y = $n = array();
  1215.         foreach (explode(',', $a) as $v) {
  1216.             if (!preg_match('`^([a-z:\-\*]+)(?:\((.*?)\))?`i', $v, $m)) {
  1217.                 continue;
  1218.             }
  1219.             if (($x = strtolower($m[1])) == '-*') {
  1220.                 $n['*'] = 1;
  1221.                 continue;
  1222.             }
  1223.             if ($x[0] == '-') {
  1224.                 $n[substr($x, 1)] = 1;
  1225.                 continue;
  1226.             }
  1227.             if (!isset($m[2])) {
  1228.                 $y[$x] = 1;
  1229.                 continue;
  1230.             }
  1231.             foreach (explode('/', $m[2]) as $m) {
  1232.                 if (empty($m) or ($p = strpos($m, '=')) == 0 or $p < 5) {
  1233.                     $y[$x] = 1;
  1234.                     continue;
  1235.                 }
  1236.                 $y[$x][strtolower(substr($m, 0, $p))] = str_replace(array(
  1237.                     "\x01",
  1238.                     "\x02",
  1239.                     "\x03",
  1240.                     "\x04",
  1241.                     "\x05",
  1242.                     "\x06",
  1243.                     "\x07",
  1244.                     "\x08"
  1245.                 ), array(
  1246.                     ";",
  1247.                     "|",
  1248.                     "~",
  1249.                     " ",
  1250.                     ",",
  1251.                     "/",
  1252.                     "(",
  1253.                     ")"
  1254.                 ), substr($m, $p + 1));
  1255.             }
  1256.             if (isset($y[$x]['match']) && !hl_regex($y[$x]['match'])) {
  1257.                 unset($y[$x]['match']);
  1258.             }
  1259.             if (isset($y[$x]['nomatch']) && !hl_regex($y[$x]['nomatch'])) {
  1260.                 unset($y[$x]['nomatch']);
  1261.             }
  1262.         }
  1263.         if (!count($y) && !count($n)) {
  1264.             continue;
  1265.         }
  1266.         foreach (explode(',', substr($w, 0, $e)) as $v) {
  1267.             if (!strlen(($v = strtolower($v)))) {
  1268.                 continue;
  1269.             }
  1270.             if (count($y)) {
  1271.                 $s[$v] = $y;
  1272.             }
  1273.             if (count($n)) {
  1274.                 $s[$v]['n'] = $n;
  1275.             }
  1276.         }
  1277.     }
  1278.     return $s;
  1279.     // eof
  1280. }
  1281.  
  1282.  
  1283. /**
  1284.  * @param $t
  1285.  * @return mixed|string
  1286.  */
  1287. function hl_tag($t)
  1288. {
  1289.     // tag/attribute handler
  1290.     global $C;
  1291.     $t = $t[0];
  1292.     // invalid < >
  1293.     if ($t == '< ') {
  1294.         return '&lt; ';
  1295.     }
  1296.     if ($t == '>') {
  1297.         return '&gt;';
  1298.     }
  1299.     if (!preg_match('`^<(/?)([a-zA-Z][a-zA-Z1-6]*)([^>]*?)\s?>$`m', $t, $m)) {
  1300.         return str_replace(array(
  1301.             '<',
  1302.             '>'
  1303.         ), array(
  1304.             '&lt;',
  1305.             '&gt;'
  1306.         ), $t);
  1307.     } elseif (!isset($C['elements'][($e = strtolower($m[2]))])) {
  1308.         return (($C['keep_bad'] % 2) ? str_replace(array(
  1309.             '<',
  1310.             '>'
  1311.         ), array(
  1312.             '&lt;',
  1313.             '&gt;'
  1314.         ), $t) : '');
  1315.     }
  1316.     // attr string
  1317.     $a = str_replace(array(
  1318.         "\n",
  1319.         "\r",
  1320.         "\t"
  1321.     ), ' ', trim($m[3]));
  1322.     // tag transform
  1323.     static $eD = array('applet' => 1, 'center' => 1, 'dir' => 1, 'embed' => 1, 'font' => 1, 'isindex' => 1, 'menu' => 1, 's' => 1, 'strike' => 1, 'u' => 1); // Deprecated
  1324.     if ($C['make_tag_strict'] && isset($eD[$e])) {
  1325.         $trt = hl_tag2($e, $a, $C['make_tag_strict']);
  1326.         if (!$e) {
  1327.             return (($C['keep_bad'] % 2) ? str_replace(array(
  1328.                 '<',
  1329.                 '>'
  1330.             ), array(
  1331.                 '&lt;',
  1332.                 '&gt;'
  1333.             ), $t) : '');
  1334.         }
  1335.     }
  1336.     // close tag
  1337.     static $eE = array('area' => 1, 'br' => 1, 'col' => 1, 'embed' => 1, 'hr' => 1, 'img' => 1, 'input' => 1, 'isindex' => 1, 'param' => 1); // Empty ele
  1338.     if (!empty($m[1])) {
  1339.         return (!isset($eE[$e]) ? "</$e>" : (($C['keep_bad']) % 2 ? str_replace(array(
  1340.             '<',
  1341.             '>'
  1342.         ), array(
  1343.             '&lt;',
  1344.             '&gt;'
  1345.         ), $t) : ''));
  1346.     }
  1347.    
  1348.     // open tag & attr
  1349.     static $aN = array('abbr' => array('td' => 1, 'th' => 1), 'accept-charset' => array('form' => 1), 'accept' => array('form' => 1, 'input' => 1), 'accesskey' => array('a' => 1, 'area' => 1, 'button' => 1, 'input' => 1, 'label' => 1, 'legend' => 1, 'textarea' => 1), 'action' => array('form' => 1), 'align' => array('caption' => 1, 'embed' => 1, 'applet' => 1, 'iframe' => 1, 'img' => 1, 'input' => 1, 'object' => 1, 'legend' => 1, 'table' => 1, 'hr' => 1, 'div' => 1, 'h1' => 1, 'h2' => 1, 'h3' => 1, 'h4' => 1, 'h5' => 1, 'h6' => 1, 'p' => 1, 'col' => 1, 'colgroup' => 1, 'tbody' => 1, 'td' => 1, 'tfoot' => 1, 'th' => 1, 'thead' => 1, 'tr' => 1), 'alt' => array('applet' => 1, 'area' => 1, 'img' => 1, 'input' => 1), 'archive' => array('applet' => 1, 'object' => 1), 'axis' => array('td' => 1, 'th' => 1), 'bgcolor' => array('embed' => 1, 'table' => 1, 'tr' => 1, 'td' => 1, 'th' => 1), 'border' => array('table' => 1, 'img' => 1, 'object' => 1), 'bordercolor' => array('table' => 1, 'td' => 1, 'tr' => 1), 'cellpadding' => array('table' => 1), 'cellspacing' => array('table' => 1), 'char' => array('col' => 1, 'colgroup' => 1, 'tbody' => 1, 'td' => 1, 'tfoot' => 1, 'th' => 1, 'thead' => 1, 'tr' => 1), 'charoff' => array('col' => 1, 'colgroup' => 1, 'tbody' => 1, 'td' => 1, 'tfoot' => 1, 'th' => 1, 'thead' => 1, 'tr' => 1), 'charset' => array('a' => 1, 'script' => 1), 'checked' => array('input' => 1), 'cite' => array('blockquote' => 1, 'q' => 1, 'del' => 1, 'ins' => 1), 'classid' => array('object' => 1), 'clear' => array('br' => 1), 'code' => array('applet' => 1), 'codebase' => array('object' => 1, 'applet' => 1), 'codetype' => array('object' => 1), 'color' => array('font' => 1), 'cols' => array('textarea' => 1), 'colspan' => array('td' => 1, 'th' => 1), 'compact' => array('dir' => 1, 'dl' => 1, 'menu' => 1, 'ol' => 1, 'ul' => 1), 'coords' => array('area' => 1, 'a' => 1), 'data' => array('object' => 1), 'datetime' => array('del' => 1, 'ins' => 1), 'declare' => array('object' => 1), 'defer' => array('script' => 1), 'dir' => array('bdo' => 1), 'disabled' => array('button' => 1, 'input' => 1, 'optgroup' => 1, 'option' => 1, 'select' => 1, 'textarea' => 1), 'enctype' => array('form' => 1), 'face' => array('font' => 1), 'flashvars' => array('embed' => 1), 'for' => array('label' => 1), 'frame' => array('table' => 1), 'frameborder' => array('iframe' => 1), 'headers' => array('td' => 1, 'th' => 1), 'height' => array('embed' => 1, 'iframe' => 1, 'td' => 1, 'th' => 1, 'img' => 1, 'object' => 1, 'applet' => 1), 'href' => array('a' => 1, 'area' => 1), 'hreflang' => array('a' => 1), 'hspace' => array('applet' => 1, 'img' => 1, 'object' => 1), 'ismap' => array('img' => 1, 'input' => 1), 'label' => array('option' => 1, 'optgroup' => 1), 'language' => array('script' => 1), 'longdesc' => array('img' => 1, 'iframe' => 1), 'marginheight' => array('iframe' => 1), 'marginwidth' => array('iframe' => 1), 'maxlength' => array('input' => 1), 'method' => array('form' => 1), 'model' => array('embed' => 1), 'multiple' => array('select' => 1), 'name' => array('button' => 1, 'embed' => 1, 'textarea' => 1, 'applet' => 1, 'select' => 1, 'form' => 1, 'iframe' => 1, 'img' => 1, 'a' => 1, 'input' => 1, 'object' => 1, 'map' => 1, 'param' => 1), 'nohref' => array('area' => 1), 'noshade' => array('hr' => 1), 'nowrap' => array('td' => 1, 'th' => 1), 'object' => array('applet' => 1), 'onblur' => array('a' => 1, 'area' => 1, 'button' => 1, 'input' => 1, 'label' => 1, 'select' => 1, 'textarea' => 1), 'onchange' => array('input' => 1, 'select' => 1, 'textarea' => 1), 'onfocus' => array('a' => 1, 'area' => 1, 'button' => 1, 'input' => 1, 'label' => 1, 'select' => 1, 'textarea' => 1), 'onreset' => array('form' => 1), 'onselect' => array('input' => 1, 'textarea' => 1), 'onsubmit' => array('form' => 1), 'pluginspage' => array('embed' => 1), 'pluginurl' => array('embed' => 1), 'prompt' => array('isindex' => 1), 'readonly' => array('textarea' => 1, 'input' => 1), 'rel' => array('a' => 1), 'rev' => array('a' => 1), 'rows' => array('textarea' => 1), 'rowspan' => array('td' => 1, 'th' => 1), 'rules' => array('table' => 1), 'scope' => array('td' => 1, 'th' => 1), 'scrolling' => array('iframe' => 1), 'selected' => array('option' => 1), 'shape' => array('area' => 1, 'a' => 1), 'size' => array('hr' => 1, 'font' => 1, 'input' => 1, 'select' => 1), 'span' => array('col' => 1, 'colgroup' => 1), 'src' => array('embed' => 1, 'script' => 1, 'input' => 1, 'iframe' => 1, 'img' => 1), 'standby' => array('object' => 1), 'start' => array('ol' => 1), 'summary' => array('table' => 1), 'tabindex' => array('a' => 1, 'area' => 1, 'button' => 1, 'input' => 1, 'object' => 1, 'select' => 1, 'textarea' => 1), 'target' => array('a' => 1, 'area' => 1, 'form' => 1), 'type' => array('a' => 1, 'embed' => 1, 'object' => 1, 'param' => 1, 'script' => 1, 'input' => 1, 'li' => 1, 'ol' => 1, 'ul' => 1, 'button' => 1), 'usemap' => array('img' => 1, 'input' => 1, 'object' => 1), 'valign' => array('col' => 1, 'colgroup' => 1, 'tbody' => 1, 'td' => 1, 'tfoot' => 1, 'th' => 1, 'thead' => 1, 'tr' => 1), 'value' => array('input' => 1, 'option' => 1, 'param' => 1, 'button' => 1, 'li' => 1), 'valuetype' => array('param' => 1), 'vspace' => array('applet' => 1, 'img' => 1, 'object' => 1), 'width' => array('embed' => 1, 'hr' => 1, 'iframe' => 1, 'img' => 1, 'object' => 1, 'table' => 1, 'td' => 1, 'th' => 1, 'applet' => 1, 'col' => 1, 'colgroup' => 1, 'pre' => 1), 'wmode' => array('embed' => 1), 'xml:space' => array('pre' => 1, 'script' => 1, 'style' => 1)); // Ele-specific
  1350.     static $aNE = array('checked' => 1, 'compact' => 1, 'declare' => 1, 'defer' => 1, 'disabled' => 1, 'ismap' => 1, 'multiple' => 1, 'nohref' => 1, 'noresize' => 1, 'noshade' => 1, 'nowrap' => 1, 'readonly' => 1, 'selected' => 1); // Empty
  1351.     static $aNP = array('action' => 1, 'cite' => 1, 'classid' => 1, 'codebase' => 1, 'data' => 1, 'href' => 1, 'longdesc' => 1, 'model' => 1, 'pluginspage' => 1, 'pluginurl' => 1, 'usemap' => 1); // Need scheme check; excludes style, on* & src
  1352.     static $aNU = array('class' => array('param' => 1, 'script' => 1), 'dir' => array('applet' => 1, 'bdo' => 1, 'br' => 1, 'iframe' => 1, 'param' => 1, 'script' => 1), 'id' => array('script' => 1), 'lang' => array('applet' => 1, 'br' => 1, 'iframe' => 1, 'param' => 1, 'script' => 1), 'xml:lang' => array('applet' => 1, 'br' => 1, 'iframe' => 1, 'param' => 1, 'script' => 1), 'onclick' => array('applet' => 1, 'bdo' => 1, 'br' => 1, 'font' => 1, 'iframe' => 1, 'isindex' => 1, 'param' => 1, 'script' => 1), 'ondblclick' => array('applet' => 1, 'bdo' => 1, 'br' => 1, 'font' => 1, 'iframe' => 1, 'isindex' => 1, 'param' => 1, 'script' => 1), 'onkeydown' => array('applet' => 1, 'bdo' => 1, 'br' => 1, 'font' => 1, 'iframe' => 1, 'isindex' => 1, 'param' => 1, 'script' => 1), 'onkeypress' => array('applet' => 1, 'bdo' => 1, 'br' => 1, 'font' => 1, 'iframe' => 1, 'isindex' => 1, 'param' => 1, 'script' => 1), 'onkeyup' => array('applet' => 1, 'bdo' => 1, 'br' => 1, 'font' => 1, 'iframe' => 1, 'isindex' => 1, 'param' => 1, 'script' => 1), 'onmousedown' => array('applet' => 1, 'bdo' => 1, 'br' => 1, 'font' => 1, 'iframe' => 1, 'isindex' => 1, 'param' => 1, 'script' => 1), 'onmousemove' => array('applet' => 1, 'bdo' => 1, 'br' => 1, 'font' => 1, 'iframe' => 1, 'isindex' => 1, 'param' => 1, 'script' => 1), 'onmouseout' => array('applet' => 1, 'bdo' => 1, 'br' => 1, 'font' => 1, 'iframe' => 1, 'isindex' => 1, 'param' => 1, 'script' => 1), 'onmouseover' => array('applet' => 1, 'bdo' => 1, 'br' => 1, 'font' => 1, 'iframe' => 1, 'isindex' => 1, 'param' => 1, 'script' => 1), 'onmouseup' => array('applet' => 1, 'bdo' => 1, 'br' => 1, 'font' => 1, 'iframe' => 1, 'isindex' => 1, 'param' => 1, 'script' => 1), 'style' => array('param' => 1, 'script' => 1), 'title' => array('param' => 1, 'script' => 1)); // Univ & exceptions
  1353.    
  1354.     if ($C['lc_std_val']) {
  1355.         // predef attr vals for $eAL & $aNE ele
  1356.         static $aNL = array('all' => 1, 'baseline' => 1, 'bottom' => 1, 'button' => 1, 'center' => 1, 'char' => 1, 'checkbox' => 1, 'circle' => 1, 'col' => 1, 'colgroup' => 1, 'cols' => 1, 'data' => 1, 'default' => 1, 'file' => 1, 'get' => 1, 'groups' => 1, 'hidden' => 1, 'image' => 1, 'justify' => 1, 'left' => 1, 'ltr' => 1, 'middle' => 1, 'none' => 1, 'object' => 1, 'password' => 1, 'poly' => 1, 'post' => 1, 'preserve' => 1, 'radio' => 1, 'rect' => 1, 'ref' => 1, 'reset' => 1, 'right' => 1, 'row' => 1, 'rowgroup' => 1, 'rows' => 1, 'rtl' => 1, 'submit' => 1, 'text' => 1, 'top' => 1);
  1357.         static $eAL = array('a' => 1, 'area' => 1, 'bdo' => 1, 'button' => 1, 'col' => 1, 'form' => 1, 'img' => 1, 'input' => 1, 'object' => 1, 'optgroup' => 1, 'option' => 1, 'param' => 1, 'script' => 1, 'select' => 1, 'table' => 1, 'td' => 1, 'tfoot' => 1, 'th' => 1, 'thead' => 1, 'tr' => 1, 'xml:space' => 1);
  1358.         $lcase = isset($eAL[$e]) ? 1 : 0;
  1359.     }
  1360.    
  1361.     $depTr = 0;
  1362.     if ($C['no_deprecated_attr']) {
  1363.         // dep attr:applicable ele
  1364.         static $aND = array('align' => array('caption' => 1, 'div' => 1, 'h1' => 1, 'h2' => 1, 'h3' => 1, 'h4' => 1, 'h5' => 1, 'h6' => 1, 'hr' => 1, 'img' => 1, 'input' => 1, 'legend' => 1, 'object' => 1, 'p' => 1, 'table' => 1), 'bgcolor' => array('table' => 1, 'td' => 1, 'th' => 1, 'tr' => 1), 'border' => array('img' => 1, 'object' => 1), 'bordercolor' => array('table' => 1, 'td' => 1, 'tr' => 1), 'clear' => array('br' => 1), 'compact' => array('dl' => 1, 'ol' => 1, 'ul' => 1), 'height' => array('td' => 1, 'th' => 1), 'hspace' => array('img' => 1, 'object' => 1), 'language' => array('script' => 1), 'name' => array('a' => 1, 'form' => 1, 'iframe' => 1, 'img' => 1, 'map' => 1), 'noshade' => array('hr' => 1), 'nowrap' => array('td' => 1, 'th' => 1), 'size' => array('hr' => 1), 'start' => array('ol' => 1), 'type' => array('li' => 1, 'ol' => 1, 'ul' => 1), 'value' => array('li' => 1), 'vspace' => array('img' => 1, 'object' => 1), 'width' => array('hr' => 1, 'pre' => 1, 'td' => 1, 'th' => 1));
  1365.         static $eAD = array('a' => 1, 'br' => 1, 'caption' => 1, 'div' => 1, 'dl' => 1, 'form' => 1, 'h1' => 1, 'h2' => 1, 'h3' => 1, 'h4' => 1, 'h5' => 1, 'h6' => 1, 'hr' => 1, 'iframe' => 1, 'img' => 1, 'input' => 1, 'legend' => 1, 'li' => 1, 'map' => 1, 'object' => 1, 'ol' => 1, 'p' => 1, 'pre' => 1, 'script' => 1, 'table' => 1, 'td' => 1, 'th' => 1, 'tr' => 1, 'ul' => 1);
  1366.         $depTr = isset($eAD[$e]) ? 1 : 0;
  1367.     }
  1368.    
  1369.     // attr name-vals
  1370.     if (strpos($a, "\x01") !== false) {
  1371.         $a = preg_replace('`\x01[^\x01]*\x01`', '', $a);
  1372.     } // No comment/CDATA sec
  1373.     $mode = 0;
  1374.     $a    = trim($a, ' /');
  1375.     $aA   = array();
  1376.     while (strlen($a)) {
  1377.         $w = 0;
  1378.         switch ($mode) {
  1379.             case 0: // Name
  1380.                 if (preg_match('`^[a-zA-Z][\-a-zA-Z:]+`', $a, $m)) {
  1381.                     $nm = strtolower($m[0]);
  1382.                     $w  = $mode = 1;
  1383.                     $a  = ltrim(substr_replace($a, '', 0, strlen($m[0])));
  1384.                 }
  1385.                 break;
  1386.             case 1:
  1387.                 if ($a[0] == '=') { // =
  1388.                     $w    = 1;
  1389.                     $mode = 2;
  1390.                     $a    = ltrim($a, '= ');
  1391.                 } else { // No val
  1392.                     $w       = 1;
  1393.                     $mode    = 0;
  1394.                     $a       = ltrim($a);
  1395.                     $aA[$nm] = '';
  1396.                 }
  1397.                 break;
  1398.             case 2: // Val
  1399.                 if (preg_match('`^"[^"]*"`', $a, $m) or preg_match("`^'[^']*'`", $a, $m) or preg_match("`^\s*[^\s\"']+`", $a, $m)) {
  1400.                     $m       = $m[0];
  1401.                     $w       = 1;
  1402.                     $mode    = 0;
  1403.                     $a       = ltrim(substr_replace($a, '', 0, strlen($m)));
  1404.                     $aA[$nm] = trim(($m[0] == '"' or $m[0] == '\'') ? substr($m, 1, -1) : $m);
  1405.                 }
  1406.                 break;
  1407.         }
  1408.         if ($w == 0) { // Parse errs, deal with space, " & '
  1409.             $a    = preg_replace('`^(?:"[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*`', '', $a);
  1410.             $mode = 0;
  1411.         }
  1412.     }
  1413.     if ($mode == 1) {
  1414.         $aA[$nm] = '';
  1415.     }
  1416.    
  1417.     // clean attrs
  1418.     global $S;
  1419.     $rl  = isset($S[$e]) ? $S[$e] : array();
  1420.     $a   = array();
  1421.     $nfr = 0;
  1422.     foreach ($aA as $k => $v) {
  1423.         if (((isset($C['deny_attribute']['*']) ? isset($C['deny_attribute'][$k]) : !isset($C['deny_attribute'][$k])) or isset($rl[$k])) && ((!isset($rl['n'][$k]) && !isset($rl['n']['*'])) or isset($rl[$k])) && (isset($aN[$k][$e]) or (isset($aNU[$k]) && !isset($aNU[$k][$e])))) {
  1424.             if (isset($aNE[$k])) {
  1425.                 $v = $k;
  1426.             } elseif (!empty($lcase) && (($e != 'button' or $e != 'input') or $k == 'type')) { // Rather loose but ?not cause issues
  1427.                 $v = (isset($aNL[($v2 = strtolower($v))])) ? $v2 : $v;
  1428.             }
  1429.             if ($k == 'style' && !$C['style_pass']) {
  1430.                 if (false !== strpos($v, '&#')) {
  1431.                     static $sC = array('&#x20;' => ' ', '&#32;' => ' ', '&#x45;' => 'e', '&#69;' => 'e', '&#x65;' => 'e', '&#101;' => 'e', '&#x58;' => 'x', '&#88;' => 'x', '&#x78;' => 'x', '&#120;' => 'x', '&#x50;' => 'p', '&#80;' => 'p', '&#x70;' => 'p', '&#112;' => 'p', '&#x53;' => 's', '&#83;' => 's', '&#x73;' => 's', '&#115;' => 's', '&#x49;' => 'i', '&#73;' => 'i', '&#x69;' => 'i', '&#105;' => 'i', '&#x4f;' => 'o', '&#79;' => 'o', '&#x6f;' => 'o', '&#111;' => 'o', '&#x4e;' => 'n', '&#78;' => 'n', '&#x6e;' => 'n', '&#110;' => 'n', '&#x55;' => 'u', '&#85;' => 'u', '&#x75;' => 'u', '&#117;' => 'u', '&#x52;' => 'r', '&#82;' => 'r', '&#x72;' => 'r', '&#114;' => 'r', '&#x4c;' => 'l', '&#76;' => 'l', '&#x6c;' => 'l', '&#108;' => 'l', '&#x28;' => '(', '&#40;' => '(', '&#x29;' => ')', '&#41;' => ')', '&#x20;' => ':', '&#32;' => ':', '&#x22;' => '"', '&#34;' => '"', '&#x27;' => "'", '&#39;' => "'", '&#x2f;' => '/', '&#47;' => '/', '&#x2a;' => '*', '&#42;' => '*', '&#x5c;' => '\\', '&#92;' => '\\');
  1432.                     $v = strtr($v, $sC);
  1433.                 }
  1434.                 $v = preg_replace_callback('`(url(?:\()(?: )*(?:\'|"|&(?:quot|apos);)?)(.+?)((?:\'|"|&(?:quot|apos);)?(?: )*(?:\)))`iS', 'hl_prot', $v);
  1435.                 $v = !$C['css_expression'] ? preg_replace('`expression`i', ' ', preg_replace('`\\\\\S|(/|(%2f))(\*|(%2a))`i', ' ', $v)) : $v;
  1436.             } elseif (isset($aNP[$k]) or strpos($k, 'src') !== false or $k[0] == 'o') {
  1437.                 $v = str_replace("\xad", ' ', (strpos($v, '&') !== false ? str_replace(array(
  1438.                     '&#xad;',
  1439.                     '&#173;',
  1440.                     '&shy;'
  1441.                 ), ' ', $v) : $v));
  1442.                 $v = hl_prot($v, $k);
  1443.                 if ($k == 'href') { // X-spam
  1444.                     if ($C['anti_mail_spam'] && strpos($v, 'mailto:') === 0) {
  1445.                         $v = str_replace('@', htmlspecialchars($C['anti_mail_spam']), $v);
  1446.                     } elseif ($C['anti_link_spam']) {
  1447.                         $r1 = $C['anti_link_spam'][1];
  1448.                         if (!empty($r1) && preg_match($r1, $v)) {
  1449.                             continue;
  1450.                         }
  1451.                         $r0 = $C['anti_link_spam'][0];
  1452.                         if (!empty($r0) && preg_match($r0, $v)) {
  1453.                             if (isset($a['rel'])) {
  1454.                                 if (!preg_match('`\bnofollow\b`i', $a['rel'])) {
  1455.                                     $a['rel'] .= ' nofollow';
  1456.                                 }
  1457.                             } elseif (isset($aA['rel'])) {
  1458.                                 if (!preg_match('`\bnofollow\b`i', $aA['rel'])) {
  1459.                                     $nfr = 1;
  1460.                                 }
  1461.                             } else {
  1462.                                 $a['rel'] = 'nofollow';
  1463.                             }
  1464.                         }
  1465.                     }
  1466.                 }
  1467.             }
  1468.             if (isset($rl[$k]) && is_array($rl[$k]) && ($v = hl_attrval($v, $rl[$k])) === 0) {
  1469.                 continue;
  1470.             }
  1471.             $a[$k] = str_replace('"', '&quot;', $v);
  1472.         }
  1473.     }
  1474.     if ($nfr) {
  1475.         $a['rel'] = isset($a['rel']) ? $a['rel'] . ' nofollow' : 'nofollow';
  1476.     }
  1477.    
  1478.     // rqd attr
  1479.     static $eAR = array('area' => array('alt' => 'area'), 'bdo' => array('dir' => 'ltr'), 'form' => array('action' => ''), 'img' => array('src' => '', 'alt' => 'image'), 'map' => array('name' => ''), 'optgroup' => array('label' => ''), 'param' => array('name' => ''), 'script' => array('type' => 'text/javascript'), 'textarea' => array('rows' => '10', 'cols' => '50'));
  1480.     if (isset($eAR[$e])) {
  1481.         foreach ($eAR[$e] as $k => $v) {
  1482.             if (!isset($a[$k])) {
  1483.                 $a[$k] = isset($v[0]) ? $v : $k;
  1484.             }
  1485.         }
  1486.     }
  1487.    
  1488.     // depr attrs
  1489.     if ($depTr) {
  1490.         $c = array();
  1491.         foreach ($a as $k => $v) {
  1492.             if ($k == 'style' or !isset($aND[$k][$e])) {
  1493.                 continue;
  1494.             }
  1495.             if ($k == 'align') {
  1496.                 unset($a['align']);
  1497.                 if ($e == 'img' && ($v == 'left' or $v == 'right')) {
  1498.                     $c[] = 'float: ' . $v;
  1499.                 } elseif (($e == 'div' or $e == 'table') && $v == 'center') {
  1500.                     $c[] = 'margin: auto';
  1501.                 } else {
  1502.                     $c[] = 'text-align: ' . $v;
  1503.                 }
  1504.             } elseif ($k == 'bgcolor') {
  1505.                 unset($a['bgcolor']);
  1506.                 $c[] = 'background-color: ' . $v;
  1507.             } elseif ($k == 'border') {
  1508.                 unset($a['border']);
  1509.                 $c[] = "border: {$v}px";
  1510.             } elseif ($k == 'bordercolor') {
  1511.                 unset($a['bordercolor']);
  1512.                 $c[] = 'border-color: ' . $v;
  1513.             } elseif ($k == 'clear') {
  1514.                 unset($a['clear']);
  1515.                 $c[] = 'clear: ' . ($v != 'all' ? $v : 'both');
  1516.             } elseif ($k == 'compact') {
  1517.                 unset($a['compact']);
  1518.                 $c[] = 'font-size: 85%';
  1519.             } elseif ($k == 'height' or $k == 'width') {
  1520.                 unset($a[$k]);
  1521.                 $c[] = $k . ': ' . ($v[0] != '*' ? $v . (ctype_digit($v) ? 'px' : '') : 'auto');
  1522.             } elseif ($k == 'hspace') {
  1523.                 unset($a['hspace']);
  1524.                 $c[] = "margin-left: {$v}px; margin-right: {$v}px";
  1525.             } elseif ($k == 'language' && !isset($a['type'])) {
  1526.                 unset($a['language']);
  1527.                 $a['type'] = 'text/' . strtolower($v);
  1528.             } elseif ($k == 'name') {
  1529.                 if ($C['no_deprecated_attr'] == 2 or ($e != 'a' && $e != 'map')) {
  1530.                     unset($a['name']);
  1531.                 }
  1532.                 if (!isset($a['id']) && preg_match('`[a-zA-Z][a-zA-Z\d.:_\-]*`', $v)) {
  1533.                     $a['id'] = $v;
  1534.                 }
  1535.             } elseif ($k == 'noshade') {
  1536.                 unset($a['noshade']);
  1537.                 $c[] = 'border-style: none; border: 0; background-color: gray; color: gray';
  1538.             } elseif ($k == 'nowrap') {
  1539.                 unset($a['nowrap']);
  1540.                 $c[] = 'white-space: nowrap';
  1541.             } elseif ($k == 'size') {
  1542.                 unset($a['size']);
  1543.                 $c[] = 'size: ' . $v . 'px';
  1544.             } elseif ($k == 'start' or $k == 'value') {
  1545.                 unset($a[$k]);
  1546.             } elseif ($k == 'type') {
  1547.                 unset($a['type']);
  1548.                 static $ol_type = array('i' => 'lower-roman', 'I' => 'upper-roman', 'a' => 'lower-latin', 'A' => 'upper-latin', '1' => 'decimal');
  1549.                 $c[] = 'list-style-type: ' . (isset($ol_type[$v]) ? $ol_type[$v] : 'decimal');
  1550.             } elseif ($k == 'vspace') {
  1551.                 unset($a['vspace']);
  1552.                 $c[] = "margin-top: {$v}px; margin-bottom: {$v}px";
  1553.             }
  1554.         }
  1555.         if (count($c)) {
  1556.             $c          = implode('; ', $c);
  1557.             $a['style'] = isset($a['style']) ? rtrim($a['style'], ' ;') . '; ' . $c . ';' : $c . ';';
  1558.         }
  1559.     }
  1560.     // unique ID
  1561.     if ($C['unique_ids'] && isset($a['id'])) {
  1562.         if (!preg_match('`^[A-Za-z][A-Za-z0-9_\-.:]*$`', ($id = $a['id'])) or (isset($GLOBALS['hl_Ids'][$id]) && $C['unique_ids'] == 1)) {
  1563.             unset($a['id']);
  1564.         } else {
  1565.             while (isset($GLOBALS['hl_Ids'][$id])) {
  1566.                 $id = $C['unique_ids'] . $id;
  1567.             }
  1568.             $GLOBALS['hl_Ids'][($a['id'] = $id)] = 1;
  1569.         }
  1570.     }
  1571.     // xml:lang
  1572.     if ($C['xml:lang'] && isset($a['lang'])) {
  1573.         $a['xml:lang'] = isset($a['xml:lang']) ? $a['xml:lang'] : $a['lang'];
  1574.         if ($C['xml:lang'] == 2) {
  1575.             unset($a['lang']);
  1576.         }
  1577.     }
  1578.     // for transformed tag
  1579.     if (!empty($trt)) {
  1580.         $a['style'] = isset($a['style']) ? rtrim($a['style'], ' ;') . '; ' . $trt : $trt;
  1581.     }
  1582.     // return with empty ele /
  1583.     if (empty($C['hook_tag'])) {
  1584.         $aA = '';
  1585.         foreach ($a as $k => $v) {
  1586.             $aA .= " {$k}=\"{$v}\"";
  1587.         }
  1588.         return "<{$e}{$aA}" . (isset($eE[$e]) ? ' /' : '') . '>';
  1589.     } else {
  1590.         return $C['hook_tag']($e, $a);
  1591.     }
  1592.     // eof
  1593. }
  1594.  
  1595.  
  1596. /**
  1597.  * @param $e
  1598.  * @param $a
  1599.  * @param int $t
  1600.  * @return int|string
  1601.  */
  1602. function hl_tag2(&$e, &$a, $t = 1)
  1603. {
  1604.     // transform tag
  1605.     if ($e == 'center') {
  1606.         $e = 'div';
  1607.         return 'text-align: center;';
  1608.     }
  1609.     if ($e == 'dir' or $e == 'menu') {
  1610.         $e = 'ul';
  1611.         return '';
  1612.     }
  1613.     if ($e == 's' or $e == 'strike') {
  1614.         $e = 'span';
  1615.         return 'text-decoration: line-through;';
  1616.     }
  1617.     if ($e == 'u') {
  1618.         $e = 'span';
  1619.         return 'text-decoration: underline;';
  1620.     }
  1621.     static $fs = array('0' => 'xx-small', '1' => 'xx-small', '2' => 'small', '3' => 'medium', '4' => 'large', '5' => 'x-large', '6' => 'xx-large', '7' => '300%', '-1' => 'smaller', '-2' => '60%', '+1' => 'larger', '+2' => '150%', '+3' => '200%', '+4' => '300%');
  1622.     if ($e == 'font') {
  1623.         $a2 = '';
  1624.         if (preg_match('`face\s*=\s*(\'|")([^=]+?)\\1`i', $a, $m) or preg_match('`face\s*=\s*([^"])(\S+)`i', $a, $m)) {
  1625.             $a2 .= ' font-family: ' . str_replace('"', '\'', trim($m[2])) . ';';
  1626.         }
  1627.         if (preg_match('`color\s*=\s*(\'|")?(.+?)(\\1|\s|$)`i', $a, $m)) {
  1628.             $a2 .= ' color: ' . trim($m[2]) . ';';
  1629.         }
  1630.         if (preg_match('`size\s*=\s*(\'|")?(.+?)(\\1|\s|$)`i', $a, $m) && isset($fs[($m = trim($m[2]))])) {
  1631.             $a2 .= ' font-size: ' . $fs[$m] . ';';
  1632.         }
  1633.         $e = 'span';
  1634.         return ltrim($a2);
  1635.     }
  1636.     if ($t == 2) {
  1637.         $e = 0;
  1638.         return 0;
  1639.     }
  1640.     return '';
  1641.     // eof
  1642. }
  1643.  
  1644.  
  1645. /**
  1646.  * @param $t
  1647.  * @param $w
  1648.  * @param $p
  1649.  * @return array|mixed
  1650.  */
  1651. function hl_tidy($t, $w, $p)
  1652. {
  1653.     // Tidy/compact HTM
  1654.     if (strpos(' pre,script,textarea', "$p,")) {
  1655.         return $t;
  1656.     }
  1657.     $t = str_replace(' </', '</', preg_replace(array(
  1658.         '`(<\w[^>]*(?<!/)>)\s+`',
  1659.         '`\s+`',
  1660.         '`(<\w[^>]*(?<!/)>) `'
  1661.     ), array(
  1662.         ' $1',
  1663.         ' ',
  1664.         '$1'
  1665.     ), preg_replace_callback(array(
  1666.         '`(<(!\[CDATA\[))(.+?)(\]\]>)`sm',
  1667.         '`(<(!--))(.+?)(-->)`sm',
  1668.         '`(<(pre|script|textarea)[^>]*?>)(.+?)(</\2>)`sm'
  1669.     ), create_function('$m', 'return $m[1]. str_replace(array("<", ">", "\n", "\r", "\t", " "), array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), $m[3]). $m[4];'), $t)));
  1670.     if (($w = strtolower($w)) == -1) {
  1671.         return str_replace(array(
  1672.             "\x01",
  1673.             "\x02",
  1674.             "\x03",
  1675.             "\x04",
  1676.             "\x05",
  1677.             "\x07"
  1678.         ), array(
  1679.             '<',
  1680.             '>',
  1681.             "\n",
  1682.             "\r",
  1683.             "\t",
  1684.             ' '
  1685.         ), $t);
  1686.     }
  1687.     $s = strpos(" $w", 't') ? "\t" : ' ';
  1688.     $s = preg_match('`\d`', $w, $m) ? str_repeat($s, $m[0]) : str_repeat($s, ($s == "\t" ? 1 : 2));
  1689.     $n = preg_match('`[ts]([1-9])`', $w, $m) ? $m[1] : 0;
  1690.     $a = array(
  1691.         'br' => 1
  1692.     );
  1693.     $b = array(
  1694.         'button' => 1,
  1695.         'input' => 1,
  1696.         'option' => 1
  1697.     );
  1698.     $c = array(
  1699.         'caption' => 1,
  1700.         'dd' => 1,
  1701.         'dt' => 1,
  1702.         'h1' => 1,
  1703.         'h2' => 1,
  1704.         'h3' => 1,
  1705.         'h4' => 1,
  1706.         'h5' => 1,
  1707.         'h6' => 1,
  1708.         'isindex' => 1,
  1709.         'label' => 1,
  1710.         'legend' => 1,
  1711.         'li' => 1,
  1712.         'object' => 1,
  1713.         'p' => 1,
  1714.         'pre' => 1,
  1715.         'td' => 1,
  1716.         'textarea' => 1,
  1717.         'th' => 1
  1718.     );
  1719.     $d = array(
  1720.         'address' => 1,
  1721.         'blockquote' => 1,
  1722.         'center' => 1,
  1723.         'colgroup' => 1,
  1724.         'dir' => 1,
  1725.         'div' => 1,
  1726.         'dl' => 1,
  1727.         'fieldset' => 1,
  1728.         'form' => 1,
  1729.         'hr' => 1,
  1730.         'iframe' => 1,
  1731.         'map' => 1,
  1732.         'menu' => 1,
  1733.         'noscript' => 1,
  1734.         'ol' => 1,
  1735.         'optgroup' => 1,
  1736.         'rbc' => 1,
  1737.         'rtc' => 1,
  1738.         'ruby' => 1,
  1739.         'script' => 1,
  1740.         'select' => 1,
  1741.         'table' => 1,
  1742.         'tfoot' => 1,
  1743.         'thead' => 1,
  1744.         'tr' => 1,
  1745.         'ul' => 1
  1746.     );
  1747.     ob_start();
  1748.     if (isset($d[$p])) {
  1749.         echo str_repeat($s, ++$n);
  1750.     }
  1751.     $t = explode('<', $t);
  1752.     echo ltrim(array_shift($t));
  1753.     for ($i = -1, $j = count($t); ++$i < $j; ) {
  1754.         $r = '';
  1755.         list($e, $r) = explode('>', $t[$i]);
  1756.         $x = $e[0] == '/' ? 0 : (substr($e, -1) == '/' ? 1 : ($e[0] != '!' ? 2 : -1));
  1757.         $y = !$x ? ltrim($e, '/') : ($x > 0 ? substr($e, 0, strcspn($e, ' ')) : 0);
  1758.         $e = "<$e>";
  1759.         if (isset($d[$y])) {
  1760.             if (!$x) {
  1761.                 echo "\n", str_repeat($s, --$n), "$e\n", str_repeat($s, $n);
  1762.             } else {
  1763.                 echo "\n", str_repeat($s, $n), "$e\n", str_repeat($s, ($x != 1 ? ++$n : $n));
  1764.             }
  1765.             echo ltrim($r);
  1766.             continue;
  1767.         }
  1768.         $f = "\n" . str_repeat($s, $n);
  1769.         if (isset($c[$y])) {
  1770.             if (!$x) {
  1771.                 echo $e, $f, ltrim($r);
  1772.             } else {
  1773.                 echo $f, $e, $r;
  1774.             }
  1775.         } elseif (isset($b[$y])) {
  1776.             echo $f, $e, $r;
  1777.         } elseif (isset($a[$y])) {
  1778.             echo $e, $f, ltrim($r);
  1779.         } elseif (!$y) {
  1780.             echo $f, $e, $f, ltrim($r);
  1781.         } else {
  1782.             echo $e, $r;
  1783.         }
  1784.     }
  1785.     $t = preg_replace('`[\n]\s*?[\n]+`', "\n", ob_get_contents());
  1786.     ob_end_clean();
  1787.     if (($l = strpos(" $w", 'r') ? (strpos(" $w", 'n') ? "\r\n" : "\r") : 0)) {
  1788.         $t = str_replace("\n", $l, $t);
  1789.     }
  1790.     return str_replace(array(
  1791.         "\x01",
  1792.         "\x02",
  1793.         "\x03",
  1794.         "\x04",
  1795.         "\x05",
  1796.         "\x07"
  1797.     ), array(
  1798.         '<',
  1799.         '>',
  1800.         "\n",
  1801.         "\r",
  1802.         "\t",
  1803.         ' '
  1804.     ), $t);
  1805.     // eof
  1806. }
  1807.  
  1808.  
  1809. /**
  1810.  * @return string
  1811.  */
  1812. function hl_version()
  1813. {
  1814.     // rel
  1815.     return '1.1.10';
  1816.     // eof
  1817. }
  1818.  
  1819.  
  1820. /**
  1821.  * @param $t
  1822.  * @param $h
  1823.  * @param array $p
  1824.  * @return array|mixed|string
  1825.  */
  1826. function kses($t, $h, $p = array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'gopher', 'mailto'))
  1827. {
  1828.     // kses compat
  1829.     foreach ($h as $k => $v) {
  1830.         $h[$k]['n']['*'] = 1;
  1831.     }
  1832.     $C['cdata']    = $C['comment'] = $C['make_tag_strict'] = $C['no_deprecated_attr'] = $C['unique_ids'] = 0;
  1833.     $C['keep_bad'] = 1;
  1834.     $C['elements'] = count($h) ? strtolower(implode(',', array_keys($h))) : '-*';
  1835.     $C['hook']     = 'kses_hook';
  1836.     $C['schemes']  = '*:' . implode(',', $p);
  1837.     return htmLawed($t, $C, $h);
  1838.     // eof
  1839. }
  1840.  
  1841.  
  1842. /**
  1843.  * @param $t
  1844.  * @param $C
  1845.  * @param $S
  1846.  * @return
  1847.  */
  1848. function kses_hook($t, &$C, &$S)
  1849. {
  1850.     // kses compat
  1851.     return $t;
  1852.     // eof
  1853. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement