+
+ // Don't bother if there are no specialchars - saves some processing
+ if ( !preg_match( '/[&<>"\']/', $string ) ) {
+ return $string;
+ }
+
+ // Account for the previous behaviour of the function when the $quote_style is not an accepted value
+ if ( empty( $quote_style ) ) {
+ $quote_style = ENT_NOQUOTES;
+ } elseif ( !in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) {
+ $quote_style = ENT_QUOTES;
+ }
+
+ // Store the site charset as a static to avoid multiple calls to wp_load_alloptions()
+ if ( !$charset ) {
+ static $_charset;
+ if ( !isset( $_charset ) ) {
+ $alloptions = wp_load_alloptions();
+ $_charset = isset( $alloptions['blog_charset'] ) ? $alloptions['blog_charset'] : '';
+ }
+ $charset = $_charset;
+ }
+ if ( in_array( $charset, array( 'utf8', 'utf-8', 'UTF8' ) ) ) {
+ $charset = 'UTF-8';
+ }
+
+ $_quote_style = $quote_style;
+
+ if ( $quote_style === 'double' ) {
+ $quote_style = ENT_COMPAT;
+ $_quote_style = ENT_COMPAT;
+ } elseif ( $quote_style === 'single' ) {
+ $quote_style = ENT_NOQUOTES;
+ }
+
+ // Handle double encoding ourselves
+ if ( !$double_encode ) {
+ $string = wp_specialchars_decode( $string, $_quote_style );
+ $string = preg_replace( '/&(#?x?[0-9a-z]+);/i', '|wp_entity|$1|/wp_entity|', $string );
+ }
+
+ $string = @htmlspecialchars( $string, $quote_style, $charset );
+
+ // Handle double encoding ourselves
+ if ( !$double_encode ) {
+ $string = str_replace( array( '|wp_entity|', '|/wp_entity|' ), array( '&', ';' ), $string );
+ }
+
+ // Backwards compatibility
+ if ( 'single' === $_quote_style ) {
+ $string = str_replace( "'", ''', $string );
+ }
+
+ return $string;
+}
+
+/**
+ * Converts a number of HTML entities into their special characters.
+ *
+ * Specifically deals with: &, <, >, ", and '.
+ *
+ * $quote_style can be set to ENT_COMPAT to decode " entities,
+ * or ENT_QUOTES to do both " and '. Default is ENT_NOQUOTES where no quotes are decoded.
+ *
+ * @since 2.8
+ *
+ * @param string $string The text which is to be decoded.
+ * @param mixed $quote_style Optional. Converts double quotes if set to ENT_COMPAT, both single and double if set to ENT_QUOTES or none if set to ENT_NOQUOTES. Also compatible with old _wp_specialchars() values; converting single quotes if set to 'single', double if set to 'double' or both if otherwise set. Default is ENT_NOQUOTES.
+ * @return string The decoded text without HTML entities.
+ */
+function wp_specialchars_decode( $string, $quote_style = ENT_NOQUOTES ) {
+ $string = (string) $string;
+
+ if ( 0 === strlen( $string ) ) {
+ return '';
+ }
+
+ // Don't bother if there are no entities - saves a lot of processing
+ if ( strpos( $string, '&' ) === false ) {
+ return $string;
+ }
+
+ // Match the previous behaviour of _wp_specialchars() when the $quote_style is not an accepted value
+ if ( empty( $quote_style ) ) {
+ $quote_style = ENT_NOQUOTES;
+ } elseif ( !in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) {
+ $quote_style = ENT_QUOTES;
+ }
+
+ // More complete than get_html_translation_table( HTML_SPECIALCHARS )
+ $single = array( ''' => '\'', ''' => '\'' );
+ $single_preg = array( '/�*39;/' => ''', '/�*27;/i' => ''' );
+ $double = array( '"' => '"', '"' => '"', '"' => '"' );
+ $double_preg = array( '/�*34;/' => '"', '/�*22;/i' => '"' );
+ $others = array( '<' => '<', '<' => '<', '>' => '>', '>' => '>', '&' => '&', '&' => '&', '&' => '&' );
+ $others_preg = array( '/�*60;/' => '<', '/�*62;/' => '>', '/�*38;/' => '&', '/�*26;/i' => '&' );
+
+ if ( $quote_style === ENT_QUOTES ) {
+ $translation = array_merge( $single, $double, $others );
+ $translation_preg = array_merge( $single_preg, $double_preg, $others_preg );
+ } elseif ( $quote_style === ENT_COMPAT || $quote_style === 'double' ) {
+ $translation = array_merge( $double, $others );
+ $translation_preg = array_merge( $double_preg, $others_preg );
+ } elseif ( $quote_style === 'single' ) {
+ $translation = array_merge( $single, $others );
+ $translation_preg = array_merge( $single_preg, $others_preg );
+ } elseif ( $quote_style === ENT_NOQUOTES ) {
+ $translation = $others;
+ $translation_preg = $others_preg;
+ }
+
+ // Remove zero padding on numeric entities
+ $string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string );
+
+ // Replace characters according to translation table
+ return strtr( $string, $translation );
+}
+
+/**
+ * Checks for invalid UTF8 in a string.
+ *
+ * @since 2.8
+ *
+ * @param string $string The text which is to be checked.
+ * @param boolean $strip Optional. Whether to attempt to strip out invalid UTF8. Default is false.
+ * @return string The checked text.
+ */
+function wp_check_invalid_utf8( $string, $strip = false ) {
+ $string = (string) $string;
+
+ if ( 0 === strlen( $string ) ) {
+ return '';
+ }
+
+ // Store the site charset as a static to avoid multiple calls to get_option()
+ static $is_utf8;
+ if ( !isset( $is_utf8 ) ) {
+ $is_utf8 = in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) );
+ }
+ if ( !$is_utf8 ) {
+ return $string;
+ }
+
+ // Check for support for utf8 in the installed PCRE library once and store the result in a static
+ static $utf8_pcre;
+ if ( !isset( $utf8_pcre ) ) {
+ $utf8_pcre = @preg_match( '/^./u', 'a' );
+ }
+ // We can't demand utf8 in the PCRE installation, so just return the string in those cases
+ if ( !$utf8_pcre ) {
+ return $string;
+ }
+
+ // preg_match fails when it encounters invalid UTF8 in $string
+ if ( 1 === @preg_match( '/^./us', $string ) ) {
+ return $string;
+ }
+
+ // Attempt to strip the bad chars if requested (not recommended)
+ if ( $strip && function_exists( 'iconv' ) ) {
+ return iconv( 'utf-8', 'utf-8', $string );
+ }
+
+ return '';