~canonical-sysadmins/wordpress/4.2

« back to all changes in this revision

Viewing changes to wp-includes/kses.php

  • Committer: Paul Gear
  • Date: 2015-04-24 01:35:20 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: paul.gear@canonical.com-20150424013520-w4p9ksth76zh6opw
Merge new upstream release 4.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
441
441
                'q' => array(
442
442
                        'cite' => true,
443
443
                ),
 
444
                's' => array(),
444
445
                'strike' => array(),
445
446
                'strong' => array(),
446
447
        );
556
557
                case 'post':
557
558
                        /** This filter is documented in wp-includes/kses.php */
558
559
                        return apply_filters( 'wp_kses_allowed_html', $allowedposttags, $context );
559
 
                        break;
 
560
 
560
561
                case 'user_description':
561
562
                case 'pre_user_description':
562
563
                        $tags = $allowedtags;
563
564
                        $tags['a']['rel'] = true;
564
565
                        /** This filter is documented in wp-includes/kses.php */
565
566
                        return apply_filters( 'wp_kses_allowed_html', $tags, $context );
566
 
                        break;
 
567
 
567
568
                case 'strip':
568
569
                        /** This filter is documented in wp-includes/kses.php */
569
570
                        return apply_filters( 'wp_kses_allowed_html', array(), $context );
570
 
                        break;
 
571
 
571
572
                case 'entities':
572
573
                        /** This filter is documented in wp-includes/kses.php */
573
574
                        return apply_filters( 'wp_kses_allowed_html', $allowedentitynames, $context);
574
 
                        break;
 
575
 
575
576
                case 'data':
576
577
                default:
577
578
                        /** This filter is documented in wp-includes/kses.php */
672
673
 
673
674
        if (substr($string, 0, 1) != '<')
674
675
                return '&gt;';
675
 
        # It matched a ">" character
 
676
        // It matched a ">" character
676
677
 
677
678
        if ( '<!--' == substr( $string, 0, 4 ) ) {
678
679
                $string = str_replace( array('<!--', '-->'), '', $string );
686
687
                $string = preg_replace('/-$/', '', $string);
687
688
                return "<!--{$string}-->";
688
689
        }
689
 
        # Allow HTML comments
 
690
        // Allow HTML comments
690
691
 
691
692
        if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches))
692
693
                return '';
693
 
        # It's seriously malformed
 
694
        // It's seriously malformed
694
695
 
695
696
        $slash = trim($matches[1]);
696
697
        $elem = $matches[2];
701
702
 
702
703
        if ( ! isset($allowed_html[strtolower($elem)]) )
703
704
                return '';
704
 
        # They are using a not allowed HTML element
 
705
        // They are using a not allowed HTML element
705
706
 
706
707
        if ($slash != '')
707
708
                return "</$elem>";
708
 
        # No attributes are allowed for closing elements
 
709
        // No attributes are allowed for closing elements
709
710
 
710
711
        return wp_kses_attr( $elem, $attrlist, $allowed_html, $allowed_protocols );
711
712
}
728
729
 * @return string Sanitized HTML element
729
730
 */
730
731
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols) {
731
 
        # Is there a closing XHTML slash at the end of the attributes?
 
732
        // Is there a closing XHTML slash at the end of the attributes?
732
733
 
733
734
        if ( ! is_array( $allowed_html ) )
734
735
                $allowed_html = wp_kses_allowed_html( $allowed_html );
737
738
        if (preg_match('%\s*/\s*$%', $attr))
738
739
                $xhtml_slash = ' /';
739
740
 
740
 
        # Are any attributes allowed at all for this element?
 
741
        // Are any attributes allowed at all for this element?
741
742
        if ( ! isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0 )
742
743
                return "<$element$xhtml_slash>";
743
744
 
744
 
        # Split it
 
745
        // Split it
745
746
        $attrarr = wp_kses_hair($attr, $allowed_protocols);
746
747
 
747
 
        # Go through $attrarr, and save the allowed attributes for this element
748
 
        # in $attr2
 
748
        // Go through $attrarr, and save the allowed attributes for this element
 
749
        // in $attr2
749
750
        $attr2 = '';
750
751
 
751
752
        $allowed_attr = $allowed_html[strtolower($element)];
752
753
        foreach ($attrarr as $arreach) {
753
754
                if ( ! isset( $allowed_attr[strtolower($arreach['name'])] ) )
754
 
                        continue; # the attribute is not allowed
 
755
                        continue; // the attribute is not allowed
755
756
 
756
757
                $current = $allowed_attr[strtolower($arreach['name'])];
757
758
                if ( $current == '' )
758
 
                        continue; # the attribute is not allowed
 
759
                        continue; // the attribute is not allowed
759
760
 
760
761
                if ( strtolower( $arreach['name'] ) == 'style' ) {
761
762
                        $orig_value = $arreach['value'];
770
771
 
771
772
                if ( ! is_array($current) ) {
772
773
                        $attr2 .= ' '.$arreach['whole'];
773
 
                # there are no checks
 
774
                // there are no checks
774
775
 
775
776
                } else {
776
 
                        # there are some checks
 
777
                        // there are some checks
777
778
                        $ok = true;
778
779
                        foreach ($current as $currkey => $currval) {
779
780
                                if ( ! wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval) ) {
783
784
                        }
784
785
 
785
786
                        if ( $ok )
786
 
                                $attr2 .= ' '.$arreach['whole']; # it passed them
787
 
                } # if !is_array($current)
788
 
        } # foreach
 
787
                                $attr2 .= ' '.$arreach['whole']; // it passed them
 
788
                } // if !is_array($current)
 
789
        } // foreach
