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