home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Blogs / wordpress2.6.exe / wordpress2.6 / wp-includes / kses.php < prev    next >
Encoding:
PHP Script  |  2008-07-21  |  30.2 KB  |  1,069 lines

  1. <?php
  2. /**
  3.  * HTML/XHTML filter that only allows some elements and attributes
  4.  *
  5.  * Added wp_ prefix to avoid conflicts with existing kses users
  6.  *
  7.  * @version 0.2.2
  8.  * @copyright (C) 2002, 2003, 2005
  9.  * @author Ulf Harnhammar <metaur@users.sourceforge.net>
  10.  *
  11.  * @package External
  12.  * @subpackage KSES
  13.  *
  14.  * @internal
  15.  * *** CONTACT INFORMATION ***
  16.  * E-mail:      metaur at users dot sourceforge dot net
  17.  * Web page:    http://sourceforge.net/projects/kses
  18.  * Paper mail:  Ulf Harnhammar
  19.  *              Ymergatan 17 C
  20.  *              753 25  Uppsala
  21.  *              SWEDEN
  22.  *
  23.  * [kses strips evil scripts!]
  24.  */
  25.  
  26. /**
  27.  * You can override this in your my-hacks.php file
  28.  * You can also override this in a plugin file. The
  29.  * my-hacks.php is deprecated in its usage.
  30.  *
  31.  * @since 1.2.0
  32.  */
  33. if (!defined('CUSTOM_TAGS'))
  34.     define('CUSTOM_TAGS', false);
  35.  
  36. if (!CUSTOM_TAGS) {
  37.     /**
  38.      * Kses global for default allowable HTML tags
  39.      *
  40.      * Can be override by using CUSTOM_TAGS constant
  41.      * @global array $allowedposttags
  42.      * @since 2.0.0
  43.      */
  44.     $allowedposttags = array(
  45.         'address' => array(),
  46.         'a' => array(
  47.             'class' => array (),
  48.             'href' => array (),
  49.             'id' => array (),
  50.             'title' => array (),
  51.             'rel' => array (),
  52.             'rev' => array (),
  53.             'name' => array (),
  54.             'target' => array()),
  55.         'abbr' => array(
  56.             'class' => array (),
  57.             'title' => array ()),
  58.         'acronym' => array(
  59.             'title' => array ()),
  60.         'b' => array(),
  61.         'big' => array(),
  62.         'blockquote' => array(
  63.             'id' => array (),
  64.             'cite' => array (),
  65.             'class' => array(),
  66.             'lang' => array(),
  67.             'xml:lang' => array()),
  68.         'br' => array (
  69.             'class' => array ()),
  70.         'button' => array(
  71.             'disabled' => array (),
  72.             'name' => array (),
  73.             'type' => array (),
  74.             'value' => array ()),
  75.         'caption' => array(
  76.             'align' => array (),
  77.             'class' => array ()),
  78.         'cite' => array (
  79.             'class' => array(),
  80.             'dir' => array(),
  81.             'lang' => array(),
  82.             'title' => array ()),
  83.         'code' => array (
  84.             'style' => array()),
  85.         'col' => array(
  86.             'align' => array (),
  87.             'char' => array (),
  88.             'charoff' => array (),
  89.             'span' => array (),
  90.             'dir' => array(),
  91.             'style' => array (),
  92.             'valign' => array (),
  93.             'width' => array ()),
  94.         'del' => array(
  95.             'datetime' => array ()),
  96.         'dd' => array(),
  97.         'div' => array(
  98.             'align' => array (),
  99.             'class' => array (),
  100.             'dir' => array (),
  101.             'lang' => array(),
  102.             'style' => array (),
  103.             'xml:lang' => array()),
  104.         'dl' => array(),
  105.         'dt' => array(),
  106.         'em' => array(),
  107.         'fieldset' => array(),
  108.         'font' => array(
  109.             'color' => array (),
  110.             'face' => array (),
  111.             'size' => array ()),
  112.         'form' => array(
  113.             'action' => array (),
  114.             'accept' => array (),
  115.             'accept-charset' => array (),
  116.             'enctype' => array (),
  117.             'method' => array (),
  118.             'name' => array (),
  119.             'target' => array ()),
  120.         'h1' => array(
  121.             'align' => array (),
  122.             'class' => array ()),
  123.         'h2' => array(
  124.             'align' => array (),
  125.             'class' => array ()),
  126.         'h3' => array(
  127.             'align' => array (),
  128.             'class' => array ()),
  129.         'h4' => array(
  130.             'align' => array (),
  131.             'class' => array ()),
  132.         'h5' => array(
  133.             'align' => array (),
  134.             'class' => array ()),
  135.         'h6' => array(
  136.             'align' => array (),
  137.             'class' => array ()),
  138.         'hr' => array(
  139.             'align' => array (),
  140.             'class' => array (),
  141.             'noshade' => array (),
  142.             'size' => array (),
  143.             'width' => array ()),
  144.         'i' => array(),
  145.         'img' => array(
  146.             'alt' => array (),
  147.             'align' => array (),
  148.             'border' => array (),
  149.             'class' => array (),
  150.             'height' => array (),
  151.             'hspace' => array (),
  152.             'longdesc' => array (),
  153.             'vspace' => array (),
  154.             'src' => array (),
  155.             'style' => array (),
  156.             'width' => array ()),
  157.         'ins' => array(
  158.             'datetime' => array (),
  159.             'cite' => array ()),
  160.         'kbd' => array(),
  161.         'label' => array(
  162.             'for' => array ()),
  163.         'legend' => array(
  164.             'align' => array ()),
  165.         'li' => array (
  166.             'align' => array (),
  167.             'class' => array ()),
  168.         'p' => array(
  169.             'class' => array (),
  170.             'align' => array (),
  171.             'dir' => array(),
  172.             'lang' => array(),
  173.             'style' => array (),
  174.             'xml:lang' => array()),
  175.         'pre' => array(
  176.             'style' => array(),
  177.             'width' => array ()),
  178.         'q' => array(
  179.             'cite' => array ()),
  180.         's' => array(),
  181.         'span' => array (
  182.             'class' => array (),
  183.             'dir' => array (),
  184.             'align' => array (),
  185.             'lang' => array (),
  186.             'style' => array (),
  187.             'title' => array (),
  188.             'xml:lang' => array()),
  189.         'strike' => array(),
  190.         'strong' => array(),
  191.         'sub' => array(),
  192.         'sup' => array(),
  193.         'table' => array(
  194.             'align' => array (),
  195.             'bgcolor' => array (),
  196.             'border' => array (),
  197.             'cellpadding' => array (),
  198.             'cellspacing' => array (),
  199.             'class' => array (),
  200.             'dir' => array(),
  201.             'id' => array(),
  202.             'rules' => array (),
  203.             'style' => array (),
  204.             'summary' => array (),
  205.             'width' => array ()),
  206.         'tbody' => array(
  207.             'align' => array (),
  208.             'char' => array (),
  209.             'charoff' => array (),
  210.             'valign' => array ()),
  211.         'td' => array(
  212.             'abbr' => array (),
  213.             'align' => array (),
  214.             'axis' => array (),
  215.             'bgcolor' => array (),
  216.             'char' => array (),
  217.             'charoff' => array (),
  218.             'class' => array (),
  219.             'colspan' => array (),
  220.             'dir' => array(),
  221.             'headers' => array (),
  222.             'height' => array (),
  223.             'nowrap' => array (),
  224.             'rowspan' => array (),
  225.             'scope' => array (),
  226.             'style' => array (),
  227.             'valign' => array (),
  228.             'width' => array ()),
  229.         'textarea' => array(
  230.             'cols' => array (),
  231.             'rows' => array (),
  232.             'disabled' => array (),
  233.             'name' => array (),
  234.             'readonly' => array ()),
  235.         'tfoot' => array(
  236.             'align' => array (),
  237.             'char' => array (),
  238.             'class' => array (),
  239.             'charoff' => array (),
  240.             'valign' => array ()),
  241.         'th' => array(
  242.             'abbr' => array (),
  243.             'align' => array (),
  244.             'axis' => array (),
  245.             'bgcolor' => array (),
  246.             'char' => array (),
  247.             'charoff' => array (),
  248.             'class' => array (),
  249.             'colspan' => array (),
  250.             'headers' => array (),
  251.             'height' => array (),
  252.             'nowrap' => array (),
  253.             'rowspan' => array (),
  254.             'scope' => array (),
  255.             'valign' => array (),
  256.             'width' => array ()),
  257.         'thead' => array(
  258.             'align' => array (),
  259.             'char' => array (),
  260.             'charoff' => array (),
  261.             'class' => array (),
  262.             'valign' => array ()),
  263.         'title' => array(),
  264.         'tr' => array(
  265.             'align' => array (),
  266.             'bgcolor' => array (),
  267.             'char' => array (),
  268.             'charoff' => array (),
  269.             'class' => array (),
  270.             'style' => array (),
  271.             'valign' => array ()),
  272.         'tt' => array(),
  273.         'u' => array(),
  274.         'ul' => array (
  275.             'class' => array (),
  276.             'style' => array (), 
  277.             'type' => array ()),
  278.         'ol' => array (
  279.             'class' => array (),
  280.             'start' => array (),
  281.             'style' => array (), 
  282.             'type' => array ()),
  283.         'var' => array ());
  284.     /**
  285.      * Kses allowed HTML elements
  286.      *
  287.      * @global array $allowedtags
  288.      * @since 1.0.0
  289.      */
  290.     $allowedtags = array(
  291.         'a' => array(
  292.             'href' => array (),
  293.             'title' => array ()),
  294.         'abbr' => array(
  295.             'title' => array ()),
  296.         'acronym' => array(
  297.             'title' => array ()),
  298.         'b' => array(),
  299.         'blockquote' => array(
  300.             'cite' => array ()),
  301.         //    'br' => array(),
  302.         'cite' => array (),
  303.         'code' => array(),
  304.         'del' => array(
  305.             'datetime' => array ()),
  306.         //    'dd' => array(),
  307.         //    'dl' => array(),
  308.         //    'dt' => array(),
  309.         'em' => array (), 'i' => array (),
  310.         //    'ins' => array('datetime' => array(), 'cite' => array()),
  311.         //    'li' => array(),
  312.         //    'ol' => array(),
  313.         //    'p' => array(),
  314.         'q' => array(
  315.             'cite' => array ()),
  316.         'strike' => array(),
  317.         'strong' => array(),
  318.         //    'sub' => array(),
  319.         //    'sup' => array(),
  320.         //    'u' => array(),
  321.         //    'ul' => array(),
  322.     );
  323. }
  324.  
  325. /**
  326.  * wp_kses() - Filters content and keeps only allowable HTML elements.
  327.  *
  328.  * This function makes sure that only the allowed HTML element names,
  329.  * attribute names and attribute values plus only sane HTML entities
  330.  * will occur in $string. You have to remove any slashes from PHP's
  331.  * magic quotes before you call this function.
  332.  *
  333.  * The default allowed protocols are 'http', 'https', 'ftp', 'mailto',
  334.  * 'news', 'irc', 'gopher', 'nntp', 'feed', and finally 'telnet. This
  335.  * covers all common link protocols, except for 'javascript' which
  336.  * should not be allowed for untrusted users.
  337.  *
  338.  * @since 1.0.0
  339.  *
  340.  * @param string $string Content to filter through kses
  341.  * @param array $allowed_html List of allowed HTML elements
  342.  * @param array $allowed_protocols Optional. Allowed protocol in links.
  343.  * @return string Filtered content with only allowed HTML elements
  344.  */
  345. function wp_kses($string, $allowed_html, $allowed_protocols = array ('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet')) {
  346.     $string = wp_kses_no_null($string);
  347.     $string = wp_kses_js_entities($string);
  348.     $string = wp_kses_normalize_entities($string);
  349.     $allowed_html_fixed = wp_kses_array_lc($allowed_html);
  350.     $string = wp_kses_hook($string, $allowed_html_fixed, $allowed_protocols); // WP changed the order of these funcs and added args to wp_kses_hook
  351.     return wp_kses_split($string, $allowed_html_fixed, $allowed_protocols);
  352. }
  353.  
  354. /**
  355.  * wp_kses_hook() - You add any kses hooks here.
  356.  *
  357.  * There is currently only one kses WordPress hook and it is
  358.  * called here. All parameters are passed to the hooks and
  359.  * expected to recieve a string.
  360.  *
  361.  * @since 1.0.0
  362.  *
  363.  * @param string $string Content to filter through kses
  364.  * @param array $allowed_html List of allowed HTML elements
  365.  * @param array $allowed_protocols Allowed protocol in links
  366.  * @return string Filtered content through 'pre_kses' hook
  367.  */
  368. function wp_kses_hook($string, $allowed_html, $allowed_protocols) {
  369.     $string = apply_filters('pre_kses', $string, $allowed_html, $allowed_protocols);
  370.     return $string;
  371. }
  372.  
  373. /**
  374.  * wp_kses_version() - This function returns kses' version number.
  375.  *
  376.  * @since 1.0.0
  377.  *
  378.  * @return string Version Number
  379.  */
  380. function wp_kses_version() {
  381.     return '0.2.2';
  382. }
  383.  
  384. /**
  385.  * wp_kses_split() - Searches for HTML tags, no matter how malformed
  386.  *
  387.  * It also matches stray ">" characters.
  388.  *
  389.  * @since 1.0.0
  390.  *
  391.  * @param string $string Content to filter
  392.  * @param array $allowed_html Allowed HTML elements
  393.  * @param array $allowed_protocols Allowed protocols to keep
  394.  * @return string Content with fixed HTML tags
  395.  */
  396. function wp_kses_split($string, $allowed_html, $allowed_protocols) {
  397.     return preg_replace('%((<!--.*?(-->|$))|(<[^>]*(>|$)|>))%e',
  398.     "wp_kses_split2('\\1', \$allowed_html, ".'$allowed_protocols)', $string);
  399. }
  400.  
  401. /**
  402.  * wp_kses_split2() - Callback for wp_kses_split for fixing malformed HTML tags
  403.  *
  404.  * This function does a lot of work. It rejects some very malformed things
  405.  * like <:::>. It returns an empty string, if the element isn't allowed (look
  406.  * ma, no strip_tags()!). Otherwise it splits the tag into an element and an
  407.  * attribute list.
  408.  *
  409.  * After the tag is split into an element and an attribute list, it is run
  410.  * through another filter which will remove illegal attributes and once
  411.  * that is completed, will be returned.
  412.  *
  413.  * @since 1.0.0
  414.  * @uses wp_kses_attr()
  415.  *
  416.  * @param string $string Content to filter
  417.  * @param array $allowed_html Allowed HTML elements
  418.  * @param array $allowed_protocols Allowed protocols to keep
  419.  * @return string Fixed HTML element
  420.  */
  421. function wp_kses_split2($string, $allowed_html, $allowed_protocols) {
  422.     $string = wp_kses_stripslashes($string);
  423.  
  424.     if (substr($string, 0, 1) != '<')
  425.         return '>';
  426.     # It matched a ">" character
  427.  
  428.     if (preg_match('%^<!--(.*?)(-->)?$%', $string, $matches)) {
  429.         $string = str_replace(array('<!--', '-->'), '', $matches[1]);
  430.         while ( $string != $newstring = wp_kses($string, $allowed_html, $allowed_protocols) )
  431.             $string = $newstring;
  432.         if ( $string == '' )
  433.             return '';
  434.         // prevent multiple dashes in comments
  435.         $string = preg_replace('/--+/', '-', $string);
  436.         // prevent three dashes closing a comment
  437.         $string = preg_replace('/-$/', '', $string);
  438.         return "<!--{$string}-->";
  439.     }
  440.     # Allow HTML comments
  441.  
  442.     if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches))
  443.         return '';
  444.     # It's seriously malformed
  445.  
  446.     $slash = trim($matches[1]);
  447.     $elem = $matches[2];
  448.     $attrlist = $matches[3];
  449.  
  450.     if (!@isset($allowed_html[strtolower($elem)]))
  451.         return '';
  452.     # They are using a not allowed HTML element
  453.  
  454.     if ($slash != '')
  455.         return "<$slash$elem>";
  456.     # No attributes are allowed for closing elements
  457.  
  458.     return wp_kses_attr("$slash$elem", $attrlist, $allowed_html, $allowed_protocols);
  459. }
  460.  
  461. /**
  462.  * wp_kses_attr() - Removes all attributes, if none are allowed for this element
  463.  *
  464.  * If some are allowed it calls wp_kses_hair() to split them further, and then
  465.  * it builds up new HTML code from the data that kses_hair() returns. It also
  466.  * removes "<" and ">" characters, if there are any left. One more thing it
  467.  * does is to check if the tag has a closing XHTML slash, and if it does, it
  468.  * puts one in the returned code as well.
  469.  *
  470.  * @since 1.0.0
  471.  *
  472.  * @param string $element HTML element/tag
  473.  * @param string $attr HTML attributes from HTML element to closing HTML element tag
  474.  * @param array $allowed_html Allowed HTML elements
  475.  * @param array $allowed_protocols Allowed protocols to keep
  476.  * @return string Sanitized HTML element
  477.  */
  478. function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols) {
  479.     # Is there a closing XHTML slash at the end of the attributes?
  480.  
  481.     $xhtml_slash = '';
  482.     if (preg_match('%\s/\s*$%', $attr))
  483.         $xhtml_slash = ' /';
  484.  
  485.     # Are any attributes allowed at all for this element?
  486.  
  487.     if (@ count($allowed_html[strtolower($element)]) == 0)
  488.         return "<$element$xhtml_slash>";
  489.  
  490.     # Split it
  491.  
  492.     $attrarr = wp_kses_hair($attr, $allowed_protocols);
  493.  
  494.     # Go through $attrarr, and save the allowed attributes for this element
  495.     # in $attr2
  496.  
  497.     $attr2 = '';
  498.  
  499.     foreach ($attrarr as $arreach) {
  500.         if (!@ isset ($allowed_html[strtolower($element)][strtolower($arreach['name'])]))
  501.             continue; # the attribute is not allowed
  502.  
  503.         $current = $allowed_html[strtolower($element)][strtolower($arreach['name'])];
  504.         if ($current == '')
  505.             continue; # the attribute is not allowed
  506.  
  507.         if (!is_array($current))
  508.             $attr2 .= ' '.$arreach['whole'];
  509.         # there are no checks
  510.  
  511.         else {
  512.             # there are some checks
  513.             $ok = true;
  514.             foreach ($current as $currkey => $currval)
  515.                 if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
  516.                     $ok = false;
  517.                     break;
  518.                 }
  519.  
  520.             if ($ok)
  521.                 $attr2 .= ' '.$arreach['whole']; # it passed them
  522.         } # if !is_array($current)
  523.     } # foreach
  524.  
  525.     # Remove any "<" or ">" characters
  526.  
  527.     $attr2 = preg_replace('/[<>]/', '', $attr2);
  528.  
  529.     return "<$element$attr2$xhtml_slash>";
  530. }
  531.  
  532. /**
  533.  * wp_kses_hair() - Builds an attribute list from string containing attributes.
  534.  *
  535.  * This function does a lot of work. It parses an attribute list into an array
  536.  * with attribute data, and tries to do the right thing even if it gets weird
  537.  * input. It will add quotes around attribute values that don't have any quotes
  538.  * or apostrophes around them, to make it easier to produce HTML code that will
  539.  * conform to W3C's HTML specification. It will also remove bad URL protocols
  540.  * from attribute values.  It also reduces duplicate attributes by using the
  541.  * attribute defined first (foo='bar' foo='baz' will result in foo='bar').
  542.  *
  543.  * @since 1.0.0
  544.  *
  545.  * @param string $attr Attribute list from HTML element to closing HTML element tag
  546.  * @param array $allowed_protocols Allowed protocols to keep
  547.  * @return array List of attributes after parsing
  548.  */
  549. function wp_kses_hair($attr, $allowed_protocols) {
  550.     $attrarr = array ();
  551.     $mode = 0;
  552.     $attrname = '';
  553.  
  554.     # Loop through the whole attribute list
  555.  
  556.     while (strlen($attr) != 0) {
  557.         $working = 0; # Was the last operation successful?
  558.  
  559.         switch ($mode) {
  560.             case 0 : # attribute name, href for instance
  561.  
  562.                 if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) {
  563.                     $attrname = $match[1];
  564.                     $working = $mode = 1;
  565.                     $attr = preg_replace('/^[-a-zA-Z]+/', '', $attr);
  566.                 }
  567.  
  568.                 break;
  569.  
  570.             case 1 : # equals sign or valueless ("selected")
  571.  
  572.                 if (preg_match('/^\s*=\s*/', $attr)) # equals sign
  573.                     {
  574.                     $working = 1;
  575.                     $mode = 2;
  576.                     $attr = preg_replace('/^\s*=\s*/', '', $attr);
  577.                     break;
  578.                 }
  579.  
  580.                 if (preg_match('/^\s+/', $attr)) # valueless
  581.                     {
  582.                     $working = 1;
  583.                     $mode = 0;
  584.                     if(FALSE === array_key_exists($attrname, $attrarr)) {
  585.                         $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
  586.                     }
  587.                     $attr = preg_replace('/^\s+/', '', $attr);
  588.                 }
  589.  
  590.                 break;
  591.  
  592.             case 2 : # attribute value, a URL after href= for instance
  593.  
  594.                 if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match))
  595.                     # "value"
  596.                     {
  597.                     $thisval = wp_kses_bad_protocol($match[1], $allowed_protocols);
  598.  
  599.                     if(FALSE === array_key_exists($attrname, $attrarr)) {
  600.                         $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
  601.                     }
  602.                     $working = 1;
  603.                     $mode = 0;
  604.                     $attr = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr);
  605.                     break;
  606.                 }
  607.  
  608.                 if (preg_match("/^'([^']*)'(\s+|$)/", $attr, $match))
  609.                     # 'value'
  610.                     {
  611.                     $thisval = wp_kses_bad_protocol($match[1], $allowed_protocols);
  612.  
  613.                     if(FALSE === array_key_exists($attrname, $attrarr)) {
  614.                         $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname='$thisval'", 'vless' => 'n');
  615.                     }
  616.                     $working = 1;
  617.                     $mode = 0;
  618.                     $attr = preg_replace("/^'[^']*'(\s+|$)/", '', $attr);
  619.                     break;
  620.                 }
  621.  
  622.                 if (preg_match("%^([^\s\"']+)(\s+|$)%", $attr, $match))
  623.                     # value
  624.                     {
  625.                     $thisval = wp_kses_bad_protocol($match[1], $allowed_protocols);
  626.  
  627.                     if(FALSE === array_key_exists($attrname, $attrarr)) {
  628.                         $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
  629.                     }
  630.                     # We add quotes to conform to W3C's HTML spec.
  631.                     $working = 1;
  632.                     $mode = 0;
  633.                     $attr = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr);
  634.                 }
  635.  
  636.                 break;
  637.         } # switch
  638.  
  639.         if ($working == 0) # not well formed, remove and try again
  640.         {
  641.             $attr = wp_kses_html_error($attr);
  642.             $mode = 0;
  643.         }
  644.     } # while
  645.  
  646.     if ($mode == 1 && FALSE === array_key_exists($attrname, $attrarr))
  647.         # special case, for when the attribute list ends with a valueless
  648.         # attribute like "selected"
  649.         $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
  650.  
  651.     return $attrarr;
  652. }
  653.  
  654. /**
  655.  * wp_kses_check_attr_val() - Performs different checks for attribute values.
  656.  *
  657.  * The currently implemented checks are "maxlen", "minlen", "maxval", "minval"
  658.  * and "valueless" with even more checks to come soon.
  659.  *
  660.  * @since 1.0.0
  661.  *
  662.  * @param string $value Attribute value
  663.  * @param string $vless Whether the value is valueless or not. Use 'y' or 'n'
  664.  * @param string $checkname What $checkvalue is checking for.
  665.  * @param mixed $checkvalue What constraint the value should pass
  666.  * @return bool Whether check passes (true) or not (false)
  667.  */
  668. function wp_kses_check_attr_val($value, $vless, $checkname, $checkvalue) {
  669.     $ok = true;
  670.  
  671.     switch (strtolower($checkname)) {
  672.         case 'maxlen' :
  673.             # The maxlen check makes sure that the attribute value has a length not
  674.             # greater than the given value. This can be used to avoid Buffer Overflows
  675.             # in WWW clients and various Internet servers.
  676.  
  677.             if (strlen($value) > $checkvalue)
  678.                 $ok = false;
  679.             break;
  680.  
  681.         case 'minlen' :
  682.             # The minlen check makes sure that the attribute value has a length not
  683.             # smaller than the given value.
  684.  
  685.             if (strlen($value) < $checkvalue)
  686.                 $ok = false;
  687.             break;
  688.  
  689.         case 'maxval' :
  690.             # The maxval check does two things: it checks that the attribute value is
  691.             # an integer from 0 and up, without an excessive amount of zeroes or
  692.             # whitespace (to avoid Buffer Overflows). It also checks that the attribute
  693.             # value is not greater than the given value.
  694.             # This check can be used to avoid Denial of Service attacks.
  695.  
  696.             if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
  697.                 $ok = false;
  698.             if ($value > $checkvalue)
  699.                 $ok = false;
  700.             break;
  701.  
  702.         case 'minval' :
  703.             # The minval check checks that the attribute value is a positive integer,
  704.             # and that it is not smaller than the given value.
  705.  
  706.             if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
  707.                 $ok = false;
  708.             if ($value < $checkvalue)
  709.                 $ok = false;
  710.             break;
  711.  
  712.         case 'valueless' :
  713.             # The valueless check checks if the attribute has a value
  714.             # (like <a href="blah">) or not (<option selected>). If the given value
  715.             # is a "y" or a "Y", the attribute must not have a value.
  716.             # If the given value is an "n" or an "N", the attribute must have one.
  717.  
  718.             if (strtolower($checkvalue) != $vless)
  719.                 $ok = false;
  720.             break;
  721.     } # switch
  722.  
  723.     return $ok;
  724. }
  725.  
  726. /**
  727.  * wp_kses_bad_protocol() - Sanitize string from bad protocols
  728.  *
  729.  * This function removes all non-allowed protocols from the beginning
  730.  * of $string. It ignores whitespace and the case of the letters, and
  731.  * it does understand HTML entities. It does its work in a while loop,
  732.  * so it won't be fooled by a string like "javascript:javascript:alert(57)".
  733.  *
  734.  * @since 1.0.0
  735.  *
  736.  * @param string $string Content to filter bad protocols from
  737.  * @param array $allowed_protocols Allowed protocols to keep
  738.  * @return string Filtered content
  739.  */
  740. function wp_kses_bad_protocol($string, $allowed_protocols) {
  741.     $string = wp_kses_no_null($string);
  742.     $string = preg_replace('/\xad+/', '', $string); # deals with Opera "feature"
  743.     $string2 = $string.'a';
  744.  
  745.     while ($string != $string2) {
  746.         $string2 = $string;
  747.         $string = wp_kses_bad_protocol_once($string, $allowed_protocols);
  748.     } # while
  749.  
  750.     return $string;
  751. }
  752.  
  753. /**
  754.  * wp_kses_no_null() - Removes any NULL characters in $string.
  755.  *
  756.  * @since 1.0.0
  757.  *
  758.  * @param string $string
  759.  * @return string
  760.  */
  761. function wp_kses_no_null($string) {
  762.     $string = preg_replace('/\0+/', '', $string);
  763.     $string = preg_replace('/(\\\\0)+/', '', $string);
  764.  
  765.     return $string;
  766. }
  767.  
  768. /**
  769.  * wp_kses_stripslashes() - Strips slashes from in front of quotes
  770.  *
  771.  * This function changes the character sequence  \"  to just  "
  772.  * It leaves all other slashes alone. It's really weird, but the
  773.  * quoting from preg_replace(//e) seems to require this.
  774.  *
  775.  * @since 1.0.0
  776.  *
  777.  * @param string $string String to strip slashes
  778.  * @return string Fixed strings with quoted slashes
  779.  */
  780. function wp_kses_stripslashes($string) {
  781.     return preg_replace('%\\\\"%', '"', $string);
  782. }
  783.  
  784. /**
  785.  * wp_kses_array_lc() - Goes through an array and changes the keys to all lower case.
  786.  *
  787.  * @since 1.0.0
  788.  *
  789.  * @param array $inarray Unfiltered array
  790.  * @return array Fixed array with all lowercase keys
  791.  */
  792. function wp_kses_array_lc($inarray) {
  793.     $outarray = array ();
  794.  
  795.     foreach ($inarray as $inkey => $inval) {
  796.         $outkey = strtolower($inkey);
  797.         $outarray[$outkey] = array ();
  798.  
  799.         foreach ($inval as $inkey2 => $inval2) {
  800.             $outkey2 = strtolower($inkey2);
  801.             $outarray[$outkey][$outkey2] = $inval2;
  802.         } # foreach $inval
  803.     } # foreach $inarray
  804.  
  805.     return $outarray;
  806. }
  807.  
  808. /**
  809.  * wp_kses_js_entities() - Removes the HTML JavaScript entities found in early versions of Netscape 4.
  810.  *
  811.  * @since 1.0.0
  812.  *
  813.  * @param string $string
  814.  * @return string
  815.  */
  816. function wp_kses_js_entities($string) {
  817.     return preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string);
  818. }
  819.  
  820. /**
  821.  * wp_kses_html_error() - Handles parsing errors in wp_kses_hair()
  822.  *
  823.  * The general plan is to remove everything to and including some
  824.  * whitespace, but it deals with quotes and apostrophes as well.
  825.  *
  826.  * @since 1.0.0
  827.  *
  828.  * @param string $string
  829.  * @return string
  830.  */
  831. function wp_kses_html_error($string) {
  832.     return preg_replace('/^("[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*/', '', $string);
  833. }
  834.  
  835. /**
  836.  * wp_kses_bad_protocol_once() - Sanitizes content from bad protocols and other characters
  837.  *
  838.  * This function searches for URL protocols at the beginning of $string,
  839.  * while handling whitespace and HTML entities.
  840.  *
  841.  * @since 1.0.0
  842.  *
  843.  * @param string $string Content to check for bad protocols
  844.  * @param string $allowed_protocols Allowed protocols
  845.  * @return string Sanitized content
  846.  */
  847. function wp_kses_bad_protocol_once($string, $allowed_protocols) {
  848.     global $_kses_allowed_protocols;
  849.     $_kses_allowed_protocols = $allowed_protocols;
  850.  
  851.     $string2 = preg_split('/:|:|:/i', $string, 2);
  852.     if ( isset($string2[1]) && !preg_match('%/\?%', $string2[0]) )
  853.         $string = wp_kses_bad_protocol_once2($string2[0], $allowed_protocols) . trim($string2[1]);
  854.     else
  855.         $string = preg_replace_callback('/^((&[^;]*;|[\sA-Za-z0-9])*)'.'(:|:|&#[Xx]3[Aa];)\s*/', create_function('$matches', 'global $_kses_allowed_protocols; return wp_kses_bad_protocol_once2($matches[1], $_kses_allowed_protocols);'), $string);
  856.  
  857.     return $string;
  858. }
  859.  
  860. /**
  861.  * wp_kses_bad_protocol_once2() - Callback for wp_kses_bad_protocol_once() regular expression.
  862.  *
  863.  * This function processes URL protocols, checks to see if they're in the
  864.  * white-list or not, and returns different data depending on the answer.
  865.  *
  866.  * @since 1.0.0
  867.  *
  868.  * @param string $string Content to check for bad protocols
  869.  * @param array $allowed_protocols Allowed protocols
  870.  * @return string Sanitized content
  871.  */
  872. function wp_kses_bad_protocol_once2($string, $allowed_protocols) {
  873.     $string2 = wp_kses_decode_entities($string);
  874.     $string2 = preg_replace('/\s/', '', $string2);
  875.     $string2 = wp_kses_no_null($string2);
  876.     $string2 = preg_replace('/\xad+/', '', $string2);
  877.     # deals with Opera "feature"
  878.     $string2 = strtolower($string2);
  879.  
  880.     $allowed = false;
  881.     foreach ($allowed_protocols as $one_protocol)
  882.         if (strtolower($one_protocol) == $string2) {
  883.             $allowed = true;
  884.             break;
  885.         }
  886.  
  887.     if ($allowed)
  888.         return "$string2:";
  889.     else
  890.         return '';
  891. }
  892.  
  893. /**
  894.  * wp_kses_normalize_entities() - Converts and fixes HTML entities
  895.  *
  896.  * This function normalizes HTML entities. It will convert "AT&T" to the
  897.  * correct "AT&T", ":" to ":", "&#XYZZY;" to "&#XYZZY;"
  898.  * and so on.
  899.  *
  900.  * @since 1.0.0
  901.  *
  902.  * @param string $string Content to normalize entities
  903.  * @return string Content with normalized entities
  904.  */
  905. function wp_kses_normalize_entities($string) {
  906.     # Disarm all entities by converting & to &
  907.  
  908.     $string = str_replace('&', '&', $string);
  909.  
  910.     # Change back the allowed entities in our entity whitelist
  911.  
  912.     $string = preg_replace('/&([A-Za-z][A-Za-z0-9]{0,19});/', '&\\1;', $string);
  913.     $string = preg_replace_callback('/&#0*([0-9]{1,5});/', create_function('$matches', 'return wp_kses_normalize_entities2($matches[1]);'), $string);
  914.     $string = preg_replace('/&#([Xx])0*(([0-9A-Fa-f]{2}){1,2});/', '&#\\1\\2;', $string);
  915.  
  916.     return $string;
  917. }
  918.  
  919. /**
  920.  * wp_kses_normalize_entities2() - Callback for wp_kses_normalize_entities() regular expression
  921.  *
  922.  * This function helps wp_kses_normalize_entities() to only accept 16 bit
  923.  * values and nothing more for &#number; entities.
  924.  *
  925.  * @since 1.0.0
  926.  *
  927.  * @param int $i Number encoded entity
  928.  * @return string Correctly encoded entity
  929.  */
  930. function wp_kses_normalize_entities2($i) {
  931.     return (($i > 65535) ? "&#$i;" : "&#$i;");
  932. }
  933.  
  934. /**
  935.  * wp_kses_decode_entities() - Convert all entities to their character counterparts.
  936.  *
  937.  * This function decodes numeric HTML entities (A and A). It
  938.  * doesn't do anything with other entities like ä, but we don't need
  939.  * them in the URL protocol whitelisting system anyway.
  940.  *
  941.  * @since 1.0.0
  942.  *
  943.  * @param string $string Content to change entities
  944.  * @return string Content after decoded entities
  945.  */
  946. function wp_kses_decode_entities($string) {
  947.     $string = preg_replace('/&#([0-9]+);/e', 'chr("\\1")', $string);
  948.     $string = preg_replace('/&#[Xx]([0-9A-Fa-f]+);/e', 'chr(hexdec("\\1"))', $string);
  949.  
  950.     return $string;
  951. }
  952.  
  953. /**
  954.  * wp_filter_kses() - Sanitize content with allowed HTML Kses rules
  955.  *
  956.  * @since 1.0.0
  957.  * @uses $allowedtags
  958.  *
  959.  * @param string $data Content to filter
  960.  * @return string Filtered content
  961.  */
  962. function wp_filter_kses($data) {
  963.     global $allowedtags;
  964.     return addslashes( wp_kses(stripslashes( $data ), $allowedtags) );
  965. }
  966.  
  967. /**
  968.  * wp_filter_post_kses() - Sanitize content for allowed HTML tags for post content
  969.  *
  970.  * Post content refers to the page contents of the 'post' type and not
  971.  * $_POST data from forms.
  972.  *
  973.  * @since 2.0.0
  974.  * @uses $allowedposttags
  975.  *
  976.  * @param string $data Post content to filter
  977.  * @return string Filtered post content with allowed HTML tags and attributes intact.
  978.  */
  979. function wp_filter_post_kses($data) {
  980.     global $allowedposttags;
  981.     return addslashes ( wp_kses(stripslashes( $data ), $allowedposttags) );
  982. }
  983.  
  984. /**
  985.  * wp_filter_nohtml_kses() - Strips all of the HTML in the content
  986.  *
  987.  * @since 2.1.0
  988.  *
  989.  * @param string $data Content to strip all HTML from
  990.  * @return string Filtered content without any HTML
  991.  */
  992. function wp_filter_nohtml_kses($data) {
  993.     return addslashes ( wp_kses(stripslashes( $data ), array()) );
  994. }
  995.  
  996. /**
  997.  * kses_init_filters() - Adds all Kses input form content filters
  998.  *
  999.  * All hooks have default priority. The wp_filter_kses() fucntion
  1000.  * is added to the 'pre_comment_content' and 'title_save_pre'
  1001.  * hooks. The wp_filter_post_kses() function is added to the
  1002.  * 'content_save_pre', 'excerpt_save_pre', and 'content_filtered_save_pre'
  1003.  * hooks.
  1004.  *
  1005.  * @since 2.0.0
  1006.  * @uses add_filter() See description for what functions are added to what hooks.
  1007.  */
  1008. function kses_init_filters() {
  1009.     // Normal filtering.
  1010.     add_filter('pre_comment_content', 'wp_filter_kses');
  1011.     add_filter('title_save_pre', 'wp_filter_kses');
  1012.  
  1013.     // Post filtering
  1014.     add_filter('content_save_pre', 'wp_filter_post_kses');
  1015.     add_filter('excerpt_save_pre', 'wp_filter_post_kses');
  1016.     add_filter('content_filtered_save_pre', 'wp_filter_post_kses');
  1017. }
  1018.  
  1019. /**
  1020.  * kses_remove_filters() - Removes all Kses input form content filters
  1021.  *
  1022.  * A quick procedural method to removing all of the filters
  1023.  * that kses uses for content in WordPress Loop.
  1024.  *
  1025.  * Does not remove the kses_init() function from 'init' hook
  1026.  * (priority is default). Also does not remove kses_init()
  1027.  * function from 'set_current_user' hook (priority is also
  1028.  * default).
  1029.  *
  1030.  * @since 2.0.6
  1031.  */
  1032. function kses_remove_filters() {
  1033.     // Normal filtering.
  1034.     remove_filter('pre_comment_content', 'wp_filter_kses');
  1035.     remove_filter('title_save_pre', 'wp_filter_kses');
  1036.  
  1037.     // Post filtering
  1038.     remove_filter('content_save_pre', 'wp_filter_post_kses');
  1039.     remove_filter('excerpt_save_pre', 'wp_filter_post_kses');
  1040.     remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
  1041. }
  1042.  
  1043. /**
  1044.  * kses_init() - Sets up most of the Kses filters for input form content
  1045.  *
  1046.  * If you remove the kses_init() function from 'init' hook and
  1047.  * 'set_current_user' (priority is default), then none of the
  1048.  * Kses filter hooks will be added.
  1049.  *
  1050.  * First removes all of the Kses filters in case the current user
  1051.  * does not need to have Kses filter the content. If the user does
  1052.  * not have unfiltered html capability, then Kses filters are added.
  1053.  *
  1054.  * @uses kses_remove_filters() Removes the Kses filters
  1055.  * @uses kses_init_filters() Adds the Kses filters back if the user
  1056.  *        does not have unfiltered HTML capability.
  1057.  * @since 2.0.0
  1058.  */
  1059. function kses_init() {
  1060.     kses_remove_filters();
  1061.  
  1062.     if (current_user_can('unfiltered_html') == false)
  1063.         kses_init_filters();
  1064. }
  1065.  
  1066. add_action('init', 'kses_init');
  1067. add_action('set_current_user', 'kses_init');
  1068. ?>
  1069.