789
790
 
790
 
        # Remove any "<" or ">" characters
 
791
        // Remove any "<" or ">" characters
791
792
        $attr2 = preg_replace('/[<>]/', '', $attr2);
792
793
 
793
794
        return "<$element$attr2$xhtml_slash>";
816
817
        $attrname = '';
817
818
        $uris = array('xmlns', 'profile', 'href', 'src', 'cite', 'classid', 'codebase', 'data', 'usemap', 'longdesc', 'action');
818
819
 
819
 
        # Loop through the whole attribute list
 
820
        // Loop through the whole attribute list
820
821
 
821
822
        while (strlen($attr) != 0) {
822
 
                $working = 0; # Was the last operation successful?
 
823
                $working = 0; // Was the last operation successful?
823
824
 
824
825
                switch ($mode) {
825
 
                        case 0 : # attribute name, href for instance
 
826
                        case 0 : // attribute name, href for instance
826
827
 
827
828
                                if ( preg_match('/^([-a-zA-Z:]+)/', $attr, $match ) ) {
828
829
                                        $attrname = $match[1];
832
833
 
833
834
                                break;
834
835
 
835
 
                        case 1 : # equals sign or valueless ("selected")
 
836
                        case 1 : // equals sign or valueless ("selected")
836
837
 
837
 
                                if (preg_match('/^\s*=\s*/', $attr)) # equals sign
 
838
                                if (preg_match('/^\s*=\s*/', $attr)) // equals sign
838
839
                                        {
839
840
                                        $working = 1;
840
841
                                        $mode = 2;
842
843
                                        break;
843
844
                                }
844
845
 
845
 
                                if (preg_match('/^\s+/', $attr)) # valueless
 
846
                                if (preg_match('/^\s+/', $attr)) // valueless
846
847
                                        {
847
848
                                        $working = 1;
848
849
                                        $mode = 0;
854
855
 
855
856
                                break;
856
857
 
857
 
                        case 2 : # attribute value, a URL after href= for instance
 
858
                        case 2 : // attribute value, a URL after href= for instance
858
859
 
859
860
                                if (preg_match('%^"([^"]*)"(\s+|/?$)%', $attr, $match))
860
 
                                        # "value"
 
861
                                        // "value"
861
862
                                        {
862
863
                                        $thisval = $match[1];
863
864
                                        if ( in_array(strtolower($attrname), $uris) )
873
874
                                }
874
875
 
875
876
                                if (preg_match("%^'([^']*)'(\s+|/?$)%", $attr, $match))
876
 
                                        # 'value'
 
877
                                        // 'value'
877
878
                                        {
878
879
                                        $thisval = $match[1];
879
880
                                        if ( in_array(strtolower($attrname), $uris) )
889
890
                                }
890
891
 
891
892
                                if (preg_match("%^([^\s\"']+)(\s+|/?$)%", $attr, $match))
892
 
                                        # value
 
893
                                        // value
893
894
                                        {
894
895
                                        $thisval = $match[1];
895
896
                                        if ( in_array(strtolower($attrname), $uris) )
898
899
                                        if(false === array_key_exists($attrname, $attrarr)) {
899
900
                                                $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
900
901
                                        }
901
 
                                        # We add quotes to conform to W3C's HTML spec.
 
902
                                        // We add quotes to conform to W3C's HTML spec.
902
903
                                        $working = 1;
903
904
                                        $mode = 0;
904
905
                                        $attr = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr);
905
906
                                }
906
907
 
907
908
                                break;
908
 
                } # switch
 
909
                } // switch
909
910
 
910
 
                if ($working == 0) # not well formed, remove and try again
 
911
                if ($working == 0) // not well formed, remove and try again
911
912
                {
912
913
                        $attr = wp_kses_html_error($attr);
913
914
                        $mode = 0;
914
915
                }
915
 
        } # while
 
916
        } // while
916
917
 
917
918
        if ($mode == 1 && false === array_key_exists($attrname, $attrarr))
918
 
                # special case, for when the attribute list ends with a valueless
919
 
                # attribute like "selected"
 
