WordPress.org

Make WordPress Core

Ticket #29717: 29717.4.patch

File 29717.4.patch, 5.0 KB (added by askapache, 5 years ago)

29717.4.patch - kitchin2

  • formatting.php

     
    695695/**
    696696 * Checks for invalid UTF8 in a string.
    697697 *
     698 * Could change the ini_setting mbstring.substitute_character to 'none' without restoring.
     699 *
    698700 * @since 2.8.0
    699701 *
    700702 * @param string $string The text which is to be checked.
    701703 * @param boolean $strip Optional. Whether to attempt to strip out invalid UTF8. Default is false.
    702  * @return string The checked text.
     704 * @return string If the string is valid UTF-8 or the blog_charset is not UTF-8, the string is returned unmodified. Otherwise, an empty string is returned, or optionally the string stripped of invalid chars.
    703705 */
    704706function wp_check_invalid_utf8( $string, $strip = false ) {
    705707        $string = (string) $string;
    706708
    707         if ( 0 === strlen( $string ) ) {
     709        // if string length is 0 (faster than strlen) return empty
     710        if ( ! isset( $string[0] ) ) {
    708711                return '';
    709712        }
    710713
    711         // Store the site charset as a static to avoid multiple calls to get_option()
     714        // Store the site charset
    712715        static $is_utf8;
    713         if ( !isset( $is_utf8 ) ) {
    714                 $is_utf8 = in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) );
     716
     717        // if first time this function is called, save boolean if utf-8 enabled or not static
     718        if ( ! isset( $is_utf8 ) ) {
     719                $is_utf8 = ( in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) );
    715720        }
    716         if ( !$is_utf8 ) {
     721
     722        // if utf not used return the string
     723        if ( ! $is_utf8 ) {
    717724                return $string;
    718725        }
    719726
     727        // Whether pcre is enabled, and whether pcre needs to use the (*UTF8) trick
     728        static $pcre_utf8;
     729
    720730        // Check for support for utf8 in the installed PCRE library once and store the result in a static
    721         static $utf8_pcre;
    722         if ( !isset( $utf8_pcre ) ) {
    723                 $utf8_pcre = @preg_match( '/^./u', 'a' );
     731        if ( ! isset( $pcre_utf8 ) ) {
     732                $pcre_utf8 = ( @preg_match( '//u', '' ) !== false );
    724733        }
    725         // We can't demand utf8 in the PCRE installation, so just return the string in those cases
    726         if ( !$utf8_pcre ) {
     734
     735        // If pcre_utf /u modifier allowed and the utf is valid, return string
     736        if ( $pcre_utf8 && @preg_match( '//u', $string ) !== false ) {
    727737                return $string;
    728738        }
    729739
    730         // preg_match fails when it encounters invalid UTF8 in $string
    731         if ( 1 === @preg_match( '/^./us', $string ) ) {
    732                 return $string;
     740        // just means that the /u modifier is disallowed, so try the pattern option
     741        if ( ! $pcre_utf8 ) {
     742
     743                // Use the pattern option for pcre and return string if valid.  Else use the regex
     744                if ( @preg_match( '/(*UTF8)/', $string ) !== false ) {
     745                        return $string;
     746                } else {
     747
     748                        // pcre was compiled explicitly to forbid the support of UTF.  So use a regex to check (third times the charm)
     749                        $pattern = '/(
     750                                [\xC0-\xC1] # Invalid UTF-8 Bytes
     751                                | [\xF5-\xFF] # Invalid UTF-8 Bytes
     752                                | \xE0[\x80-\x9F] # Overlong encoding of prior code point
     753                                | \xF0[\x80-\x8F] # Overlong encoding of prior code point
     754                                | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
     755                                | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
     756                                | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
     757                                | (?<=[\x0-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
     758                                | (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]|[\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence
     759                                | (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
     760                                | (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
     761                                | (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
     762                        )/x';
     763
     764                        // if the utf is valid return the string
     765                        if ( @preg_match( $pattern , $string ) === 1 ) {
     766                                return $string;
     767                        }
     768                }
    733769        }
    734770
    735771        // Attempt to strip the bad chars if requested (not recommended)
    736         if ( $strip && function_exists( 'iconv' ) ) {
    737                 return iconv( 'utf-8', 'utf-8', $string );
     772        if ( $strip ) {
     773                // Whether inconv is available
     774                static $iconv;
     775
     776                // Check once for support for iconv and save statically, if not set the mbstring.substitute_character ini
     777                if ( ! isset( $iconv ) ) {
     778                        $iconv = function_exists( 'iconv' );
     779
     780                        if ( ! $iconv ) {
     781                                // only create a static var if $iconv is not available since only then will the final if ( $mb_convert ) check utilize this var
     782                                static $mb_convert;
     783
     784                                // if mb_convert_encoding is available, set the ini_setting once                       
     785                                @ini_set( 'mbstring.substitute_character', 'none' );
     786                                $mb_convert = ( function_exists( 'mb_convert_encoding' ) && @ini_get( 'mbstring.substitute_character' ) === 'none' );
     787                        }
     788                }
     789
     790                // use iconv if exists
     791                if ( $iconv ) {
     792                        return @iconv( 'utf-8', 'utf-8//ignore', $string );
     793                }
     794
     795                // otherwise try to use mb_convert_encoding, setting the substitue_character to none to mimic strip
     796                if ( $mb_convert ) {
     797                        return @mb_convert_encoding( $string, 'utf-8', 'utf-8' );
     798                }
    738799        }
    739800
     801        // default to returning empty string, meaning invalid utf was found
    740802        return '';
    741803}
    742804