[ Index ]

PHP Cross Reference of WordPress 3.0 beta 1

[ Index ]     [ Variables ]     [ Functions ]     [ Classes ]     [ Constants ]     [ Statistics ]

title

Body

[close]

/wp-includes/ -> kses.php (source)

   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 a plugin.
  28   *
  29   * @since 1.2.0
  30   */
  31  if ( ! defined( 'CUSTOM_TAGS' ) )
  32      define( 'CUSTOM_TAGS', false );
  33  
  34  if ( ! CUSTOM_TAGS ) {
  35      /**
  36       * Kses global for default allowable HTML tags.
  37       *
  38       * Can be override by using CUSTOM_TAGS constant.
  39       *
  40       * @global array $allowedposttags
  41       * @since 2.0.0
  42       */
  43      $allowedposttags = array(
  44          'address' => array(),
  45          'a' => array(
  46              'class' => array (),
  47              'href' => array (),
  48              'id' => array (),
  49              'title' => array (),
  50              'rel' => array (),
  51              'rev' => array (),
  52              'name' => array (),
  53              'target' => array()),
  54          'abbr' => array(
  55              'class' => array (),
  56              'title' => array ()),
  57          'acronym' => array(
  58              'title' => array ()),
  59          'b' => array(),
  60          'big' => array(),
  61          'blockquote' => array(
  62              'id' => array (),
  63              'cite' => array (),
  64              'class' => array(),
  65              'lang' => array(),
  66              'xml:lang' => array()),
  67          'br' => array (
  68              'class' => array ()),
  69          'button' => array(
  70              'disabled' => array (),
  71              'name' => array (),
  72              'type' => array (),
  73              'value' => array ()),
  74          'caption' => array(
  75              'align' => array (),
  76              'class' => array ()),
  77          'cite' => array (
  78              'class' => array(),
  79              'dir' => array(),
  80              'lang' => array(),
  81              'title' => array ()),
  82          'code' => array (
  83              'style' => array()),
  84          'col' => array(
  85              'align' => array (),
  86              'char' => array (),
  87              'charoff' => array (),
  88              'span' => array (),
  89              'dir' => array(),
  90              'style' => array (),
  91              'valign' => array (),
  92              'width' => array ()),
  93          'del' => array(
  94              'datetime' => array ()),
  95          'dd' => array(),
  96          'div' => array(
  97              'align' => array (),
  98              'class' => array (),
  99              'dir' => array (),
 100              'lang' => array(),
 101              'style' => array (),
 102              'xml:lang' => array()),
 103          'dl' => array(),
 104          'dt' => array(),
 105          'em' => array(),
 106          'fieldset' => array(),
 107          'font' => array(
 108              'color' => array (),
 109              'face' => array (),
 110              'size' => array ()),
 111          'form' => array(
 112              'action' => array (),
 113              'accept' => array (),
 114              'accept-charset' => array (),
 115              'enctype' => array (),
 116              'method' => array (),
 117              'name' => array (),
 118              'target' => array ()),
 119          'h1' => array(
 120              'align' => array (),
 121              'class' => array (),
 122              'id'    => array (),
 123              'style' => array ()),
 124          'h2' => array (
 125              'align' => array (),
 126              'class' => array (),
 127              'id'    => array (),
 128              'style' => array ()),
 129          'h3' => array (
 130              'align' => array (),
 131              'class' => array (),
 132              'id'    => array (),
 133              'style' => array ()),
 134          'h4' => array (
 135              'align' => array (),
 136              'class' => array (),
 137              'id'    => array (),
 138              'style' => array ()),
 139          'h5' => array (
 140              'align' => array (),
 141              'class' => array (),
 142              'id'    => array (),
 143              'style' => array ()),
 144          'h6' => array (
 145              'align' => array (),
 146              'class' => array (),
 147              'id'    => array (),
 148              'style' => array ()),
 149          'hr' => array (
 150              'align' => array (),
 151              'class' => array (),
 152              'noshade' => array (),
 153              'size' => array (),
 154              'width' => array ()),
 155          'i' => array(),
 156          'img' => array(
 157              'alt' => array (),
 158              'align' => array (),
 159              'border' => array (),
 160              'class' => array (),
 161              'height' => array (),
 162              'hspace' => array (),
 163              'longdesc' => array (),
 164              'vspace' => array (),
 165              'src' => array (),
 166              'style' => array (),
 167              'width' => array ()),
 168          'ins' => array(
 169              'datetime' => array (),
 170              'cite' => array ()),
 171          'kbd' => array(),
 172          'label' => array(
 173              'for' => array ()),
 174          'legend' => array(
 175              'align' => array ()),
 176          'li' => array (
 177              'align' => array (),
 178              'class' => array ()),
 179          'p' => array(
 180              'class' => array (),
 181              'align' => array (),
 182              'dir' => array(),
 183              'lang' => array(),
 184              'style' => array (),
 185              'xml:lang' => array()),
 186          'pre' => array(
 187              'style' => array(),
 188              'width' => array ()),
 189          'q' => array(
 190              'cite' => array ()),
 191          's' => array(),
 192          'span' => array (
 193              'class' => array (),
 194              'dir' => array (),
 195              'align' => array (),
 196              'lang' => array (),
 197              'style' => array (),
 198              'title' => array (),
 199              'xml:lang' => array()),
 200          'strike' => array(),
 201          'strong' => array(),
 202          'sub' => array(),
 203          'sup' => array(),
 204          'table' => array(
 205              'align' => array (),
 206              'bgcolor' => array (),
 207              'border' => array (),
 208              'cellpadding' => array (),
 209              'cellspacing' => array (),
 210              'class' => array (),
 211              'dir' => array(),
 212              'id' => array(),
 213              'rules' => array (),
 214              'style' => array (),
 215              'summary' => array (),
 216              'width' => array ()),
 217          'tbody' => array(
 218              'align' => array (),
 219              'char' => array (),
 220              'charoff' => array (),
 221              'valign' => array ()),
 222          'td' => array(
 223              'abbr' => array (),
 224              'align' => array (),
 225              'axis' => array (),
 226              'bgcolor' => array (),
 227              'char' => array (),
 228              'charoff' => array (),
 229              'class' => array (),
 230              'colspan' => array (),
 231              'dir' => array(),
 232              'headers' => array (),
 233              'height' => array (),
 234              'nowrap' => array (),
 235              'rowspan' => array (),
 236              'scope' => array (),
 237              'style' => array (),
 238              'valign' => array (),
 239              'width' => array ()),
 240          'textarea' => array(
 241              'cols' => array (),
 242              'rows' => array (),
 243              'disabled' => array (),
 244              'name' => array (),
 245              'readonly' => array ()),
 246          'tfoot' => array(
 247              'align' => array (),
 248              'char' => array (),
 249              'class' => array (),
 250              'charoff' => array (),
 251              'valign' => array ()),
 252          'th' => array(
 253              'abbr' => array (),
 254              'align' => array (),
 255              'axis' => array (),
 256              'bgcolor' => array (),
 257              'char' => array (),
 258              'charoff' => array (),
 259              'class' => array (),
 260              'colspan' => array (),
 261              'headers' => array (),
 262              'height' => array (),
 263              'nowrap' => array (),
 264              'rowspan' => array (),
 265              'scope' => array (),
 266              'valign' => array (),
 267              'width' => array ()),
 268          'thead' => array(
 269              'align' => array (),
 270              'char' => array (),
 271              'charoff' => array (),
 272              'class' => array (),
 273              'valign' => array ()),
 274          'title' => array(),
 275          'tr' => array(
 276              'align' => array (),
 277              'bgcolor' => array (),
 278              'char' => array (),
 279              'charoff' => array (),
 280              'class' => array (),
 281              'style' => array (),
 282              'valign' => array ()),
 283          'tt' => array(),
 284          'u' => array(),
 285          'ul' => array (
 286              'class' => array (),
 287              'style' => array (),
 288              'type' => array ()),
 289          'ol' => array (
 290              'class' => array (),
 291              'start' => array (),
 292              'style' => array (),
 293              'type' => array ()),
 294          'var' => array ());
 295  
 296      /**
 297       * Kses allowed HTML elements.
 298       *
 299       * @global array $allowedtags
 300       * @since 1.0.0
 301       */
 302      $allowedtags = array(
 303          'a' => array(
 304              'href' => array (),
 305              'title' => array ()),
 306          'abbr' => array(
 307              'title' => array ()),
 308          'acronym' => array(
 309              'title' => array ()),
 310          'b' => array(),
 311          'blockquote' => array(
 312              'cite' => array ()),
 313          //    'br' => array(),
 314          'cite' => array (),
 315          'code' => array(),
 316          'del' => array(
 317              'datetime' => array ()),
 318          //    'dd' => array(),
 319          //    'dl' => array(),
 320          //    'dt' => array(),
 321          'em' => array (), 'i' => array (),
 322          //    'ins' => array('datetime' => array(), 'cite' => array()),
 323          //    'li' => array(),
 324          //    'ol' => array(),
 325          //    'p' => array(),
 326          'q' => array(
 327              'cite' => array ()),
 328          'strike' => array(),
 329          'strong' => array(),
 330          //    'sub' => array(),
 331          //    'sup' => array(),
 332          //    'u' => array(),
 333          //    'ul' => array(),
 334      );
 335  
 336      $allowedentitynames = array(
 337          'nbsp',    'iexcl',  'cent',    'pound',  'curren', 'yen',
 338          'brvbar',  'sect',   'uml',     'copy',   'ordf',   'laquo',
 339          'not',     'shy',    'reg',     'macr',   'deg',    'plusmn',
 340          'acute',   'micro',  'para',    'middot', 'cedil',  'ordm',
 341          'raquo',   'iquest', 'Agrave',  'Aacute', 'Acirc',  'Atilde',
 342          'Auml',    'Aring',  'AElig',   'Ccedil', 'Egrave', 'Eacute',
 343          'Ecirc',   'Euml',   'Igrave',  'Iacute', 'Icirc',  'Iuml',
 344          'ETH',     'Ntilde', 'Ograve',  'Oacute', 'Ocirc',  'Otilde',
 345          'Ouml',    'times',  'Oslash',  'Ugrave', 'Uacute', 'Ucirc',
 346          'Uuml',    'Yacute', 'THORN',   'szlig',  'agrave', 'aacute',
 347          'acirc',   'atilde', 'auml',    'aring',  'aelig',  'ccedil',
 348          'egrave',  'eacute', 'ecirc',   'euml',   'igrave', 'iacute',
 349          'icirc',   'iuml',   'eth',     'ntilde', 'ograve', 'oacute',
 350          'ocirc',   'otilde', 'ouml',    'divide', 'oslash', 'ugrave',
 351          'uacute',  'ucirc',  'uuml',    'yacute', 'thorn',  'yuml',
 352          'quot',    'amp',    'lt',      'gt',     'apos',   'OElig',
 353          'oelig',   'Scaron', 'scaron',  'Yuml',   'circ',   'tilde',
 354          'ensp',    'emsp',   'thinsp',  'zwnj',   'zwj',    'lrm',
 355          'rlm',     'ndash',  'mdash',   'lsquo',  'rsquo',  'sbquo',
 356          'ldquo',   'rdquo',  'bdquo',   'dagger', 'Dagger', 'permil',
 357          'lsaquo',  'rsaquo', 'euro',    'fnof',   'Alpha',  'Beta',
 358          'Gamma',   'Delta',  'Epsilon', 'Zeta',   'Eta',    'Theta',
 359          'Iota',    'Kappa',  'Lambda',  'Mu',     'Nu',     'Xi',
 360          'Omicron', 'Pi',     'Rho',     'Sigma',  'Tau',    'Upsilon',
 361          'Phi',     'Chi',    'Psi',     'Omega',  'alpha',  'beta',
 362          'gamma',   'delta',  'epsilon', 'zeta',   'eta',    'theta',
 363          'iota',    'kappa',  'lambda',  'mu',     'nu',     'xi',
 364          'omicron', 'pi',     'rho',     'sigmaf', 'sigma',  'tau',
 365          'upsilon', 'phi',    'chi',     'psi',    'omega',  'thetasym',
 366          'upsih',   'piv',    'bull',    'hellip', 'prime',  'Prime',
 367          'oline',   'frasl',  'weierp',  'image',  'real',   'trade',
 368          'alefsym', 'larr',   'uarr',    'rarr',   'darr',   'harr',
 369          'crarr',   'lArr',   'uArr',    'rArr',   'dArr',   'hArr',
 370          'forall',  'part',   'exist',   'empty',  'nabla',  'isin',
 371          'notin',   'ni',     'prod',    'sum',    'minus',  'lowast',
 372          'radic',   'prop',   'infin',   'ang',    'and',    'or',
 373          'cap',     'cup',    'int',     'sim',    'cong',   'asymp',
 374          'ne',      'equiv',  'le',      'ge',     'sub',    'sup',
 375          'nsub',    'sube',   'supe',    'oplus',  'otimes', 'perp',
 376          'sdot',    'lceil',  'rceil',   'lfloor', 'rfloor', 'lang',
 377          'rang',    'loz',    'spades',  'clubs',  'hearts', 'diams',
 378      );
 379  }
 380  
 381  /**
 382   * Filters content and keeps only allowable HTML elements.
 383   *
 384   * This function makes sure that only the allowed HTML element names, attribute
 385   * names and attribute values plus only sane HTML entities will occur in
 386   * $string. You have to remove any slashes from PHP's magic quotes before you
 387   * call this function.
 388   *
 389   * The default allowed protocols are 'http', 'https', 'ftp', 'mailto', 'news',
 390   * 'irc', 'gopher', 'nntp', 'feed', and finally 'telnet. This covers all common
 391   * link protocols, except for 'javascript' which should not be allowed for
 392   * untrusted users.
 393   *
 394   * @since 1.0.0
 395   *
 396   * @param string $string Content to filter through kses
 397   * @param array $allowed_html List of allowed HTML elements
 398   * @param array $allowed_protocols Optional. Allowed protocol in links.
 399   * @return string Filtered content with only allowed HTML elements
 400   */
 401  function wp_kses($string, $allowed_html, $allowed_protocols = array ('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet')) {
 402      $string = wp_kses_no_null($string);
 403      $string = wp_kses_js_entities($string);
 404      $string = wp_kses_normalize_entities($string);
 405      $allowed_html_fixed = wp_kses_array_lc($allowed_html);
 406      $string = wp_kses_hook($string, $allowed_html_fixed, $allowed_protocols); // WP changed the order of these funcs and added args to wp_kses_hook
 407      return wp_kses_split($string, $allowed_html_fixed, $allowed_protocols);
 408  }
 409  
 410  /**
 411   * You add any kses hooks here.
 412   *
 413   * There is currently only one kses WordPress hook and it is called here. All
 414   * parameters are passed to the hooks and expected to recieve a string.
 415   *
 416   * @since 1.0.0
 417   *
 418   * @param string $string Content to filter through kses
 419   * @param array $allowed_html List of allowed HTML elements
 420   * @param array $allowed_protocols Allowed protocol in links
 421   * @return string Filtered content through 'pre_kses' hook
 422   */
 423  function wp_kses_hook($string, $allowed_html, $allowed_protocols) {
 424      $string = apply_filters('pre_kses', $string, $allowed_html, $allowed_protocols);
 425      return $string;
 426  }
 427  
 428  /**
 429   * This function returns kses' version number.
 430   *
 431   * @since 1.0.0
 432   *
 433   * @return string KSES Version Number
 434   */
 435  function wp_kses_version() {
 436      return '0.2.2';
 437  }
 438  
 439  /**
 440   * Searches for HTML tags, no matter how malformed.
 441   *
 442   * It also matches stray ">" characters.
 443   *
 444   * @since 1.0.0
 445   *
 446   * @param string $string Content to filter
 447   * @param array $allowed_html Allowed HTML elements
 448   * @param array $allowed_protocols Allowed protocols to keep
 449   * @return string Content with fixed HTML tags
 450   */
 451  function wp_kses_split($string, $allowed_html, $allowed_protocols) {
 452      global $pass_allowed_html, $pass_allowed_protocols;
 453      $pass_allowed_html = $allowed_html;
 454      $pass_allowed_protocols = $allowed_protocols;
 455      return preg_replace_callback('%((<!--.*?(-->|$))|(<[^>]*(>|$)|>))%',
 456          create_function('$match', 'global $pass_allowed_html, $pass_allowed_protocols; return wp_kses_split2($match[1], $pass_allowed_html, $pass_allowed_protocols);'), $string);
 457  }
 458  
 459  /**
 460   * Callback for wp_kses_split for fixing malformed HTML tags.
 461   *
 462   * This function does a lot of work. It rejects some very malformed things like
 463   * <:::>. It returns an empty string, if the element isn't allowed (look ma, no
 464   * strip_tags()!). Otherwise it splits the tag into an element and an attribute
 465   * list.
 466   *
 467   * After the tag is split into an element and an attribute list, it is run
 468   * through another filter which will remove illegal attributes and once that is
 469   * completed, will be returned.
 470   *
 471   * @access private
 472   * @since 1.0.0
 473   * @uses wp_kses_attr()
 474   *
 475   * @param string $string Content to filter
 476   * @param array $allowed_html Allowed HTML elements
 477   * @param array $allowed_protocols Allowed protocols to keep
 478   * @return string Fixed HTML element
 479   */
 480  function wp_kses_split2($string, $allowed_html, $allowed_protocols) {
 481      $string = wp_kses_stripslashes($string);
 482  
 483      if (substr($string, 0, 1) != '<')
 484          return '&gt;';
 485      # It matched a ">" character
 486  
 487      if (preg_match('%^<!--(.*?)(-->)?$%', $string, $matches)) {
 488          $string = str_replace(array('<!--', '-->'), '', $matches[1]);
 489          while ( $string != $newstring = wp_kses($string, $allowed_html, $allowed_protocols) )
 490              $string = $newstring;
 491          if ( $string == '' )
 492              return '';
 493          // prevent multiple dashes in comments
 494          $string = preg_replace('/--+/', '-', $string);
 495          // prevent three dashes closing a comment
 496          $string = preg_replace('/-$/', '', $string);
 497          return "<!--{$string}-->";
 498      }
 499      # Allow HTML comments
 500  
 501      if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches))
 502          return '';
 503      # It's seriously malformed
 504  
 505      $slash = trim($matches[1]);
 506      $elem = $matches[2];
 507      $attrlist = $matches[3];
 508  
 509      if (!@isset($allowed_html[strtolower($elem)]))
 510          return '';
 511      # They are using a not allowed HTML element
 512  
 513      if ($slash != '')
 514          return "<$slash$elem>";
 515      # No attributes are allowed for closing elements
 516  
 517      return wp_kses_attr("$slash$elem", $attrlist, $allowed_html, $allowed_protocols);
 518  }
 519  
 520  /**
 521   * Removes all attributes, if none are allowed for this element.
 522   *
 523   * If some are allowed it calls wp_kses_hair() to split them further, and then
 524   * it builds up new HTML code from the data that kses_hair() returns. It also
 525   * removes "<" and ">" characters, if there are any left. One more thing it does
 526   * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 527   * in the returned code as well.
 528   *
 529   * @since 1.0.0
 530   *
 531   * @param string $element HTML element/tag
 532   * @param string $attr HTML attributes from HTML element to closing HTML element tag
 533   * @param array $allowed_html Allowed HTML elements
 534   * @param array $allowed_protocols Allowed protocols to keep
 535   * @return string Sanitized HTML element
 536   */
 537  function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols) {
 538      # Is there a closing XHTML slash at the end of the attributes?
 539  
 540      $xhtml_slash = '';
 541      if (preg_match('%\s*/\s*$%', $attr))
 542          $xhtml_slash = ' /';
 543  
 544      # Are any attributes allowed at all for this element?
 545  
 546      if (@ count($allowed_html[strtolower($element)]) == 0)
 547          return "<$element$xhtml_slash>";
 548  
 549      # Split it
 550  
 551      $attrarr = wp_kses_hair($attr, $allowed_protocols);
 552  
 553      # Go through $attrarr, and save the allowed attributes for this element
 554      # in $attr2
 555  
 556      $attr2 = '';
 557  
 558      foreach ($attrarr as $arreach) {
 559          if (!@ isset ($allowed_html[strtolower($element)][strtolower($arreach['name'])]))
 560              continue; # the attribute is not allowed
 561  
 562          $current = $allowed_html[strtolower($element)][strtolower($arreach['name'])];
 563          if ($current == '')
 564              continue; # the attribute is not allowed
 565  
 566          if (!is_array($current))
 567              $attr2 .= ' '.$arreach['whole'];
 568          # there are no checks
 569  
 570          else {
 571              # there are some checks
 572              $ok = true;
 573              foreach ($current as $currkey => $currval)
 574                  if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
 575                      $ok = false;
 576                      break;
 577                  }
 578  
 579              if ( $arreach['name'] == 'style' ) {
 580                  $orig_value = $arreach['value'];
 581  
 582                  $value = safecss_filter_attr($orig_value);
 583  
 584                  if ( empty($value) )
 585                      continue;
 586  
 587                  $arreach['value'] = $value;
 588  
 589                  $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
 590              }
 591  
 592              if ($ok)
 593                  $attr2 .= ' '.$arreach['whole']; # it passed them
 594          } # if !is_array($current)
 595      } # foreach
 596  
 597      # Remove any "<" or ">" characters
 598  
 599      $attr2 = preg_replace('/[<>]/', '', $attr2);
 600  
 601      return "<$element$attr2$xhtml_slash>";
 602  }
 603  
 604  /**
 605   * Builds an attribute list from string containing attributes.
 606   *
 607   * This function does a lot of work. It parses an attribute list into an array
 608   * with attribute data, and tries to do the right thing even if it gets weird
 609   * input. It will add quotes around attribute values that don't have any quotes
 610   * or apostrophes around them, to make it easier to produce HTML code that will
 611   * conform to W3C's HTML specification. It will also remove bad URL protocols
 612   * from attribute values.  It also reduces duplicate attributes by using the
 613   * attribute defined first (foo='bar' foo='baz' will result in foo='bar').
 614   *
 615   * @since 1.0.0
 616   *
 617   * @param string $attr Attribute list from HTML element to closing HTML element tag
 618   * @param array $allowed_protocols Allowed protocols to keep
 619   * @return array List of attributes after parsing
 620   */
 621  function wp_kses_hair($attr, $allowed_protocols) {
 622      $attrarr = array ();
 623      $mode = 0;
 624      $attrname = '';
 625      $uris = array('xmlns', 'profile', 'href', 'src', 'cite', 'classid', 'codebase', 'data', 'usemap', 'longdesc', 'action');
 626  
 627      # Loop through the whole attribute list
 628  
 629      while (strlen($attr) != 0) {
 630          $working = 0; # Was the last operation successful?
 631  
 632          switch ($mode) {
 633              case 0 : # attribute name, href for instance
 634  
 635                  if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) {
 636                      $attrname = $match[1];
 637                      $working = $mode = 1;
 638                      $attr = preg_replace('/^[-a-zA-Z]+/', '', $attr);
 639                  }
 640  
 641                  break;
 642  
 643              case 1 : # equals sign or valueless ("selected")
 644  
 645                  if (preg_match('/^\s*=\s*/', $attr)) # equals sign
 646                      {
 647                      $working = 1;
 648                      $mode = 2;
 649                      $attr = preg_replace('/^\s*=\s*/', '', $attr);
 650                      break;
 651                  }
 652  
 653                  if (preg_match('/^\s+/', $attr)) # valueless
 654                      {
 655                      $working = 1;
 656                      $mode = 0;
 657                      if(FALSE === array_key_exists($attrname, $attrarr)) {
 658                          $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
 659                      }
 660                      $attr = preg_replace('/^\s+/', '', $attr);
 661                  }
 662  
 663                  break;
 664  
 665              case 2 : # attribute value, a URL after href= for instance
 666  
 667                  if (preg_match('%^"([^"]*)"(\s+|/?$)%', $attr, $match))
 668                      # "value"
 669                      {
 670                      $thisval = $match[1];
 671                      if ( in_array($attrname, $uris) )
 672                          $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
 673  
 674                      if(FALSE === array_key_exists($attrname, $attrarr)) {
 675                          $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
 676                      }
 677                      $working = 1;
 678                      $mode = 0;
 679                      $attr = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr);
 680                      break;
 681                  }
 682  
 683                  if (preg_match("%^'([^']*)'(\s+|/?$)%", $attr, $match))
 684                      # 'value'
 685                      {
 686                      $thisval = $match[1];
 687                      if ( in_array($attrname, $uris) )
 688                          $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
 689  
 690                      if(FALSE === array_key_exists($attrname, $attrarr)) {
 691                          $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname='$thisval'", 'vless' => 'n');
 692                      }
 693                      $working = 1;
 694                      $mode = 0;
 695                      $attr = preg_replace("/^'[^']*'(\s+|$)/", '', $attr);
 696                      break;
 697                  }
 698  
 699                  if (preg_match("%^([^\s\"']+)(\s+|/?$)%", $attr, $match))
 700                      # value
 701                      {
 702                      $thisval = $match[1];
 703                      if ( in_array($attrname, $uris) )
 704                          $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
 705  
 706                      if(FALSE === array_key_exists($attrname, $attrarr)) {
 707                          $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
 708                      }
 709                      # We add quotes to conform to W3C's HTML spec.
 710                      $working = 1;
 711                      $mode = 0;
 712                      $attr = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr);
 713                  }
 714  
 715                  break;
 716          } # switch
 717  
 718          if ($working == 0) # not well formed, remove and try again
 719          {
 720              $attr = wp_kses_html_error($attr);
 721              $mode = 0;
 722          }
 723      } # while
 724  
 725      if ($mode == 1 && FALSE === array_key_exists($attrname, $attrarr))
 726          # special case, for when the attribute list ends with a valueless
 727          # attribute like "selected"
 728          $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
 729  
 730      return $attrarr;
 731  }
 732  
 733  /**
 734   * Performs different checks for attribute values.
 735   *
 736   * The currently implemented checks are "maxlen", "minlen", "maxval", "minval"
 737   * and "valueless" with even more checks to come soon.
 738   *
 739   * @since 1.0.0
 740   *
 741   * @param string $value Attribute value
 742   * @param string $vless Whether the value is valueless. Use 'y' or 'n'
 743   * @param string $checkname What $checkvalue is checking for.
 744   * @param mixed $checkvalue What constraint the value should pass
 745   * @return bool Whether check passes
 746   */
 747  function wp_kses_check_attr_val($value, $vless, $checkname, $checkvalue) {
 748      $ok = true;
 749  
 750      switch (strtolower($checkname)) {
 751          case 'maxlen' :
 752              # The maxlen check makes sure that the attribute value has a length not
 753              # greater than the given value. This can be used to avoid Buffer Overflows
 754              # in WWW clients and various Internet servers.
 755  
 756              if (strlen($value) > $checkvalue)
 757                  $ok = false;
 758              break;
 759  
 760          case 'minlen' :
 761              # The minlen check makes sure that the attribute value has a length not
 762              # smaller than the given value.
 763  
 764              if (strlen($value) < $checkvalue)
 765                  $ok = false;
 766              break;
 767  
 768          case 'maxval' :
 769              # The maxval check does two things: it checks that the attribute value is
 770              # an integer from 0 and up, without an excessive amount of zeroes or
 771              # whitespace (to avoid Buffer Overflows). It also checks that the attribute
 772              # value is not greater than the given value.
 773              # This check can be used to avoid Denial of Service attacks.
 774  
 775              if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
 776                  $ok = false;
 777              if ($value > $checkvalue)
 778                  $ok = false;
 779              break;
 780  
 781          case 'minval' :
 782              # The minval check checks that the attribute value is a positive integer,
 783              # and that it is not smaller than the given value.
 784  
 785              if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
 786                  $ok = false;
 787              if ($value < $checkvalue)
 788                  $ok = false;
 789              break;
 790  
 791          case 'valueless' :
 792              # The valueless check checks if the attribute has a value
 793              # (like <a href="blah">) or not (<option selected>). If the given value
 794              # is a "y" or a "Y", the attribute must not have a value.
 795              # If the given value is an "n" or an "N", the attribute must have one.
 796  
 797              if (strtolower($checkvalue) != $vless)
 798                  $ok = false;
 799              break;
 800      } # switch
 801  
 802      return $ok;
 803  }
 804  
 805  /**
 806   * Sanitize string from bad protocols.
 807   *
 808   * This function removes all non-allowed protocols from the beginning of
 809   * $string. It ignores whitespace and the case of the letters, and it does
 810   * understand HTML entities. It does its work in a while loop, so it won't be
 811   * fooled by a string like "javascript:javascript:alert(57)".
 812   *
 813   * @since 1.0.0
 814   *
 815   * @param string $string Content to filter bad protocols from
 816   * @param array $allowed_protocols Allowed protocols to keep
 817   * @return string Filtered content
 818   */
 819  function wp_kses_bad_protocol($string, $allowed_protocols) {
 820      $string = wp_kses_no_null($string);
 821      $string2 = $string.'a';
 822  
 823      while ($string != $string2) {
 824          $string2 = $string;
 825          $string = wp_kses_bad_protocol_once($string, $allowed_protocols);
 826      } # while
 827  
 828      return $string;
 829  }
 830  
 831  /**
 832   * Removes any NULL characters in $string.
 833   *
 834   * @since 1.0.0
 835   *
 836   * @param string $string
 837   * @return string
 838   */
 839  function wp_kses_no_null($string) {
 840      $string = preg_replace('/\0+/', '', $string);
 841      $string = preg_replace('/(\\\\0)+/', '', $string);
 842  
 843      return $string;
 844  }
 845  
 846  /**
 847   * Strips slashes from in front of quotes.
 848   *
 849   * This function changes the character sequence  \"  to just  ". It leaves all
 850   * other slashes alone. It's really weird, but the quoting from
 851   * preg_replace(//e) seems to require this.
 852   *
 853   * @since 1.0.0
 854   *
 855   * @param string $string String to strip slashes
 856   * @return string Fixed strings with quoted slashes
 857   */
 858  function wp_kses_stripslashes($string) {
 859      return preg_replace('%\\\\"%', '"', $string);
 860  }
 861  
 862  /**
 863   * Goes through an array and changes the keys to all lower case.
 864   *
 865   * @since 1.0.0
 866   *
 867   * @param array $inarray Unfiltered array
 868   * @return array Fixed array with all lowercase keys
 869   */
 870  function wp_kses_array_lc($inarray) {
 871      $outarray = array ();
 872  
 873      foreach ( (array) $inarray as $inkey => $inval) {
 874          $outkey = strtolower($inkey);
 875          $outarray[$outkey] = array ();
 876  
 877          foreach ( (array) $inval as $inkey2 => $inval2) {
 878              $outkey2 = strtolower($inkey2);
 879              $outarray[$outkey][$outkey2] = $inval2;
 880          } # foreach $inval
 881      } # foreach $inarray
 882  
 883      return $outarray;
 884  }
 885  
 886  /**
 887   * Removes the HTML JavaScript entities found in early versions of Netscape 4.
 888   *
 889   * @since 1.0.0
 890   *
 891   * @param string $string
 892   * @return string
 893   */
 894  function wp_kses_js_entities($string) {
 895      return preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string);
 896  }
 897  
 898  /**
 899   * Handles parsing errors in wp_kses_hair().
 900   *
 901   * The general plan is to remove everything to and including some whitespace,
 902   * but it deals with quotes and apostrophes as well.
 903   *
 904   * @since 1.0.0
 905   *
 906   * @param string $string
 907   * @return string
 908   */
 909  function wp_kses_html_error($string) {
 910      return preg_replace('/^("[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*/', '', $string);
 911  }
 912  
 913  /**
 914   * Sanitizes content from bad protocols and other characters.
 915   *
 916   * This function searches for URL protocols at the beginning of $string, while
 917   * handling whitespace and HTML entities.
 918   *
 919   * @since 1.0.0
 920   *
 921   * @param string $string Content to check for bad protocols
 922   * @param string $allowed_protocols Allowed protocols
 923   * @return string Sanitized content
 924   */
 925  function wp_kses_bad_protocol_once($string, $allowed_protocols) {
 926      global $_kses_allowed_protocols;
 927      $_kses_allowed_protocols = $allowed_protocols;
 928  
 929      $string2 = preg_split('/:|&#58;|&#x3a;/i', $string, 2);
 930      if ( isset($string2[1]) && !preg_match('%/\?%', $string2[0]) )
 931          $string = wp_kses_bad_protocol_once2($string2[0]) . trim($string2[1]);
 932      else
 933          $string = preg_replace_callback('/^((&[^;]*;|[\sA-Za-z0-9])*)'.'(:|&#58;|&#[Xx]3[Aa];)\s*/', 'wp_kses_bad_protocol_once2', $string);
 934  
 935      return $string;
 936  }
 937  
 938  /**
 939   * Callback for wp_kses_bad_protocol_once() regular expression.
 940   *
 941   * This function processes URL protocols, checks to see if they're in the
 942   * white-list or not, and returns different data depending on the answer.
 943   *
 944   * @access private
 945   * @since 1.0.0
 946   *
 947   * @param mixed $matches string or preg_replace_callback() matches array to check for bad protocols
 948   * @return string Sanitized content
 949   */
 950  function wp_kses_bad_protocol_once2($matches) {
 951      global $_kses_allowed_protocols;
 952  
 953      if ( is_array($matches) ) {
 954          if ( empty($matches[1]) )
 955              return '';
 956  
 957          $string = $matches[1];
 958      } else {
 959          $string = $matches;
 960      }
 961  
 962      $string2 = wp_kses_decode_entities($string);
 963      $string2 = preg_replace('/\s/', '', $string2);
 964      $string2 = wp_kses_no_null($string2);
 965      $string2 = strtolower($string2);
 966  
 967      $allowed = false;
 968      foreach ( (array) $_kses_allowed_protocols as $one_protocol)
 969          if (strtolower($one_protocol) == $string2) {
 970              $allowed = true;
 971              break;
 972          }
 973  
 974      if ($allowed)
 975          return "$string2:";
 976      else
 977          return '';
 978  }
 979  
 980  /**
 981   * Converts and fixes HTML entities.
 982   *
 983   * This function normalizes HTML entities. It will convert "AT&T" to the correct
 984   * "AT&amp;T", "&#00058;" to "&#58;", "&#XYZZY;" to "&amp;#XYZZY;" and so on.
 985   *
 986   * @since 1.0.0
 987   *
 988   * @param string $string Content to normalize entities
 989   * @return string Content with normalized entities
 990   */
 991  function wp_kses_normalize_entities($string) {
 992      # Disarm all entities by converting & to &amp;
 993  
 994      $string = str_replace('&', '&amp;', $string);
 995  
 996      # Change back the allowed entities in our entity whitelist
 997  
 998      $string = preg_replace_callback('/&amp;([A-Za-z]{2,8});/', 'wp_kses_named_entities', $string);
 999      $string = preg_replace_callback('/&amp;#(0*[0-9]{1,7});/', 'wp_kses_normalize_entities2', $string);
1000      $string = preg_replace_callback('/&amp;#[Xx](0*[0-9A-Fa-f]{1,6});/', 'wp_kses_normalize_entities3', $string);
1001  
1002      return $string;
1003  }
1004  
1005  /**
1006   * Callback for wp_kses_normalize_entities() regular expression.
1007   *
1008   * This function only accepts valid named entity references, which are finite,
1009   * case-sensitive, and highly scrutinized by HTML and XML validators.
1010   *
1011   * @since 3.0.0
1012   *
1013   * @param array $matches preg_replace_callback() matches array
1014   * @return string Correctly encoded entity
1015   */
1016  function wp_kses_named_entities($matches) {
1017      global $allowedentitynames;
1018  
1019      if ( empty($matches[1]) )
1020          return '';
1021  
1022      $i = $matches[1];
1023      return ( ( ! in_array($i, $allowedentitynames) ) ? "&amp;$i;" : "&$i;" );
1024  }
1025  
1026  /**
1027   * Callback for wp_kses_normalize_entities() regular expression.
1028   *
1029   * This function helps wp_kses_normalize_entities() to only accept 16 bit values
1030   * and nothing more for &#number; entities.
1031   *
1032   * @access private
1033   * @since 1.0.0
1034   *
1035   * @param array $matches preg_replace_callback() matches array
1036   * @return string Correctly encoded entity
1037   */
1038  function wp_kses_normalize_entities2($matches) {
1039      if ( empty($matches[1]) )
1040          return '';
1041  
1042      $i = $matches[1];
1043      if (valid_unicode($i)) {
1044          $i = str_pad(ltrim($i,'0'), 3, '0', STR_PAD_LEFT);
1045          $i = "&#$i;";
1046      } else {
1047          $i = "&amp;#$i;";
1048      }
1049  
1050      return $i;
1051  }
1052  
1053  /**
1054   * Callback for wp_kses_normalize_entities() for regular expression.
1055   *
1056   * This function helps wp_kses_normalize_entities() to only accept valid Unicode
1057   * numeric entities in hex form.
1058   *
1059   * @access private
1060   *
1061   * @param array $matches preg_replace_callback() matches array
1062   * @return string Correctly encoded entity
1063   */
1064  function wp_kses_normalize_entities3($matches) {
1065      if ( empty($matches[1]) )
1066          return '';
1067  
1068      $hexchars = $matches[1];
1069      return ( ( ! valid_unicode(hexdec($hexchars)) ) ? "&amp;#x$hexchars;" : '&#x'.ltrim($hexchars,'0').';' );
1070  }
1071  
1072  /**
1073   * Helper function to determine if a Unicode value is valid.
1074   *
1075   * @param int $i Unicode value
1076   * @return bool true if the value was a valid Unicode number
1077   */
1078  function valid_unicode($i) {
1079      return ( $i == 0x9 || $i == 0xa || $i == 0xd ||
1080              ($i >= 0x20 && $i <= 0xd7ff) ||
1081              ($i >= 0xe000 && $i <= 0xfffd) ||
1082              ($i >= 0x10000 && $i <= 0x10ffff) );
1083  }
1084  
1085  /**
1086   * Convert all entities to their character counterparts.
1087   *
1088   * This function decodes numeric HTML entities (&#65; and &#x41;). It doesn't do
1089   * anything with other entities like &auml;, but we don't need them in the URL
1090   * protocol whitelisting system anyway.
1091   *
1092   * @since 1.0.0
1093   *
1094   * @param string $string Content to change entities
1095   * @return string Content after decoded entities
1096   */
1097  function wp_kses_decode_entities($string) {
1098      $string = preg_replace_callback('/&#([0-9]+);/', '_wp_kses_decode_entities_chr', $string);
1099      $string = preg_replace_callback('/&#[Xx]([0-9A-Fa-f]+);/', '_wp_kses_decode_entities_chr_hexdec', $string);
1100  
1101      return $string;
1102  }
1103  
1104  /**
1105   * Regex callback for wp_kses_decode_entities()
1106   *
1107   * @param array $match preg match
1108   * @return string
1109   */
1110  function _wp_kses_decode_entities_chr( $match ) {
1111      return chr( $match[1] );
1112  }
1113  
1114  /**
1115   * Regex callback for wp_kses_decode_entities()
1116   *
1117   * @param array $match preg match
1118   * @return string
1119   */
1120  function _wp_kses_decode_entities_chr_hexdec( $match ) {
1121      return chr( hexdec( $match[1] ) );
1122  }
1123  
1124  /**
1125   * Sanitize content with allowed HTML Kses rules.
1126   *
1127   * @since 1.0.0
1128   * @uses $allowedtags
1129   *
1130   * @param string $data Content to filter, expected to be escaped with slashes
1131   * @return string Filtered content
1132   */
1133  function wp_filter_kses($data) {
1134      global $allowedtags;
1135      return addslashes( wp_kses(stripslashes( $data ), $allowedtags) );
1136  }
1137  
1138  /**
1139   * Sanitize content with allowed HTML Kses rules.
1140   *
1141   * @since 2.9.0
1142   * @uses $allowedtags
1143   *
1144   * @param string $data Content to filter, expected to not be escaped
1145   * @return string Filtered content
1146   */
1147  function wp_kses_data($data) {
1148      global $allowedtags;
1149      return wp_kses( $data , $allowedtags );
1150  }
1151  
1152  /**
1153   * Sanitize content for allowed HTML tags for post content.
1154   *
1155   * Post content refers to the page contents of the 'post' type and not $_POST
1156   * data from forms.
1157   *
1158   * @since 2.0.0
1159   * @uses $allowedposttags
1160   *
1161   * @param string $data Post content to filter, expected to be escaped with slashes
1162   * @return string Filtered post content with allowed HTML tags and attributes intact.
1163   */
1164  function wp_filter_post_kses($data) {
1165      global $allowedposttags;
1166      return addslashes ( wp_kses(stripslashes( $data ), $allowedposttags) );
1167  }
1168  
1169  /**
1170   * Sanitize content for allowed HTML tags for post content.
1171   *
1172   * Post content refers to the page contents of the 'post' type and not $_POST
1173   * data from forms.
1174   *
1175   * @since 2.9.0
1176   * @uses $allowedposttags
1177   *
1178   * @param string $data Post content to filter
1179   * @return string Filtered post content with allowed HTML tags and attributes intact.
1180   */
1181  function wp_kses_post($data) {
1182      global $allowedposttags;
1183      return wp_kses( $data , $allowedposttags );
1184  }
1185  
1186  /**
1187   * Strips all of the HTML in the content.
1188   *
1189   * @since 2.1.0
1190   *
1191   * @param string $data Content to strip all HTML from
1192   * @return string Filtered content without any HTML
1193   */
1194  function wp_filter_nohtml_kses($data) {
1195      return addslashes ( wp_kses(stripslashes( $data ), array()) );
1196  }
1197  
1198  /**
1199   * Adds all Kses input form content filters.
1200   *
1201   * All hooks have default priority. The wp_filter_kses() function is added to
1202   * the 'pre_comment_content' and 'title_save_pre' hooks.
1203   *
1204   * The wp_filter_post_kses() function is added to the 'content_save_pre',
1205   * 'excerpt_save_pre', and 'content_filtered_save_pre' hooks.
1206   *
1207   * @since 2.0.0
1208   * @uses add_filter() See description for what functions are added to what hooks.
1209   */
1210  function kses_init_filters() {
1211      // Normal filtering.
1212      add_filter('pre_comment_content', 'wp_filter_kses');
1213      add_filter('title_save_pre', 'wp_filter_kses');
1214  
1215      // Post filtering
1216      add_filter('content_save_pre', 'wp_filter_post_kses');
1217      add_filter('excerpt_save_pre', 'wp_filter_post_kses');
1218      add_filter('content_filtered_save_pre', 'wp_filter_post_kses');
1219  }
1220  
1221  /**
1222   * Removes all Kses input form content filters.
1223   *
1224   * A quick procedural method to removing all of the filters that kses uses for
1225   * content in WordPress Loop.
1226   *
1227   * Does not remove the kses_init() function from 'init' hook (priority is
1228   * default). Also does not remove kses_init() function from 'set_current_user'
1229   * hook (priority is also default).
1230   *
1231   * @since 2.0.6
1232   */
1233  function kses_remove_filters() {
1234      // Normal filtering.
1235      remove_filter('pre_comment_content', 'wp_filter_kses');
1236      remove_filter('title_save_pre', 'wp_filter_kses');
1237  
1238      // Post filtering
1239      remove_filter('content_save_pre', 'wp_filter_post_kses');
1240      remove_filter('excerpt_save_pre', 'wp_filter_post_kses');
1241      remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
1242  }
1243  
1244  /**
1245   * Sets up most of the Kses filters for input form content.
1246   *
1247   * If you remove the kses_init() function from 'init' hook and
1248   * 'set_current_user' (priority is default), then none of the Kses filter hooks
1249   * will be added.
1250   *
1251   * First removes all of the Kses filters in case the current user does not need
1252   * to have Kses filter the content. If the user does not have unfiltered html
1253   * capability, then Kses filters are added.
1254   *
1255   * @uses kses_remove_filters() Removes the Kses filters
1256   * @uses kses_init_filters() Adds the Kses filters back if the user
1257   *        does not have unfiltered HTML capability.
1258   * @since 2.0.0
1259   */
1260  function kses_init() {
1261      kses_remove_filters();
1262  
1263      if (current_user_can('unfiltered_html') == false)
1264          kses_init_filters();
1265  }
1266  
1267  add_action('init', 'kses_init');
1268  add_action('set_current_user', 'kses_init');
1269  
1270  /**
1271   * Inline CSS filter
1272   *
1273   * @since 2.8.1
1274   */
1275  function safecss_filter_attr( $css, $deprecated = '' ) {
1276      if ( !empty( $deprecated ) )
1277          _deprecated_argument( __FUNCTION__, '2.8.1' ); // Never implemented
1278  
1279      $css = wp_kses_no_null($css);
1280      $css = str_replace(array("\n","\r","\t"), '', $css);
1281  
1282      if ( preg_match( '%[\\(&]|/\*%', $css ) ) // remove any inline css containing \ ( & or comments
1283          return '';
1284  
1285      $css_array = split( ';', trim( $css ) );
1286      $allowed_attr = apply_filters( 'safe_style_css', array( 'text-align', 'margin', 'color', 'float',
1287      'border', 'background', 'background-color', 'border-bottom', 'border-bottom-color',
1288      'border-bottom-style', 'border-bottom-width', 'border-collapse', 'border-color', 'border-left',
1289      'border-left-color', 'border-left-style', 'border-left-width', 'border-right', 'border-right-color',
1290      'border-right-style', 'border-right-width', 'border-spacing', 'border-style', 'border-top',
1291      'border-top-color', 'border-top-style', 'border-top-width', 'border-width', 'caption-side',
1292      'clear', 'cursor', 'direction', 'font', 'font-family', 'font-size', 'font-style',
1293      'font-variant', 'font-weight', 'height', 'letter-spacing', 'line-height', 'margin-bottom',
1294      'margin-left', 'margin-right', 'margin-top', 'overflow', 'padding', 'padding-bottom',
1295      'padding-left', 'padding-right', 'padding-top', 'text-decoration', 'text-indent', 'vertical-align',
1296      'width' ) );
1297  
1298      if ( empty($allowed_attr) )
1299          return $css;
1300  
1301      $css = '';
1302      foreach ( $css_array as $css_item ) {
1303          if ( $css_item == '' )
1304              continue;
1305          $css_item = trim( $css_item );
1306          $found = false;
1307          if ( strpos( $css_item, ':' ) === false ) {
1308              $found = true;
1309          } else {
1310              $parts = split( ':', $css_item );
1311              if ( in_array( trim( $parts[0] ), $allowed_attr ) )
1312                  $found = true;
1313          }
1314          if ( $found ) {
1315              if( $css != '' )
1316                  $css .= ';';
1317              $css .= $css_item;
1318          }
1319      }
1320  
1321      return $css;
1322  }


Generated: Mon Apr 5 14:26:09 2010 Cross-referenced by PHPXref 0.7