Changeset 33360 for branches/4.2/src/wp-includes/kses.php
- Timestamp:
- 07/22/2015 05:43:35 AM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/4.2/src/wp-includes/kses.php
r31205 r33360 530 530 531 531 /** 532 * Filters one attribute only and ensures its value is allowed. 533 * 534 * This function has the advantage of being more secure than esc_attr() and can 535 * escape data in some situations where wp_kses() must strip the whole attribute. 536 * 537 * @since 4.2.3 538 * 539 * @param string $string The 'whole' attribute, including name and value. 540 * @param string $element The element name to which the attribute belongs. 541 * @return string Filtered attribute. 542 */ 543 function wp_kses_one_attr( $string, $element ) { 544 $uris = array('xmlns', 'profile', 'href', 'src', 'cite', 'classid', 'codebase', 'data', 'usemap', 'longdesc', 'action'); 545 $allowed_html = wp_kses_allowed_html( 'post' ); 546 $allowed_protocols = wp_allowed_protocols(); 547 $string = wp_kses_no_null( $string, array( 'slash_zero' => 'keep' ) ); 548 $string = wp_kses_js_entities( $string ); 549 $string = wp_kses_normalize_entities( $string ); 550 551 // Preserve leading and trailing whitespace. 552 $matches = array(); 553 preg_match('/^\s*/', $string, $matches); 554 $lead = $matches[0]; 555 preg_match('/\s*$/', $string, $matches); 556 $trail = $matches[0]; 557 if ( empty( $trail ) ) { 558 $string = substr( $string, strlen( $lead ) ); 559 } else { 560 $string = substr( $string, strlen( $lead ), -strlen( $trail ) ); 561 } 562 563 // Parse attribute name and value from input. 564 $split = preg_split( '/\s*=\s*/', $string, 2 ); 565 $name = $split[0]; 566 if ( count( $split ) == 2 ) { 567 $value = $split[1]; 568 569 // Remove quotes surrounding $value. 570 // Also guarantee correct quoting in $string for this one attribute. 571 if ( '' == $value ) { 572 $quote = ''; 573 } else { 574 $quote = $value[0]; 575 } 576 if ( '"' == $quote || "'" == $quote ) { 577 if ( substr( $value, -1 ) != $quote ) { 578 return ''; 579 } 580 $value = substr( $value, 1, -1 ); 581 } else { 582 $quote = '"'; 583 } 584 585 // Sanitize quotes and angle braces. 586 $value = htmlspecialchars( $value, ENT_QUOTES, null, false ); 587 588 // Sanitize URI values. 589 if ( in_array( strtolower( $name ), $uris ) ) { 590 $value = wp_kses_bad_protocol( $value, $allowed_protocols ); 591 } 592 593 $string = "$name=$quote$value$quote"; 594 $vless = 'n'; 595 } else { 596 $value = ''; 597 $vless = 'y'; 598 } 599 600 // Sanitize attribute by name. 601 wp_kses_attr_check( $name, $value, $string, $vless, $element, $allowed_html ); 602 603 // Restore whitespace. 604 return $lead . $string . $trail; 605 } 606 607 /** 532 608 * Return a list of allowed tags and attributes for a given context. 533 609 * … … 749 825 // in $attr2 750 826 $attr2 = ''; 751 752 $allowed_attr = $allowed_html[strtolower($element)]; 753 foreach ($attrarr as $arreach) { 754 if ( ! isset( $allowed_attr[strtolower($arreach['name'])] ) ) 755 continue; // the attribute is not allowed 756 757 $current = $allowed_attr[strtolower($arreach['name'])]; 758 if ( $current == '' ) 759 continue; // the attribute is not allowed 760 761 if ( strtolower( $arreach['name'] ) == 'style' ) { 762 $orig_value = $arreach['value']; 763 $value = safecss_filter_attr( $orig_value ); 764 765 if ( empty( $value ) ) 766 continue; 767 768 $arreach['value'] = $value; 769 $arreach['whole'] = str_replace( $orig_value, $value, $arreach['whole'] ); 827 foreach ( $attrarr as $arreach ) { 828 if ( wp_kses_attr_check( $arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html ) ) { 829 $attr2 .= ' '.$arreach['whole']; 770 830 } 771 772 if ( ! is_array($current) ) { 773 $attr2 .= ' '.$arreach['whole']; 774 // there are no checks 775 776 } else { 777 // there are some checks 778 $ok = true; 779 foreach ($current as $currkey => $currval) { 780 if ( ! wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval) ) { 781 $ok = false; 782 break; 783 } 784 } 785 786 if ( $ok ) 787 $attr2 .= ' '.$arreach['whole']; // it passed them 788 } // if !is_array($current) 789 } // foreach 831 } 790 832 791 833 // Remove any "<" or ">" characters … … 793 835 794 836 return "<$element$attr2$xhtml_slash>"; 837 } 838 839 /** 840 * Determine whether an attribute is allowed. 841 * 842 * @since 4.2.3 843 * 844 * @param string $name The attribute name. Returns empty string when not allowed. 845 * @param string $value The attribute value. Returns a filtered value. 846 * @param string $whole The name=value input. Returns filtered input. 847 * @param string $vless 'y' when attribute like "enabled", otherwise 'n'. 848 * @param string $element The name of the element to which this attribute belongs. 849 * @param array $allowed_html The full list of allowed elements and attributes. 850 * @return bool Is the attribute allowed? 851 */ 852 function wp_kses_attr_check( &$name, &$value, &$whole, $vless, $element, $allowed_html ) { 853 $allowed_attr = $allowed_html[strtolower( $element )]; 854 855 $name_low = strtolower( $name ); 856 if ( ! isset( $allowed_attr[$name_low] ) || '' == $allowed_attr[$name_low] ) { 857 $name = $value = $whole = ''; 858 return false; 859 } 860 861 if ( 'style' == $name_low ) { 862 $new_value = safecss_filter_attr( $value ); 863 864 if ( empty( $new_value ) ) { 865 $name = $value = $whole = ''; 866 return false; 867 } 868 869 $whole = str_replace( $value, $new_value, $whole ); 870 $value = $new_value; 871 } 872 873 if ( is_array( $allowed_attr[$name_low] ) ) { 874 // there are some checks 875 foreach ( $allowed_attr[$name_low] as $currkey => $currval ) { 876 if ( ! wp_kses_check_attr_val( $value, $vless, $currkey, $currval ) ) { 877 $name = $value = $whole = ''; 878 return false; 879 } 880 } 881 } 882 883 return true; 795 884 } 796 885 … … 922 1011 923 1012 return $attrarr; 1013 } 1014 1015 /** 1016 * Finds all attributes of an HTML element. 1017 * 1018 * Does not modify input. May return "evil" output. 1019 * 1020 * Based on wp_kses_split2() and wp_kses_attr() 1021 * 1022 * @since 4.2.3 1023 * 1024 * @param string $element HTML element/tag 1025 * @return array|bool List of attributes found in $element. Returns false on failure. 1026 */ 1027 function wp_kses_attr_parse( $element ) { 1028 $valid = preg_match('%^(<\s*)(/\s*)?([a-zA-Z0-9]+\s*)([^>]*)(>?)$%', $element, $matches); 1029 if ( 1 !== $valid ) { 1030 return false; 1031 } 1032 1033 $begin = $matches[1]; 1034 $slash = $matches[2]; 1035 $elname = $matches[3]; 1036 $attr = $matches[4]; 1037 $end = $matches[5]; 1038 1039 if ( '' !== $slash ) { 1040 // Closing elements do not get parsed. 1041 return false; 1042 } 1043 1044 // Is there a closing XHTML slash at the end of the attributes? 1045 if ( 1 === preg_match( '%\s*/\s*$%', $attr, $matches ) ) { 1046 $xhtml_slash = $matches[0]; 1047 $attr = substr( $attr, 0, -strlen( $xhtml_slash ) ); 1048 } else { 1049 $xhtml_slash = ''; 1050 } 1051 1052 // Split it 1053 $attrarr = wp_kses_hair_parse( $attr ); 1054 if ( false === $attrarr ) { 1055 return false; 1056 } 1057 1058 // Make sure all input is returned by adding front and back matter. 1059 array_unshift( $attrarr, $begin . $slash . $elname ); 1060 array_push( $attrarr, $xhtml_slash . $end ); 1061 1062 return $attrarr; 1063 } 1064 1065 /** 1066 * Builds an attribute list from string containing attributes. 1067 * 1068 * Does not modify input. May return "evil" output. 1069 * In case of unexpected input, returns false instead of stripping things. 1070 * 1071 * Based on wp_kses_hair() but does not return a multi-dimensional array. 1072 * 1073 * @since 4.2.3 1074 * 1075 * @param string $attr Attribute list from HTML element to closing HTML element tag 1076 * @return array|bool List of attributes found in $attr. Returns false on failure. 1077 */ 1078 function wp_kses_hair_parse( $attr ) { 1079 if ( '' === $attr ) { 1080 return array(); 1081 } 1082 1083 $regex = 1084 '(?:' 1085 . '[-a-zA-Z:]+' // Attribute name. 1086 . '|' 1087 . '\[\[?[^\[\]]+\]\]?' // Shortcode in the name position implies unfiltered_html. 1088 . ')' 1089 . '(?:' // Attribute value. 1090 . '\s*=\s*' // All values begin with '=' 1091 . '(?:' 1092 . '"[^"]*"' // Double-quoted 1093 . '|' 1094 . "'[^']*'" // Single-quoted 1095 . '|' 1096 . '[^\s"\']+' // Non-quoted 1097 . '(?:\s|$)' // Must have a space 1098 . ')' 1099 . '|' 1100 . '(?:\s|$)' // If attribute has no value, space is required. 1101 . ')' 1102 . '\s*'; // Trailing space is optional except as mentioned above. 1103 1104 // Although it is possible to reduce this procedure to a single regexp, 1105 // we must run that regexp twice to get exactly the expected result. 1106 1107 $validation = "%^($regex)+$%"; 1108 $extraction = "%$regex%"; 1109 1110 if ( 1 === preg_match( $validation, $attr ) ) { 1111 preg_match_all( $extraction, $attr, $attrarr ); 1112 return $attrarr[0]; 1113 } else { 1114 return false; 1115 } 924 1116 } 925 1117
Note: See TracChangeset
for help on using the changeset viewer.