919
                // special case, for when the attribute list ends with a valueless
 
920
                // attribute like "selected"
920
921
                $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
921
922
 
922
923
        return $attrarr;
941
942
 
942
943
        switch (strtolower($checkname)) {
943
944
                case 'maxlen' :
944
 
                        # The maxlen check makes sure that the attribute value has a length not
945
 
                        # greater than the given value. This can be used to avoid Buffer Overflows
946
 
                        # in WWW clients and various Internet servers.
 
945
                        // The maxlen check makes sure that the attribute value has a length not
 
946
                        // greater than the given value. This can be used to avoid Buffer Overflows
 
947
                        // in WWW clients and various Internet servers.
947
948
 
948
949
                        if (strlen($value) > $checkvalue)
949
950
                                $ok = false;
950
951
                        break;
951
952
 
952
953
                case 'minlen' :
953
 
                        # The minlen check makes sure that the attribute value has a length not
954
 
                        # smaller than the given value.
 
954
                        // The minlen check makes sure that the attribute value has a length not
 
955
                        // smaller than the given value.
955
956
 
956
957
                        if (strlen($value) < $checkvalue)
957
958
                                $ok = false;
958
959
                        break;
959
960
 
960
961
                case 'maxval' :
961
 
                        # The maxval check does two things: it checks that the attribute value is
962
 
                        # an integer from 0 and up, without an excessive amount of zeroes or
963
 
                        # whitespace (to avoid Buffer Overflows). It also checks that the attribute
964
 
                        # value is not greater than the given value.
965
 
                        # This check can be used to avoid Denial of Service attacks.
 
962
                        // The maxval check does two things: it checks that the attribute value is
 
963
                        // an integer from 0 and up, without an excessive amount of zeroes or
 
964
                        // whitespace (to avoid Buffer Overflows). It also checks that the attribute
 
965
                        // value is not greater than the given value.
 
966
                        // This check can be used to avoid Denial of Service attacks.
966
967
 
967
968
                        if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
968
969
                                $ok = false;
971
972
                        break;
972
973
 
973
974
                case 'minval' :
974
 
                        # The minval check makes sure that the attribute value is a positive integer,
975
 
                        # and that it is not smaller than the given value.
 
975
                        // The minval check makes sure that the attribute value is a positive integer,
 
976
                        // and that it is not smaller than the given value.
976
977
 
977
978
                        if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
978
979
                                $ok = false;
981
982
                        break;
982
983
 
983
984
                case 'valueless' :
984
 
                        # The valueless check makes sure if the attribute has a value
985
 
                        # (like <a href="blah">) or not (<option selected>). If the given value
986
 
                        # is a "y" or a "Y", the attribute must not have a value.
987
 
                        # If the given value is an "n" or an "N", the attribute must have one.
 
985
                        // The valueless check makes sure if the attribute has a value
 
986
                        // (like <a href="blah">) or not (<option selected>). If the given value
 
987
                        // is a "y" or a "Y", the attribute must not have a value.
 
988
                        // If the given value is an "n" or an "N", the attribute must have one.
988
989
 
989
990
                        if (strtolower($checkvalue) != $vless)
990
991
                                $ok = false;
991
992
                        break;
992
 
        } # switch
 
993
        } // switch
993
994
 
994
995
        return $ok;
995
996
}
1074
1075
                foreach ( (array) $inval as $inkey2 => $inval2) {
1075
1076
                        $outkey2 = strtolower($inkey2);
1076
1077
                        $outarray[$outkey][$outkey2] = $inval2;
1077
 
                } # foreach $inval
1078
 
        } # foreach $inarray
 
1078
                } // foreach $inval
 
1079
        } // foreach $inarray
1079
1080
 
1080
1081
        return $outarray;
1081
1082
}
1181
1182
 * @return string Content with normalized entities
1182
1183
 */
1183
1184
function wp_kses_normalize_entities($string) {
1184
 
        # Disarm all entities by converting & to &amp;
 
1185
        // Disarm all entities by converting & to &amp;
1185
1186
 
1186
1187
        $string = str_replace('&', '&amp;', $string);
1187
1188
 
1188
 
        # Change back the allowed entities in our entity whitelist
 
1189
        // Change back the allowed entities in our entity whitelist
1189
1190
 
1190
1191
        $string = preg_replace_callback('/&amp;([A-Za-z]{2,8}[0-9]{0,2});/', 'wp_kses_named_entities', $string);
1191
1192
        $string = preg_replace_callback('/&amp;#(0*[0-9]{1,7});/', 'wp_kses_normalize_entities2', $string);
1452
1453
                kses_init_filters();
1453
1454
}
1454
1455
 
1455
 
add_action('init', 'kses_init');
1456
 
add_action('set_current_user', 'kses_init');
1457
 
 
1458
1456
/**
1459
1457
 * Inline CSS filter
1460
1458
 *