wp/wp-includes/formatting.php
changeset 0 d970ebf37754
child 5 5e2f62d02dcd
equal deleted inserted replaced
-1:000000000000 0:d970ebf37754
       
     1 <?php
       
     2 /**
       
     3  * Main WordPress Formatting API.
       
     4  *
       
     5  * Handles many functions for formatting output.
       
     6  *
       
     7  * @package WordPress
       
     8  */
       
     9 
       
    10 /**
       
    11  * Replaces common plain text characters into formatted entities
       
    12  *
       
    13  * As an example,
       
    14  * <code>
       
    15  * 'cause today's effort makes it worth tomorrow's "holiday"...
       
    16  * </code>
       
    17  * Becomes:
       
    18  * <code>
       
    19  * &#8217;cause today&#8217;s effort makes it worth tomorrow&#8217;s &#8220;holiday&#8221;&#8230;
       
    20  * </code>
       
    21  * Code within certain html blocks are skipped.
       
    22  *
       
    23  * @since 0.71
       
    24  * @uses $wp_cockneyreplace Array of formatted entities for certain common phrases
       
    25  *
       
    26  * @param string $text The text to be formatted
       
    27  * @return string The string replaced with html entities
       
    28  */
       
    29 function wptexturize($text) {
       
    30 	global $wp_cockneyreplace;
       
    31 	static $static_characters, $static_replacements, $dynamic_characters, $dynamic_replacements,
       
    32 		$default_no_texturize_tags, $default_no_texturize_shortcodes;
       
    33 
       
    34 	// No need to set up these static variables more than once
       
    35 	if ( ! isset( $static_characters ) ) {
       
    36 		/* translators: opening curly double quote */
       
    37 		$opening_quote = _x( '&#8220;', 'opening curly double quote' );
       
    38 		/* translators: closing curly double quote */
       
    39 		$closing_quote = _x( '&#8221;', 'closing curly double quote' );
       
    40 
       
    41 		/* translators: apostrophe, for example in 'cause or can't */
       
    42 		$apos = _x( '&#8217;', 'apostrophe' );
       
    43 
       
    44 		/* translators: prime, for example in 9' (nine feet) */
       
    45 		$prime = _x( '&#8242;', 'prime' );
       
    46 		/* translators: double prime, for example in 9" (nine inches) */
       
    47 		$double_prime = _x( '&#8243;', 'double prime' );
       
    48 
       
    49 		/* translators: opening curly single quote */
       
    50 		$opening_single_quote = _x( '&#8216;', 'opening curly single quote' );
       
    51 		/* translators: closing curly single quote */
       
    52 		$closing_single_quote = _x( '&#8217;', 'closing curly single quote' );
       
    53 
       
    54 		/* translators: en dash */
       
    55 		$en_dash = _x( '&#8211;', 'en dash' );
       
    56 		/* translators: em dash */
       
    57 		$em_dash = _x( '&#8212;', 'em dash' );
       
    58 
       
    59 		$default_no_texturize_tags = array('pre', 'code', 'kbd', 'style', 'script', 'tt');
       
    60 		$default_no_texturize_shortcodes = array('code');
       
    61 
       
    62 		// if a plugin has provided an autocorrect array, use it
       
    63 		if ( isset($wp_cockneyreplace) ) {
       
    64 			$cockney = array_keys($wp_cockneyreplace);
       
    65 			$cockneyreplace = array_values($wp_cockneyreplace);
       
    66 		} elseif ( "'" != $apos ) { // Only bother if we're doing a replacement.
       
    67 			$cockney = array( "'tain't", "'twere", "'twas", "'tis", "'twill", "'til", "'bout", "'nuff", "'round", "'cause" );
       
    68 			$cockneyreplace = array( $apos . "tain" . $apos . "t", $apos . "twere", $apos . "twas", $apos . "tis", $apos . "twill", $apos . "til", $apos . "bout", $apos . "nuff", $apos . "round", $apos . "cause" );
       
    69 		} else {
       
    70 			$cockney = $cockneyreplace = array();
       
    71 		}
       
    72 
       
    73 		$static_characters = array_merge( array( '---', ' -- ', '--', ' - ', 'xn&#8211;', '...', '``', '\'\'', ' (tm)' ), $cockney );
       
    74 		$static_replacements = array_merge( array( $em_dash, ' ' . $em_dash . ' ', $en_dash, ' ' . $en_dash . ' ', 'xn--', '&#8230;', $opening_quote, $closing_quote, ' &#8482;' ), $cockneyreplace );
       
    75 
       
    76 		$dynamic = array();
       
    77 		if ( "'" != $apos ) {
       
    78 			$dynamic[ '/\'(\d\d(?:&#8217;|\')?s)/' ] = $apos . '$1'; // '99's
       
    79 			$dynamic[ '/\'(\d)/'                   ] = $apos . '$1'; // '99
       
    80 		}
       
    81 		if ( "'" != $opening_single_quote )
       
    82 			$dynamic[ '/(\s|\A|[([{<]|")\'/'       ] = '$1' . $opening_single_quote; // opening single quote, even after (, {, <, [
       
    83 		if ( '"' != $double_prime )
       
    84 			$dynamic[ '/(\d)"/'                    ] = '$1' . $double_prime; // 9" (double prime)
       
    85 		if ( "'" != $prime )
       
    86 			$dynamic[ '/(\d)\'/'                   ] = '$1' . $prime; // 9' (prime)
       
    87 		if ( "'" != $apos )
       
    88 			$dynamic[ '/(\S)\'([^\'\s])/'          ] = '$1' . $apos . '$2'; // apostrophe in a word
       
    89 		if ( '"' != $opening_quote )
       
    90 			$dynamic[ '/(\s|\A|[([{<])"(?!\s)/'    ] = '$1' . $opening_quote . '$2'; // opening double quote, even after (, {, <, [
       
    91 		if ( '"' != $closing_quote )
       
    92 			$dynamic[ '/"(\s|\S|\Z)/'              ] = $closing_quote . '$1'; // closing double quote
       
    93 		if ( "'" != $closing_single_quote )
       
    94 			$dynamic[ '/\'([\s.]|\Z)/'             ] = $closing_single_quote . '$1'; // closing single quote
       
    95 
       
    96 		$dynamic[ '/\b(\d+)x(\d+)\b/'              ] = '$1&#215;$2'; // 9x9 (times)
       
    97 
       
    98 		$dynamic_characters = array_keys( $dynamic );
       
    99 		$dynamic_replacements = array_values( $dynamic );
       
   100 	}
       
   101 
       
   102 	// Transform into regexp sub-expression used in _wptexturize_pushpop_element
       
   103 	// Must do this every time in case plugins use these filters in a context sensitive manner
       
   104 	$no_texturize_tags = '(' . implode('|', apply_filters('no_texturize_tags', $default_no_texturize_tags) ) . ')';
       
   105 	$no_texturize_shortcodes = '(' . implode('|', apply_filters('no_texturize_shortcodes', $default_no_texturize_shortcodes) ) . ')';
       
   106 
       
   107 	$no_texturize_tags_stack = array();
       
   108 	$no_texturize_shortcodes_stack = array();
       
   109 
       
   110 	$textarr = preg_split('/(<.*>|\[.*\])/Us', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
       
   111 
       
   112 	foreach ( $textarr as &$curl ) {
       
   113 		if ( empty( $curl ) )
       
   114 			continue;
       
   115 
       
   116 		// Only call _wptexturize_pushpop_element if first char is correct tag opening
       
   117 		$first = $curl[0];
       
   118 		if ( '<' === $first ) {
       
   119 			_wptexturize_pushpop_element($curl, $no_texturize_tags_stack, $no_texturize_tags, '<', '>');
       
   120 		} elseif ( '[' === $first ) {
       
   121 			_wptexturize_pushpop_element($curl, $no_texturize_shortcodes_stack, $no_texturize_shortcodes, '[', ']');
       
   122 		} elseif ( empty($no_texturize_shortcodes_stack) && empty($no_texturize_tags_stack) ) {
       
   123 			// This is not a tag, nor is the texturization disabled static strings
       
   124 			$curl = str_replace($static_characters, $static_replacements, $curl);
       
   125 			// regular expressions
       
   126 			$curl = preg_replace($dynamic_characters, $dynamic_replacements, $curl);
       
   127 		}
       
   128 		$curl = preg_replace('/&([^#])(?![a-zA-Z1-4]{1,8};)/', '&#038;$1', $curl);
       
   129 	}
       
   130 	return implode( '', $textarr );
       
   131 }
       
   132 
       
   133 /**
       
   134  * Search for disabled element tags. Push element to stack on tag open and pop
       
   135  * on tag close. Assumes first character of $text is tag opening.
       
   136  *
       
   137  * @since 2.9.0
       
   138  * @access private
       
   139  *
       
   140  * @param string $text Text to check. First character is assumed to be $opening
       
   141  * @param array $stack Array used as stack of opened tag elements
       
   142  * @param string $disabled_elements Tags to match against formatted as regexp sub-expression
       
   143  * @param string $opening Tag opening character, assumed to be 1 character long
       
   144  * @param string $closing Tag closing character
       
   145  */
       
   146 function _wptexturize_pushpop_element($text, &$stack, $disabled_elements, $opening = '<', $closing = '>') {
       
   147 	// Check if it is a closing tag -- otherwise assume opening tag
       
   148 	if (strncmp($opening . '/', $text, 2)) {
       
   149 		// Opening? Check $text+1 against disabled elements
       
   150 		if (preg_match('/^' . $disabled_elements . '\b/', substr($text, 1), $matches)) {
       
   151 			/*
       
   152 			 * This disables texturize until we find a closing tag of our type
       
   153 			 * (e.g. <pre>) even if there was invalid nesting before that
       
   154 			 *
       
   155 			 * Example: in the case <pre>sadsadasd</code>"baba"</pre>
       
   156 			 *          "baba" won't be texturize
       
   157 			 */
       
   158 
       
   159 			array_push($stack, $matches[1]);
       
   160 		}
       
   161 	} else {
       
   162 		// Closing? Check $text+2 against disabled elements
       
   163 		$c = preg_quote($closing, '/');
       
   164 		if (preg_match('/^' . $disabled_elements . $c . '/', substr($text, 2), $matches)) {
       
   165 			$last = array_pop($stack);
       
   166 
       
   167 			// Make sure it matches the opening tag
       
   168 			if ($last != $matches[1])
       
   169 				array_push($stack, $last);
       
   170 		}
       
   171 	}
       
   172 }
       
   173 
       
   174 /**
       
   175  * Replaces double line-breaks with paragraph elements.
       
   176  *
       
   177  * A group of regex replaces used to identify text formatted with newlines and
       
   178  * replace double line-breaks with HTML paragraph tags. The remaining
       
   179  * line-breaks after conversion become <<br />> tags, unless $br is set to '0'
       
   180  * or 'false'.
       
   181  *
       
   182  * @since 0.71
       
   183  *
       
   184  * @param string $pee The text which has to be formatted.
       
   185  * @param bool $br Optional. If set, this will convert all remaining line-breaks after paragraphing. Default true.
       
   186  * @return string Text which has been converted into correct paragraph tags.
       
   187  */
       
   188 function wpautop($pee, $br = true) {
       
   189 	$pre_tags = array();
       
   190 
       
   191 	if ( trim($pee) === '' )
       
   192 		return '';
       
   193 
       
   194 	$pee = $pee . "\n"; // just to make things a little easier, pad the end
       
   195 
       
   196 	if ( strpos($pee, '<pre') !== false ) {
       
   197 		$pee_parts = explode( '</pre>', $pee );
       
   198 		$last_pee = array_pop($pee_parts);
       
   199 		$pee = '';
       
   200 		$i = 0;
       
   201 
       
   202 		foreach ( $pee_parts as $pee_part ) {
       
   203 			$start = strpos($pee_part, '<pre');
       
   204 
       
   205 			// Malformed html?
       
   206 			if ( $start === false ) {
       
   207 				$pee .= $pee_part;
       
   208 				continue;
       
   209 			}
       
   210 
       
   211 			$name = "<pre wp-pre-tag-$i></pre>";
       
   212 			$pre_tags[$name] = substr( $pee_part, $start ) . '</pre>';
       
   213 
       
   214 			$pee .= substr( $pee_part, 0, $start ) . $name;
       
   215 			$i++;
       
   216 		}
       
   217 
       
   218 		$pee .= $last_pee;
       
   219 	}
       
   220 
       
   221 	$pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
       
   222 	// Space things out a little
       
   223 	$allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|option|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|noscript|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)';
       
   224 	$pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee);
       
   225 	$pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
       
   226 	$pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines
       
   227 	if ( strpos($pee, '<object') !== false ) {
       
   228 		$pee = preg_replace('|\s*<param([^>]*)>\s*|', "<param$1>", $pee); // no pee inside object/embed
       
   229 		$pee = preg_replace('|\s*</embed>\s*|', '</embed>', $pee);
       
   230 	}
       
   231 	$pee = preg_replace("/\n\n+/", "\n\n", $pee); // take care of duplicates
       
   232 	// make paragraphs, including one at the end
       
   233 	$pees = preg_split('/\n\s*\n/', $pee, -1, PREG_SPLIT_NO_EMPTY);
       
   234 	$pee = '';
       
   235 	foreach ( $pees as $tinkle )
       
   236 		$pee .= '<p>' . trim($tinkle, "\n") . "</p>\n";
       
   237 	$pee = preg_replace('|<p>\s*</p>|', '', $pee); // under certain strange conditions it could create a P of entirely whitespace
       
   238 	$pee = preg_replace('!<p>([^<]+)</(div|address|form)>!', "<p>$1</p></$2>", $pee);
       
   239 	$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); // don't pee all over a tag
       
   240 	$pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists
       
   241 	$pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
       
   242 	$pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
       
   243 	$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
       
   244 	$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
       
   245 	if ( $br ) {
       
   246 		$pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', '_autop_newline_preservation_helper', $pee);
       
   247 		$pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); // optionally make line breaks
       
   248 		$pee = str_replace('<WPPreserveNewline />', "\n", $pee);
       
   249 	}
       
   250 	$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
       
   251 	$pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
       
   252 	$pee = preg_replace( "|\n</p>$|", '</p>', $pee );
       
   253 
       
   254 	if ( !empty($pre_tags) )
       
   255 		$pee = str_replace(array_keys($pre_tags), array_values($pre_tags), $pee);
       
   256 
       
   257 	return $pee;
       
   258 }
       
   259 
       
   260 /**
       
   261  * Newline preservation help function for wpautop
       
   262  *
       
   263  * @since 3.1.0
       
   264  * @access private
       
   265  *
       
   266  * @param array $matches preg_replace_callback matches array
       
   267  * @return string
       
   268  */
       
   269 function _autop_newline_preservation_helper( $matches ) {
       
   270 	return str_replace("\n", "<WPPreserveNewline />", $matches[0]);
       
   271 }
       
   272 
       
   273 /**
       
   274  * Don't auto-p wrap shortcodes that stand alone
       
   275  *
       
   276  * Ensures that shortcodes are not wrapped in <<p>>...<</p>>.
       
   277  *
       
   278  * @since 2.9.0
       
   279  *
       
   280  * @param string $pee The content.
       
   281  * @return string The filtered content.
       
   282  */
       
   283 function shortcode_unautop( $pee ) {
       
   284 	global $shortcode_tags;
       
   285 
       
   286 	if ( empty( $shortcode_tags ) || !is_array( $shortcode_tags ) ) {
       
   287 		return $pee;
       
   288 	}
       
   289 
       
   290 	$tagregexp = join( '|', array_map( 'preg_quote', array_keys( $shortcode_tags ) ) );
       
   291 
       
   292 	$pattern =
       
   293 		  '/'
       
   294 		. '<p>'                              // Opening paragraph
       
   295 		. '\\s*+'                            // Optional leading whitespace
       
   296 		. '('                                // 1: The shortcode
       
   297 		.     '\\['                          // Opening bracket
       
   298 		.     "($tagregexp)"                 // 2: Shortcode name
       
   299 		.     '(?![\\w-])'                   // Not followed by word character or hyphen
       
   300 		                                     // Unroll the loop: Inside the opening shortcode tag
       
   301 		.     '[^\\]\\/]*'                   // Not a closing bracket or forward slash
       
   302 		.     '(?:'
       
   303 		.         '\\/(?!\\])'               // A forward slash not followed by a closing bracket
       
   304 		.         '[^\\]\\/]*'               // Not a closing bracket or forward slash
       
   305 		.     ')*?'
       
   306 		.     '(?:'
       
   307 		.         '\\/\\]'                   // Self closing tag and closing bracket
       
   308 		.     '|'
       
   309 		.         '\\]'                      // Closing bracket
       
   310 		.         '(?:'                      // Unroll the loop: Optionally, anything between the opening and closing shortcode tags
       
   311 		.             '[^\\[]*+'             // Not an opening bracket
       
   312 		.             '(?:'
       
   313 		.                 '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag
       
   314 		.                 '[^\\[]*+'         // Not an opening bracket
       
   315 		.             ')*+'
       
   316 		.             '\\[\\/\\2\\]'         // Closing shortcode tag
       
   317 		.         ')?'
       
   318 		.     ')'
       
   319 		. ')'
       
   320 		. '\\s*+'                            // optional trailing whitespace
       
   321 		. '<\\/p>'                           // closing paragraph
       
   322 		. '/s';
       
   323 
       
   324 	return preg_replace( $pattern, '$1', $pee );
       
   325 }
       
   326 
       
   327 /**
       
   328  * Checks to see if a string is utf8 encoded.
       
   329  *
       
   330  * NOTE: This function checks for 5-Byte sequences, UTF8
       
   331  *       has Bytes Sequences with a maximum length of 4.
       
   332  *
       
   333  * @author bmorel at ssi dot fr (modified)
       
   334  * @since 1.2.1
       
   335  *
       
   336  * @param string $str The string to be checked
       
   337  * @return bool True if $str fits a UTF-8 model, false otherwise.
       
   338  */
       
   339 function seems_utf8($str) {
       
   340 	$length = strlen($str);
       
   341 	for ($i=0; $i < $length; $i++) {
       
   342 		$c = ord($str[$i]);
       
   343 		if ($c < 0x80) $n = 0; # 0bbbbbbb
       
   344 		elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb
       
   345 		elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb
       
   346 		elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb
       
   347 		elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb
       
   348 		elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b
       
   349 		else return false; # Does not match any model
       
   350 		for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
       
   351 			if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
       
   352 				return false;
       
   353 		}
       
   354 	}
       
   355 	return true;
       
   356 }
       
   357 
       
   358 /**
       
   359  * Converts a number of special characters into their HTML entities.
       
   360  *
       
   361  * Specifically deals with: &, <, >, ", and '.
       
   362  *
       
   363  * $quote_style can be set to ENT_COMPAT to encode " to
       
   364  * &quot;, or ENT_QUOTES to do both. Default is ENT_NOQUOTES where no quotes are encoded.
       
   365  *
       
   366  * @since 1.2.2
       
   367  * @access private
       
   368  *
       
   369  * @param string $string The text which is to be encoded.
       
   370  * @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 values; converting single quotes if set to 'single', double if set to 'double' or both if otherwise set. Default is ENT_NOQUOTES.
       
   371  * @param string $charset Optional. The character encoding of the string. Default is false.
       
   372  * @param boolean $double_encode Optional. Whether to encode existing html entities. Default is false.
       
   373  * @return string The encoded text with HTML entities.
       
   374  */
       
   375 function _wp_specialchars( $string, $quote_style = ENT_NOQUOTES, $charset = false, $double_encode = false ) {
       
   376 	$string = (string) $string;
       
   377 
       
   378 	if ( 0 === strlen( $string ) )
       
   379 		return '';
       
   380 
       
   381 	// Don't bother if there are no specialchars - saves some processing
       
   382 	if ( ! preg_match( '/[&<>"\']/', $string ) )
       
   383 		return $string;
       
   384 
       
   385 	// Account for the previous behaviour of the function when the $quote_style is not an accepted value
       
   386 	if ( empty( $quote_style ) )
       
   387 		$quote_style = ENT_NOQUOTES;
       
   388 	elseif ( ! in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) )
       
   389 		$quote_style = ENT_QUOTES;
       
   390 
       
   391 	// Store the site charset as a static to avoid multiple calls to wp_load_alloptions()
       
   392 	if ( ! $charset ) {
       
   393 		static $_charset;
       
   394 		if ( ! isset( $_charset ) ) {
       
   395 			$alloptions = wp_load_alloptions();
       
   396 			$_charset = isset( $alloptions['blog_charset'] ) ? $alloptions['blog_charset'] : '';
       
   397 		}
       
   398 		$charset = $_charset;
       
   399 	}
       
   400 
       
   401 	if ( in_array( $charset, array( 'utf8', 'utf-8', 'UTF8' ) ) )
       
   402 		$charset = 'UTF-8';
       
   403 
       
   404 	$_quote_style = $quote_style;
       
   405 
       
   406 	if ( $quote_style === 'double' ) {
       
   407 		$quote_style = ENT_COMPAT;
       
   408 		$_quote_style = ENT_COMPAT;
       
   409 	} elseif ( $quote_style === 'single' ) {
       
   410 		$quote_style = ENT_NOQUOTES;
       
   411 	}
       
   412 
       
   413 	// Handle double encoding ourselves
       
   414 	if ( $double_encode ) {
       
   415 		$string = @htmlspecialchars( $string, $quote_style, $charset );
       
   416 	} else {
       
   417 		// Decode &amp; into &
       
   418 		$string = wp_specialchars_decode( $string, $_quote_style );
       
   419 
       
   420 		// Guarantee every &entity; is valid or re-encode the &
       
   421 		$string = wp_kses_normalize_entities( $string );
       
   422 
       
   423 		// Now re-encode everything except &entity;
       
   424 		$string = preg_split( '/(&#?x?[0-9a-z]+;)/i', $string, -1, PREG_SPLIT_DELIM_CAPTURE );
       
   425 
       
   426 		for ( $i = 0; $i < count( $string ); $i += 2 )
       
   427 			$string[$i] = @htmlspecialchars( $string[$i], $quote_style, $charset );
       
   428 
       
   429 		$string = implode( '', $string );
       
   430 	}
       
   431 
       
   432 	// Backwards compatibility
       
   433 	if ( 'single' === $_quote_style )
       
   434 		$string = str_replace( "'", '&#039;', $string );
       
   435 
       
   436 	return $string;
       
   437 }
       
   438 
       
   439 /**
       
   440  * Converts a number of HTML entities into their special characters.
       
   441  *
       
   442  * Specifically deals with: &, <, >, ", and '.
       
   443  *
       
   444  * $quote_style can be set to ENT_COMPAT to decode " entities,
       
   445  * or ENT_QUOTES to do both " and '. Default is ENT_NOQUOTES where no quotes are decoded.
       
   446  *
       
   447  * @since 2.8.0
       
   448  *
       
   449  * @param string $string The text which is to be decoded.
       
   450  * @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.
       
   451  * @return string The decoded text without HTML entities.
       
   452  */
       
   453 function wp_specialchars_decode( $string, $quote_style = ENT_NOQUOTES ) {
       
   454 	$string = (string) $string;
       
   455 
       
   456 	if ( 0 === strlen( $string ) ) {
       
   457 		return '';
       
   458 	}
       
   459 
       
   460 	// Don't bother if there are no entities - saves a lot of processing
       
   461 	if ( strpos( $string, '&' ) === false ) {
       
   462 		return $string;
       
   463 	}
       
   464 
       
   465 	// Match the previous behaviour of _wp_specialchars() when the $quote_style is not an accepted value
       
   466 	if ( empty( $quote_style ) ) {
       
   467 		$quote_style = ENT_NOQUOTES;
       
   468 	} elseif ( !in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) {
       
   469 		$quote_style = ENT_QUOTES;
       
   470 	}
       
   471 
       
   472 	// More complete than get_html_translation_table( HTML_SPECIALCHARS )
       
   473 	$single = array( '&#039;'  => '\'', '&#x27;' => '\'' );
       
   474 	$single_preg = array( '/&#0*39;/'  => '&#039;', '/&#x0*27;/i' => '&#x27;' );
       
   475 	$double = array( '&quot;' => '"', '&#034;'  => '"', '&#x22;' => '"' );
       
   476 	$double_preg = array( '/&#0*34;/'  => '&#034;', '/&#x0*22;/i' => '&#x22;' );
       
   477 	$others = array( '&lt;'   => '<', '&#060;'  => '<', '&gt;'   => '>', '&#062;'  => '>', '&amp;'  => '&', '&#038;'  => '&', '&#x26;' => '&' );
       
   478 	$others_preg = array( '/&#0*60;/'  => '&#060;', '/&#0*62;/'  => '&#062;', '/&#0*38;/'  => '&#038;', '/&#x0*26;/i' => '&#x26;' );
       
   479 
       
   480 	if ( $quote_style === ENT_QUOTES ) {
       
   481 		$translation = array_merge( $single, $double, $others );
       
   482 		$translation_preg = array_merge( $single_preg, $double_preg, $others_preg );
       
   483 	} elseif ( $quote_style === ENT_COMPAT || $quote_style === 'double' ) {
       
   484 		$translation = array_merge( $double, $others );
       
   485 		$translation_preg = array_merge( $double_preg, $others_preg );
       
   486 	} elseif ( $quote_style === 'single' ) {
       
   487 		$translation = array_merge( $single, $others );
       
   488 		$translation_preg = array_merge( $single_preg, $others_preg );
       
   489 	} elseif ( $quote_style === ENT_NOQUOTES ) {
       
   490 		$translation = $others;
       
   491 		$translation_preg = $others_preg;
       
   492 	}
       
   493 
       
   494 	// Remove zero padding on numeric entities
       
   495 	$string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string );
       
   496 
       
   497 	// Replace characters according to translation table
       
   498 	return strtr( $string, $translation );
       
   499 }
       
   500 
       
   501 /**
       
   502  * Checks for invalid UTF8 in a string.
       
   503  *
       
   504  * @since 2.8.0
       
   505  *
       
   506  * @param string $string The text which is to be checked.
       
   507  * @param boolean $strip Optional. Whether to attempt to strip out invalid UTF8. Default is false.
       
   508  * @return string The checked text.
       
   509  */
       
   510 function wp_check_invalid_utf8( $string, $strip = false ) {
       
   511 	$string = (string) $string;
       
   512 
       
   513 	if ( 0 === strlen( $string ) ) {
       
   514 		return '';
       
   515 	}
       
   516 
       
   517 	// Store the site charset as a static to avoid multiple calls to get_option()
       
   518 	static $is_utf8;
       
   519 	if ( !isset( $is_utf8 ) ) {
       
   520 		$is_utf8 = in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) );
       
   521 	}
       
   522 	if ( !$is_utf8 ) {
       
   523 		return $string;
       
   524 	}
       
   525 
       
   526 	// Check for support for utf8 in the installed PCRE library once and store the result in a static
       
   527 	static $utf8_pcre;
       
   528 	if ( !isset( $utf8_pcre ) ) {
       
   529 		$utf8_pcre = @preg_match( '/^./u', 'a' );
       
   530 	}
       
   531 	// We can't demand utf8 in the PCRE installation, so just return the string in those cases
       
   532 	if ( !$utf8_pcre ) {
       
   533 		return $string;
       
   534 	}
       
   535 
       
   536 	// preg_match fails when it encounters invalid UTF8 in $string
       
   537 	if ( 1 === @preg_match( '/^./us', $string ) ) {
       
   538 		return $string;
       
   539 	}
       
   540 
       
   541 	// Attempt to strip the bad chars if requested (not recommended)
       
   542 	if ( $strip && function_exists( 'iconv' ) ) {
       
   543 		return iconv( 'utf-8', 'utf-8', $string );
       
   544 	}
       
   545 
       
   546 	return '';
       
   547 }
       
   548 
       
   549 /**
       
   550  * Encode the Unicode values to be used in the URI.
       
   551  *
       
   552  * @since 1.5.0
       
   553  *
       
   554  * @param string $utf8_string
       
   555  * @param int $length Max length of the string
       
   556  * @return string String with Unicode encoded for URI.
       
   557  */
       
   558 function utf8_uri_encode( $utf8_string, $length = 0 ) {
       
   559 	$unicode = '';
       
   560 	$values = array();
       
   561 	$num_octets = 1;
       
   562 	$unicode_length = 0;
       
   563 
       
   564 	$string_length = strlen( $utf8_string );
       
   565 	for ($i = 0; $i < $string_length; $i++ ) {
       
   566 
       
   567 		$value = ord( $utf8_string[ $i ] );
       
   568 
       
   569 		if ( $value < 128 ) {
       
   570 			if ( $length && ( $unicode_length >= $length ) )
       
   571 				break;
       
   572 			$unicode .= chr($value);
       
   573 			$unicode_length++;
       
   574 		} else {
       
   575 			if ( count( $values ) == 0 ) $num_octets = ( $value < 224 ) ? 2 : 3;
       
   576 
       
   577 			$values[] = $value;
       
   578 
       
   579 			if ( $length && ( $unicode_length + ($num_octets * 3) ) > $length )
       
   580 				break;
       
   581 			if ( count( $values ) == $num_octets ) {
       
   582 				if ($num_octets == 3) {
       
   583 					$unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]) . '%' . dechex($values[2]);
       
   584 					$unicode_length += 9;
       
   585 				} else {
       
   586 					$unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]);
       
   587 					$unicode_length += 6;
       
   588 				}
       
   589 
       
   590 				$values = array();
       
   591 				$num_octets = 1;
       
   592 			}
       
   593 		}
       
   594 	}
       
   595 
       
   596 	return $unicode;
       
   597 }
       
   598 
       
   599 /**
       
   600  * Converts all accent characters to ASCII characters.
       
   601  *
       
   602  * If there are no accent characters, then the string given is just returned.
       
   603  *
       
   604  * @since 1.2.1
       
   605  *
       
   606  * @param string $string Text that might have accent characters
       
   607  * @return string Filtered string with replaced "nice" characters.
       
   608  */
       
   609 function remove_accents($string) {
       
   610 	if ( !preg_match('/[\x80-\xff]/', $string) )
       
   611 		return $string;
       
   612 
       
   613 	if (seems_utf8($string)) {
       
   614 		$chars = array(
       
   615 		// Decompositions for Latin-1 Supplement
       
   616 		chr(194).chr(170) => 'a', chr(194).chr(186) => 'o',
       
   617 		chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
       
   618 		chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
       
   619 		chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
       
   620 		chr(195).chr(134) => 'AE',chr(195).chr(135) => 'C',
       
   621 		chr(195).chr(136) => 'E', chr(195).chr(137) => 'E',
       
   622 		chr(195).chr(138) => 'E', chr(195).chr(139) => 'E',
       
   623 		chr(195).chr(140) => 'I', chr(195).chr(141) => 'I',
       
   624 		chr(195).chr(142) => 'I', chr(195).chr(143) => 'I',
       
   625 		chr(195).chr(144) => 'D', chr(195).chr(145) => 'N',
       
   626 		chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
       
   627 		chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
       
   628 		chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
       
   629 		chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
       
   630 		chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
       
   631 		chr(195).chr(158) => 'TH',chr(195).chr(159) => 's',
       
   632 		chr(195).chr(160) => 'a', chr(195).chr(161) => 'a',
       
   633 		chr(195).chr(162) => 'a', chr(195).chr(163) => 'a',
       
   634 		chr(195).chr(164) => 'a', chr(195).chr(165) => 'a',
       
   635 		chr(195).chr(166) => 'ae',chr(195).chr(167) => 'c',
       
   636 		chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
       
   637 		chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
       
   638 		chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
       
   639 		chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
       
   640 		chr(195).chr(176) => 'd', chr(195).chr(177) => 'n',
       
   641 		chr(195).chr(178) => 'o', chr(195).chr(179) => 'o',
       
   642 		chr(195).chr(180) => 'o', chr(195).chr(181) => 'o',
       
   643 		chr(195).chr(182) => 'o', chr(195).chr(184) => 'o',
       
   644 		chr(195).chr(185) => 'u', chr(195).chr(186) => 'u',
       
   645 		chr(195).chr(187) => 'u', chr(195).chr(188) => 'u',
       
   646 		chr(195).chr(189) => 'y', chr(195).chr(190) => 'th',
       
   647 		chr(195).chr(191) => 'y', chr(195).chr(152) => 'O',
       
   648 		// Decompositions for Latin Extended-A
       
   649 		chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
       
   650 		chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
       
   651 		chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
       
   652 		chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
       
   653 		chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
       
   654 		chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
       
   655 		chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
       
   656 		chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
       
   657 		chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
       
   658 		chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
       
   659 		chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
       
   660 		chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
       
   661 		chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
       
   662 		chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
       
   663 		chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
       
   664 		chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
       
   665 		chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
       
   666 		chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
       
   667 		chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
       
   668 		chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
       
   669 		chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
       
   670 		chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
       
   671 		chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
       
   672 		chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
       
   673 		chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
       
   674 		chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
       
   675 		chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
       
   676 		chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
       
   677 		chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
       
   678 		chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
       
   679 		chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
       
   680 		chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
       
   681 		chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
       
   682 		chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
       
   683 		chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
       
   684 		chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
       
   685 		chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
       
   686 		chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
       
   687 		chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
       
   688 		chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
       
   689 		chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
       
   690 		chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
       
   691 		chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
       
   692 		chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
       
   693 		chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
       
   694 		chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
       
   695 		chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
       
   696 		chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
       
   697 		chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
       
   698 		chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
       
   699 		chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
       
   700 		chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
       
   701 		chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
       
   702 		chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
       
   703 		chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
       
   704 		chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
       
   705 		chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
       
   706 		chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
       
   707 		chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
       
   708 		chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
       
   709 		chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
       
   710 		chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
       
   711 		chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
       
   712 		chr(197).chr(190) => 'z', chr(197).chr(191) => 's',
       
   713 		// Decompositions for Latin Extended-B
       
   714 		chr(200).chr(152) => 'S', chr(200).chr(153) => 's',
       
   715 		chr(200).chr(154) => 'T', chr(200).chr(155) => 't',
       
   716 		// Euro Sign
       
   717 		chr(226).chr(130).chr(172) => 'E',
       
   718 		// GBP (Pound) Sign
       
   719 		chr(194).chr(163) => '',
       
   720 		// Vowels with diacritic (Vietnamese)
       
   721 		// unmarked
       
   722 		chr(198).chr(160) => 'O', chr(198).chr(161) => 'o',
       
   723 		chr(198).chr(175) => 'U', chr(198).chr(176) => 'u',
       
   724 		// grave accent
       
   725 		chr(225).chr(186).chr(166) => 'A', chr(225).chr(186).chr(167) => 'a',
       
   726 		chr(225).chr(186).chr(176) => 'A', chr(225).chr(186).chr(177) => 'a',
       
   727 		chr(225).chr(187).chr(128) => 'E', chr(225).chr(187).chr(129) => 'e',
       
   728 		chr(225).chr(187).chr(146) => 'O', chr(225).chr(187).chr(147) => 'o',
       
   729 		chr(225).chr(187).chr(156) => 'O', chr(225).chr(187).chr(157) => 'o',
       
   730 		chr(225).chr(187).chr(170) => 'U', chr(225).chr(187).chr(171) => 'u',
       
   731 		chr(225).chr(187).chr(178) => 'Y', chr(225).chr(187).chr(179) => 'y',
       
   732 		// hook
       
   733 		chr(225).chr(186).chr(162) => 'A', chr(225).chr(186).chr(163) => 'a',
       
   734 		chr(225).chr(186).chr(168) => 'A', chr(225).chr(186).chr(169) => 'a',
       
   735 		chr(225).chr(186).chr(178) => 'A', chr(225).chr(186).chr(179) => 'a',
       
   736 		chr(225).chr(186).chr(186) => 'E', chr(225).chr(186).chr(187) => 'e',
       
   737 		chr(225).chr(187).chr(130) => 'E', chr(225).chr(187).chr(131) => 'e',
       
   738 		chr(225).chr(187).chr(136) => 'I', chr(225).chr(187).chr(137) => 'i',
       
   739 		chr(225).chr(187).chr(142) => 'O', chr(225).chr(187).chr(143) => 'o',
       
   740 		chr(225).chr(187).chr(148) => 'O', chr(225).chr(187).chr(149) => 'o',
       
   741 		chr(225).chr(187).chr(158) => 'O', chr(225).chr(187).chr(159) => 'o',
       
   742 		chr(225).chr(187).chr(166) => 'U', chr(225).chr(187).chr(167) => 'u',
       
   743 		chr(225).chr(187).chr(172) => 'U', chr(225).chr(187).chr(173) => 'u',
       
   744 		chr(225).chr(187).chr(182) => 'Y', chr(225).chr(187).chr(183) => 'y',
       
   745 		// tilde
       
   746 		chr(225).chr(186).chr(170) => 'A', chr(225).chr(186).chr(171) => 'a',
       
   747 		chr(225).chr(186).chr(180) => 'A', chr(225).chr(186).chr(181) => 'a',
       
   748 		chr(225).chr(186).chr(188) => 'E', chr(225).chr(186).chr(189) => 'e',
       
   749 		chr(225).chr(187).chr(132) => 'E', chr(225).chr(187).chr(133) => 'e',
       
   750 		chr(225).chr(187).chr(150) => 'O', chr(225).chr(187).chr(151) => 'o',
       
   751 		chr(225).chr(187).chr(160) => 'O', chr(225).chr(187).chr(161) => 'o',
       
   752 		chr(225).chr(187).chr(174) => 'U', chr(225).chr(187).chr(175) => 'u',
       
   753 		chr(225).chr(187).chr(184) => 'Y', chr(225).chr(187).chr(185) => 'y',
       
   754 		// acute accent
       
   755 		chr(225).chr(186).chr(164) => 'A', chr(225).chr(186).chr(165) => 'a',
       
   756 		chr(225).chr(186).chr(174) => 'A', chr(225).chr(186).chr(175) => 'a',
       
   757 		chr(225).chr(186).chr(190) => 'E', chr(225).chr(186).chr(191) => 'e',
       
   758 		chr(225).chr(187).chr(144) => 'O', chr(225).chr(187).chr(145) => 'o',
       
   759 		chr(225).chr(187).chr(154) => 'O', chr(225).chr(187).chr(155) => 'o',
       
   760 		chr(225).chr(187).chr(168) => 'U', chr(225).chr(187).chr(169) => 'u',
       
   761 		// dot below
       
   762 		chr(225).chr(186).chr(160) => 'A', chr(225).chr(186).chr(161) => 'a',
       
   763 		chr(225).chr(186).chr(172) => 'A', chr(225).chr(186).chr(173) => 'a',
       
   764 		chr(225).chr(186).chr(182) => 'A', chr(225).chr(186).chr(183) => 'a',
       
   765 		chr(225).chr(186).chr(184) => 'E', chr(225).chr(186).chr(185) => 'e',
       
   766 		chr(225).chr(187).chr(134) => 'E', chr(225).chr(187).chr(135) => 'e',
       
   767 		chr(225).chr(187).chr(138) => 'I', chr(225).chr(187).chr(139) => 'i',
       
   768 		chr(225).chr(187).chr(140) => 'O', chr(225).chr(187).chr(141) => 'o',
       
   769 		chr(225).chr(187).chr(152) => 'O', chr(225).chr(187).chr(153) => 'o',
       
   770 		chr(225).chr(187).chr(162) => 'O', chr(225).chr(187).chr(163) => 'o',
       
   771 		chr(225).chr(187).chr(164) => 'U', chr(225).chr(187).chr(165) => 'u',
       
   772 		chr(225).chr(187).chr(176) => 'U', chr(225).chr(187).chr(177) => 'u',
       
   773 		chr(225).chr(187).chr(180) => 'Y', chr(225).chr(187).chr(181) => 'y',
       
   774 		// Vowels with diacritic (Chinese, Hanyu Pinyin)
       
   775 		chr(201).chr(145) => 'a',
       
   776 		// macron
       
   777 		chr(199).chr(149) => 'U', chr(199).chr(150) => 'u',
       
   778 		// acute accent
       
   779 		chr(199).chr(151) => 'U', chr(199).chr(152) => 'u',
       
   780 		// caron
       
   781 		chr(199).chr(141) => 'A', chr(199).chr(142) => 'a',
       
   782 		chr(199).chr(143) => 'I', chr(199).chr(144) => 'i',
       
   783 		chr(199).chr(145) => 'O', chr(199).chr(146) => 'o',
       
   784 		chr(199).chr(147) => 'U', chr(199).chr(148) => 'u',
       
   785 		chr(199).chr(153) => 'U', chr(199).chr(154) => 'u',
       
   786 		// grave accent
       
   787 		chr(199).chr(155) => 'U', chr(199).chr(156) => 'u',
       
   788 		);
       
   789 
       
   790 		// Used for locale-specific rules
       
   791 		$locale = get_locale();
       
   792 
       
   793 		if ( 'de_DE' == $locale ) {
       
   794 			$chars[ chr(195).chr(132) ] = 'Ae';
       
   795 			$chars[ chr(195).chr(164) ] = 'ae';
       
   796 			$chars[ chr(195).chr(150) ] = 'Oe';
       
   797 			$chars[ chr(195).chr(182) ] = 'oe';
       
   798 			$chars[ chr(195).chr(156) ] = 'Ue';
       
   799 			$chars[ chr(195).chr(188) ] = 'ue';
       
   800 			$chars[ chr(195).chr(159) ] = 'ss';
       
   801 		}
       
   802 
       
   803 		$string = strtr($string, $chars);
       
   804 	} else {
       
   805 		// Assume ISO-8859-1 if not UTF-8
       
   806 		$chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158)
       
   807 			.chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194)
       
   808 			.chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202)
       
   809 			.chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210)
       
   810 			.chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218)
       
   811 			.chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227)
       
   812 			.chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235)
       
   813 			.chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243)
       
   814 			.chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251)
       
   815 			.chr(252).chr(253).chr(255);
       
   816 
       
   817 		$chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
       
   818 
       
   819 		$string = strtr($string, $chars['in'], $chars['out']);
       
   820 		$double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
       
   821 		$double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
       
   822 		$string = str_replace($double_chars['in'], $double_chars['out'], $string);
       
   823 	}
       
   824 
       
   825 	return $string;
       
   826 }
       
   827 
       
   828 /**
       
   829  * Sanitizes a filename, replacing whitespace with dashes.
       
   830  *
       
   831  * Removes special characters that are illegal in filenames on certain
       
   832  * operating systems and special characters requiring special escaping
       
   833  * to manipulate at the command line. Replaces spaces and consecutive
       
   834  * dashes with a single dash. Trims period, dash and underscore from beginning
       
   835  * and end of filename.
       
   836  *
       
   837  * @since 2.1.0
       
   838  *
       
   839  * @param string $filename The filename to be sanitized
       
   840  * @return string The sanitized filename
       
   841  */
       
   842 function sanitize_file_name( $filename ) {
       
   843 	$filename_raw = $filename;
       
   844 	$special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", chr(0));
       
   845 	$special_chars = apply_filters('sanitize_file_name_chars', $special_chars, $filename_raw);
       
   846 	$filename = str_replace($special_chars, '', $filename);
       
   847 	$filename = preg_replace('/[\s-]+/', '-', $filename);
       
   848 	$filename = trim($filename, '.-_');
       
   849 
       
   850 	// Split the filename into a base and extension[s]
       
   851 	$parts = explode('.', $filename);
       
   852 
       
   853 	// Return if only one extension
       
   854 	if ( count($parts) <= 2 )
       
   855 		return apply_filters('sanitize_file_name', $filename, $filename_raw);
       
   856 
       
   857 	// Process multiple extensions
       
   858 	$filename = array_shift($parts);
       
   859 	$extension = array_pop($parts);
       
   860 	$mimes = get_allowed_mime_types();
       
   861 
       
   862 	// Loop over any intermediate extensions. Munge them with a trailing underscore if they are a 2 - 5 character
       
   863 	// long alpha string not in the extension whitelist.
       
   864 	foreach ( (array) $parts as $part) {
       
   865 		$filename .= '.' . $part;
       
   866 
       
   867 		if ( preg_match("/^[a-zA-Z]{2,5}\d?$/", $part) ) {
       
   868 			$allowed = false;
       
   869 			foreach ( $mimes as $ext_preg => $mime_match ) {
       
   870 				$ext_preg = '!^(' . $ext_preg . ')$!i';
       
   871 				if ( preg_match( $ext_preg, $part ) ) {
       
   872 					$allowed = true;
       
   873 					break;
       
   874 				}
       
   875 			}
       
   876 			if ( !$allowed )
       
   877 				$filename .= '_';
       
   878 		}
       
   879 	}
       
   880 	$filename .= '.' . $extension;
       
   881 
       
   882 	return apply_filters('sanitize_file_name', $filename, $filename_raw);
       
   883 }
       
   884 
       
   885 /**
       
   886  * Sanitizes a username, stripping out unsafe characters.
       
   887  *
       
   888  * Removes tags, octets, entities, and if strict is enabled, will only keep
       
   889  * alphanumeric, _, space, ., -, @. After sanitizing, it passes the username,
       
   890  * raw username (the username in the parameter), and the value of $strict as
       
   891  * parameters for the 'sanitize_user' filter.
       
   892  *
       
   893  * @since 2.0.0
       
   894  * @uses apply_filters() Calls 'sanitize_user' hook on username, raw username,
       
   895  *		and $strict parameter.
       
   896  *
       
   897  * @param string $username The username to be sanitized.
       
   898  * @param bool $strict If set limits $username to specific characters. Default false.
       
   899  * @return string The sanitized username, after passing through filters.
       
   900  */
       
   901 function sanitize_user( $username, $strict = false ) {
       
   902 	$raw_username = $username;
       
   903 	$username = wp_strip_all_tags( $username );
       
   904 	$username = remove_accents( $username );
       
   905 	// Kill octets
       
   906 	$username = preg_replace( '|%([a-fA-F0-9][a-fA-F0-9])|', '', $username );
       
   907 	$username = preg_replace( '/&.+?;/', '', $username ); // Kill entities
       
   908 
       
   909 	// If strict, reduce to ASCII for max portability.
       
   910 	if ( $strict )
       
   911 		$username = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $username );
       
   912 
       
   913 	$username = trim( $username );
       
   914 	// Consolidate contiguous whitespace
       
   915 	$username = preg_replace( '|\s+|', ' ', $username );
       
   916 
       
   917 	return apply_filters( 'sanitize_user', $username, $raw_username, $strict );
       
   918 }
       
   919 
       
   920 /**
       
   921  * Sanitizes a string key.
       
   922  *
       
   923  * Keys are used as internal identifiers. Lowercase alphanumeric characters, dashes and underscores are allowed.
       
   924  *
       
   925  * @since 3.0.0
       
   926  *
       
   927  * @param string $key String key
       
   928  * @return string Sanitized key
       
   929  */
       
   930 function sanitize_key( $key ) {
       
   931 	$raw_key = $key;
       
   932 	$key = strtolower( $key );
       
   933 	$key = preg_replace( '/[^a-z0-9_\-]/', '', $key );
       
   934 	return apply_filters( 'sanitize_key', $key, $raw_key );
       
   935 }
       
   936 
       
   937 /**
       
   938  * Sanitizes a title, or returns a fallback title.
       
   939  *
       
   940  * Specifically, HTML and PHP tags are stripped. Further actions can be added
       
   941  * via the plugin API. If $title is empty and $fallback_title is set, the latter
       
   942  * will be used.
       
   943  *
       
   944  * @since 1.0.0
       
   945  *
       
   946  * @param string $title The string to be sanitized.
       
   947  * @param string $fallback_title Optional. A title to use if $title is empty.
       
   948  * @param string $context Optional. The operation for which the string is sanitized
       
   949  * @return string The sanitized string.
       
   950  */
       
   951 function sanitize_title( $title, $fallback_title = '', $context = 'save' ) {
       
   952 	$raw_title = $title;
       
   953 
       
   954 	if ( 'save' == $context )
       
   955 		$title = remove_accents($title);
       
   956 
       
   957 	$title = apply_filters('sanitize_title', $title, $raw_title, $context);
       
   958 
       
   959 	if ( '' === $title || false === $title )
       
   960 		$title = $fallback_title;
       
   961 
       
   962 	return $title;
       
   963 }
       
   964 
       
   965 /**
       
   966  * Sanitizes a title with the 'query' context.
       
   967  *
       
   968  * Used for querying the database for a value from URL.
       
   969  *
       
   970  * @since 3.1.0
       
   971  * @uses sanitize_title()
       
   972  *
       
   973  * @param string $title The string to be sanitized.
       
   974  * @return string The sanitized string.
       
   975  */
       
   976 function sanitize_title_for_query( $title ) {
       
   977 	return sanitize_title( $title, '', 'query' );
       
   978 }
       
   979 
       
   980 /**
       
   981  * Sanitizes a title, replacing whitespace and a few other characters with dashes.
       
   982  *
       
   983  * Limits the output to alphanumeric characters, underscore (_) and dash (-).
       
   984  * Whitespace becomes a dash.
       
   985  *
       
   986  * @since 1.2.0
       
   987  *
       
   988  * @param string $title The title to be sanitized.
       
   989  * @param string $raw_title Optional. Not used.
       
   990  * @param string $context Optional. The operation for which the string is sanitized.
       
   991  * @return string The sanitized title.
       
   992  */
       
   993 function sanitize_title_with_dashes( $title, $raw_title = '', $context = 'display' ) {
       
   994 	$title = strip_tags($title);
       
   995 	// Preserve escaped octets.
       
   996 	$title = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '---$1---', $title);
       
   997 	// Remove percent signs that are not part of an octet.
       
   998 	$title = str_replace('%', '', $title);
       
   999 	// Restore octets.
       
  1000 	$title = preg_replace('|---([a-fA-F0-9][a-fA-F0-9])---|', '%$1', $title);
       
  1001 
       
  1002 	if (seems_utf8($title)) {
       
  1003 		if (function_exists('mb_strtolower')) {
       
  1004 			$title = mb_strtolower($title, 'UTF-8');
       
  1005 		}
       
  1006 		$title = utf8_uri_encode($title, 200);
       
  1007 	}
       
  1008 
       
  1009 	$title = strtolower($title);
       
  1010 	$title = preg_replace('/&.+?;/', '', $title); // kill entities
       
  1011 	$title = str_replace('.', '-', $title);
       
  1012 
       
  1013 	if ( 'save' == $context ) {
       
  1014 		// Convert nbsp, ndash and mdash to hyphens
       
  1015 		$title = str_replace( array( '%c2%a0', '%e2%80%93', '%e2%80%94' ), '-', $title );
       
  1016 
       
  1017 		// Strip these characters entirely
       
  1018 		$title = str_replace( array(
       
  1019 			// iexcl and iquest
       
  1020 			'%c2%a1', '%c2%bf',
       
  1021 			// angle quotes
       
  1022 			'%c2%ab', '%c2%bb', '%e2%80%b9', '%e2%80%ba',
       
  1023 			// curly quotes
       
  1024 			'%e2%80%98', '%e2%80%99', '%e2%80%9c', '%e2%80%9d',
       
  1025 			'%e2%80%9a', '%e2%80%9b', '%e2%80%9e', '%e2%80%9f',
       
  1026 			// copy, reg, deg, hellip and trade
       
  1027 			'%c2%a9', '%c2%ae', '%c2%b0', '%e2%80%a6', '%e2%84%a2',
       
  1028 			// acute accents
       
  1029 			'%c2%b4', '%cb%8a', '%cc%81', '%cd%81',
       
  1030 			// grave accent, macron, caron
       
  1031 			'%cc%80', '%cc%84', '%cc%8c',
       
  1032 		), '', $title );
       
  1033 
       
  1034 		// Convert times to x
       
  1035 		$title = str_replace( '%c3%97', 'x', $title );
       
  1036 	}
       
  1037 
       
  1038 	$title = preg_replace('/[^%a-z0-9 _-]/', '', $title);
       
  1039 	$title = preg_replace('/\s+/', '-', $title);
       
  1040 	$title = preg_replace('|-+|', '-', $title);
       
  1041 	$title = trim($title, '-');
       
  1042 
       
  1043 	return $title;
       
  1044 }
       
  1045 
       
  1046 /**
       
  1047  * Ensures a string is a valid SQL order by clause.
       
  1048  *
       
  1049  * Accepts one or more columns, with or without ASC/DESC, and also accepts
       
  1050  * RAND().
       
  1051  *
       
  1052  * @since 2.5.1
       
  1053  *
       
  1054  * @param string $orderby Order by string to be checked.
       
  1055  * @return string|bool Returns the order by clause if it is a match, false otherwise.
       
  1056  */
       
  1057 function sanitize_sql_orderby( $orderby ){
       
  1058 	preg_match('/^\s*([a-z0-9_]+(\s+(ASC|DESC))?(\s*,\s*|\s*$))+|^\s*RAND\(\s*\)\s*$/i', $orderby, $obmatches);
       
  1059 	if ( !$obmatches )
       
  1060 		return false;
       
  1061 	return $orderby;
       
  1062 }
       
  1063 
       
  1064 /**
       
  1065  * Sanitizes an HTML classname to ensure it only contains valid characters.
       
  1066  *
       
  1067  * Strips the string down to A-Z,a-z,0-9,_,-. If this results in an empty
       
  1068  * string then it will return the alternative value supplied.
       
  1069  *
       
  1070  * @todo Expand to support the full range of CDATA that a class attribute can contain.
       
  1071  *
       
  1072  * @since 2.8.0
       
  1073  *
       
  1074  * @param string $class The classname to be sanitized
       
  1075  * @param string $fallback Optional. The value to return if the sanitization end's up as an empty string.
       
  1076  * 	Defaults to an empty string.
       
  1077  * @return string The sanitized value
       
  1078  */
       
  1079 function sanitize_html_class( $class, $fallback = '' ) {
       
  1080 	//Strip out any % encoded octets
       
  1081 	$sanitized = preg_replace( '|%[a-fA-F0-9][a-fA-F0-9]|', '', $class );
       
  1082 
       
  1083 	//Limit to A-Z,a-z,0-9,_,-
       
  1084 	$sanitized = preg_replace( '/[^A-Za-z0-9_-]/', '', $sanitized );
       
  1085 
       
  1086 	if ( '' == $sanitized )
       
  1087 		$sanitized = $fallback;
       
  1088 
       
  1089 	return apply_filters( 'sanitize_html_class', $sanitized, $class, $fallback );
       
  1090 }
       
  1091 
       
  1092 /**
       
  1093  * Converts a number of characters from a string.
       
  1094  *
       
  1095  * Metadata tags <<title>> and <<category>> are removed, <<br>> and <<hr>> are
       
  1096  * converted into correct XHTML and Unicode characters are converted to the
       
  1097  * valid range.
       
  1098  *
       
  1099  * @since 0.71
       
  1100  *
       
  1101  * @param string $content String of characters to be converted.
       
  1102  * @param string $deprecated Not used.
       
  1103  * @return string Converted string.
       
  1104  */
       
  1105 function convert_chars($content, $deprecated = '') {
       
  1106 	if ( !empty( $deprecated ) )
       
  1107 		_deprecated_argument( __FUNCTION__, '0.71' );
       
  1108 
       
  1109 	// Translation of invalid Unicode references range to valid range
       
  1110 	$wp_htmltranswinuni = array(
       
  1111 	'&#128;' => '&#8364;', // the Euro sign
       
  1112 	'&#129;' => '',
       
  1113 	'&#130;' => '&#8218;', // these are Windows CP1252 specific characters
       
  1114 	'&#131;' => '&#402;',  // they would look weird on non-Windows browsers
       
  1115 	'&#132;' => '&#8222;',
       
  1116 	'&#133;' => '&#8230;',
       
  1117 	'&#134;' => '&#8224;',
       
  1118 	'&#135;' => '&#8225;',
       
  1119 	'&#136;' => '&#710;',
       
  1120 	'&#137;' => '&#8240;',
       
  1121 	'&#138;' => '&#352;',
       
  1122 	'&#139;' => '&#8249;',
       
  1123 	'&#140;' => '&#338;',
       
  1124 	'&#141;' => '',
       
  1125 	'&#142;' => '&#381;',
       
  1126 	'&#143;' => '',
       
  1127 	'&#144;' => '',
       
  1128 	'&#145;' => '&#8216;',
       
  1129 	'&#146;' => '&#8217;',
       
  1130 	'&#147;' => '&#8220;',
       
  1131 	'&#148;' => '&#8221;',
       
  1132 	'&#149;' => '&#8226;',
       
  1133 	'&#150;' => '&#8211;',
       
  1134 	'&#151;' => '&#8212;',
       
  1135 	'&#152;' => '&#732;',
       
  1136 	'&#153;' => '&#8482;',
       
  1137 	'&#154;' => '&#353;',
       
  1138 	'&#155;' => '&#8250;',
       
  1139 	'&#156;' => '&#339;',
       
  1140 	'&#157;' => '',
       
  1141 	'&#158;' => '&#382;',
       
  1142 	'&#159;' => '&#376;'
       
  1143 	);
       
  1144 
       
  1145 	// Remove metadata tags
       
  1146 	$content = preg_replace('/<title>(.+?)<\/title>/','',$content);
       
  1147 	$content = preg_replace('/<category>(.+?)<\/category>/','',$content);
       
  1148 
       
  1149 	// Converts lone & characters into &#38; (a.k.a. &amp;)
       
  1150 	$content = preg_replace('/&([^#])(?![a-z1-4]{1,8};)/i', '&#038;$1', $content);
       
  1151 
       
  1152 	// Fix Word pasting
       
  1153 	$content = strtr($content, $wp_htmltranswinuni);
       
  1154 
       
  1155 	// Just a little XHTML help
       
  1156 	$content = str_replace('<br>', '<br />', $content);
       
  1157 	$content = str_replace('<hr>', '<hr />', $content);
       
  1158 
       
  1159 	return $content;
       
  1160 }
       
  1161 
       
  1162 /**
       
  1163  * Balances tags if forced to, or if the 'use_balanceTags' option is set to true.
       
  1164  *
       
  1165  * @since 0.71
       
  1166  *
       
  1167  * @param string $text Text to be balanced
       
  1168  * @param bool $force If true, forces balancing, ignoring the value of the option. Default false.
       
  1169  * @return string Balanced text
       
  1170  */
       
  1171 function balanceTags( $text, $force = false ) {
       
  1172 	if ( $force || get_option('use_balanceTags') == 1 )
       
  1173 		return force_balance_tags( $text );
       
  1174 	else
       
  1175 		return $text;
       
  1176 }
       
  1177 
       
  1178 /**
       
  1179  * Balances tags of string using a modified stack.
       
  1180  *
       
  1181  * @since 2.0.4
       
  1182  *
       
  1183  * @author Leonard Lin <leonard@acm.org>
       
  1184  * @license GPL
       
  1185  * @copyright November 4, 2001
       
  1186  * @version 1.1
       
  1187  * @todo Make better - change loop condition to $text in 1.2
       
  1188  * @internal Modified by Scott Reilly (coffee2code) 02 Aug 2004
       
  1189  *		1.1  Fixed handling of append/stack pop order of end text
       
  1190  *			 Added Cleaning Hooks
       
  1191  *		1.0  First Version
       
  1192  *
       
  1193  * @param string $text Text to be balanced.
       
  1194  * @return string Balanced text.
       
  1195  */
       
  1196 function force_balance_tags( $text ) {
       
  1197 	$tagstack = array();
       
  1198 	$stacksize = 0;
       
  1199 	$tagqueue = '';
       
  1200 	$newtext = '';
       
  1201 	// Known single-entity/self-closing tags
       
  1202 	$single_tags = array( 'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param', 'source' );
       
  1203 	// Tags that can be immediately nested within themselves
       
  1204 	$nestable_tags = array( 'blockquote', 'div', 'object', 'q', 'span' );
       
  1205 
       
  1206 	// WP bug fix for comments - in case you REALLY meant to type '< !--'
       
  1207 	$text = str_replace('< !--', '<    !--', $text);
       
  1208 	// WP bug fix for LOVE <3 (and other situations with '<' before a number)
       
  1209 	$text = preg_replace('#<([0-9]{1})#', '&lt;$1', $text);
       
  1210 
       
  1211 	while ( preg_match("/<(\/?[\w:]*)\s*([^>]*)>/", $text, $regex) ) {
       
  1212 		$newtext .= $tagqueue;
       
  1213 
       
  1214 		$i = strpos($text, $regex[0]);
       
  1215 		$l = strlen($regex[0]);
       
  1216 
       
  1217 		// clear the shifter
       
  1218 		$tagqueue = '';
       
  1219 		// Pop or Push
       
  1220 		if ( isset($regex[1][0]) && '/' == $regex[1][0] ) { // End Tag
       
  1221 			$tag = strtolower(substr($regex[1],1));
       
  1222 			// if too many closing tags
       
  1223 			if( $stacksize <= 0 ) {
       
  1224 				$tag = '';
       
  1225 				// or close to be safe $tag = '/' . $tag;
       
  1226 			}
       
  1227 			// if stacktop value = tag close value then pop
       
  1228 			else if ( $tagstack[$stacksize - 1] == $tag ) { // found closing tag
       
  1229 				$tag = '</' . $tag . '>'; // Close Tag
       
  1230 				// Pop
       
  1231 				array_pop( $tagstack );
       
  1232 				$stacksize--;
       
  1233 			} else { // closing tag not at top, search for it
       
  1234 				for ( $j = $stacksize-1; $j >= 0; $j-- ) {
       
  1235 					if ( $tagstack[$j] == $tag ) {
       
  1236 					// add tag to tagqueue
       
  1237 						for ( $k = $stacksize-1; $k >= $j; $k--) {
       
  1238 							$tagqueue .= '</' . array_pop( $tagstack ) . '>';
       
  1239 							$stacksize--;
       
  1240 						}
       
  1241 						break;
       
  1242 					}
       
  1243 				}
       
  1244 				$tag = '';
       
  1245 			}
       
  1246 		} else { // Begin Tag
       
  1247 			$tag = strtolower($regex[1]);
       
  1248 
       
  1249 			// Tag Cleaning
       
  1250 
       
  1251 			// If it's an empty tag "< >", do nothing
       
  1252 			if ( '' == $tag ) {
       
  1253 				// do nothing
       
  1254 			}
       
  1255 			// ElseIf it presents itself as a self-closing tag...
       
  1256 			elseif ( substr( $regex[2], -1 ) == '/' ) {
       
  1257 				// ...but it isn't a known single-entity self-closing tag, then don't let it be treated as such and
       
  1258 				// immediately close it with a closing tag (the tag will encapsulate no text as a result)
       
  1259 				if ( ! in_array( $tag, $single_tags ) )
       
  1260 					$regex[2] = trim( substr( $regex[2], 0, -1 ) ) . "></$tag";
       
  1261 			}
       
  1262 			// ElseIf it's a known single-entity tag but it doesn't close itself, do so
       
  1263 			elseif ( in_array($tag, $single_tags) ) {
       
  1264 				$regex[2] .= '/';
       
  1265 			}
       
  1266 			// Else it's not a single-entity tag
       
  1267 			else {
       
  1268 				// If the top of the stack is the same as the tag we want to push, close previous tag
       
  1269 				if ( $stacksize > 0 && !in_array($tag, $nestable_tags) && $tagstack[$stacksize - 1] == $tag ) {
       
  1270 					$tagqueue = '</' . array_pop( $tagstack ) . '>';
       
  1271 					$stacksize--;
       
  1272 				}
       
  1273 				$stacksize = array_push( $tagstack, $tag );
       
  1274 			}
       
  1275 
       
  1276 			// Attributes
       
  1277 			$attributes = $regex[2];
       
  1278 			if( ! empty( $attributes ) && $attributes[0] != '>' )
       
  1279 				$attributes = ' ' . $attributes;
       
  1280 
       
  1281 			$tag = '<' . $tag . $attributes . '>';
       
  1282 			//If already queuing a close tag, then put this tag on, too
       
  1283 			if ( !empty($tagqueue) ) {
       
  1284 				$tagqueue .= $tag;
       
  1285 				$tag = '';
       
  1286 			}
       
  1287 		}
       
  1288 		$newtext .= substr($text, 0, $i) . $tag;
       
  1289 		$text = substr($text, $i + $l);
       
  1290 	}
       
  1291 
       
  1292 	// Clear Tag Queue
       
  1293 	$newtext .= $tagqueue;
       
  1294 
       
  1295 	// Add Remaining text
       
  1296 	$newtext .= $text;
       
  1297 
       
  1298 	// Empty Stack
       
  1299 	while( $x = array_pop($tagstack) )
       
  1300 		$newtext .= '</' . $x . '>'; // Add remaining tags to close
       
  1301 
       
  1302 	// WP fix for the bug with HTML comments
       
  1303 	$newtext = str_replace("< !--","<!--",$newtext);
       
  1304 	$newtext = str_replace("<    !--","< !--",$newtext);
       
  1305 
       
  1306 	return $newtext;
       
  1307 }
       
  1308 
       
  1309 /**
       
  1310  * Acts on text which is about to be edited.
       
  1311  *
       
  1312  * The $content is run through esc_textarea(), which uses htmlspecialchars()
       
  1313  * to convert special characters to HTML entities. If $richedit is set to true,
       
  1314  * it is simply a holder for the 'format_to_edit' filter.
       
  1315  *
       
  1316  * @since 0.71
       
  1317  *
       
  1318  * @param string $content The text about to be edited.
       
  1319  * @param bool $richedit Whether the $content should not pass through htmlspecialchars(). Default false (meaning it will be passed).
       
  1320  * @return string The text after the filter (and possibly htmlspecialchars()) has been run.
       
  1321  */
       
  1322 function format_to_edit( $content, $richedit = false ) {
       
  1323 	$content = apply_filters( 'format_to_edit', $content );
       
  1324 	if ( ! $richedit )
       
  1325 		$content = esc_textarea( $content );
       
  1326 	return $content;
       
  1327 }
       
  1328 
       
  1329 /**
       
  1330  * Holder for the 'format_to_post' filter.
       
  1331  *
       
  1332  * @since 0.71
       
  1333  *
       
  1334  * @param string $content The text to pass through the filter.
       
  1335  * @return string Text returned from the 'format_to_post' filter.
       
  1336  */
       
  1337 function format_to_post($content) {
       
  1338 	$content = apply_filters('format_to_post', $content);
       
  1339 	return $content;
       
  1340 }
       
  1341 
       
  1342 /**
       
  1343  * Add leading zeros when necessary.
       
  1344  *
       
  1345  * If you set the threshold to '4' and the number is '10', then you will get
       
  1346  * back '0010'. If you set the threshold to '4' and the number is '5000', then you
       
  1347  * will get back '5000'.
       
  1348  *
       
  1349  * Uses sprintf to append the amount of zeros based on the $threshold parameter
       
  1350  * and the size of the number. If the number is large enough, then no zeros will
       
  1351  * be appended.
       
  1352  *
       
  1353  * @since 0.71
       
  1354  *
       
  1355  * @param mixed $number Number to append zeros to if not greater than threshold.
       
  1356  * @param int $threshold Digit places number needs to be to not have zeros added.
       
  1357  * @return string Adds leading zeros to number if needed.
       
  1358  */
       
  1359 function zeroise($number, $threshold) {
       
  1360 	return sprintf('%0'.$threshold.'s', $number);
       
  1361 }
       
  1362 
       
  1363 /**
       
  1364  * Adds backslashes before letters and before a number at the start of a string.
       
  1365  *
       
  1366  * @since 0.71
       
  1367  *
       
  1368  * @param string $string Value to which backslashes will be added.
       
  1369  * @return string String with backslashes inserted.
       
  1370  */
       
  1371 function backslashit($string) {
       
  1372 	if ( isset( $string[0] ) && $string[0] >= '0' && $string[0] <= '9' )
       
  1373 		$string = '\\\\' . $string;
       
  1374 	return addcslashes( $string, 'A..Za..z' );
       
  1375 }
       
  1376 
       
  1377 /**
       
  1378  * Appends a trailing slash.
       
  1379  *
       
  1380  * Will remove trailing slash if it exists already before adding a trailing
       
  1381  * slash. This prevents double slashing a string or path.
       
  1382  *
       
  1383  * The primary use of this is for paths and thus should be used for paths. It is
       
  1384  * not restricted to paths and offers no specific path support.
       
  1385  *
       
  1386  * @since 1.2.0
       
  1387  * @uses untrailingslashit() Unslashes string if it was slashed already.
       
  1388  *
       
  1389  * @param string $string What to add the trailing slash to.
       
  1390  * @return string String with trailing slash added.
       
  1391  */
       
  1392 function trailingslashit($string) {
       
  1393 	return untrailingslashit($string) . '/';
       
  1394 }
       
  1395 
       
  1396 /**
       
  1397  * Removes trailing slash if it exists.
       
  1398  *
       
  1399  * The primary use of this is for paths and thus should be used for paths. It is
       
  1400  * not restricted to paths and offers no specific path support.
       
  1401  *
       
  1402  * @since 2.2.0
       
  1403  *
       
  1404  * @param string $string What to remove the trailing slash from.
       
  1405  * @return string String without the trailing slash.
       
  1406  */
       
  1407 function untrailingslashit($string) {
       
  1408 	return rtrim($string, '/');
       
  1409 }
       
  1410 
       
  1411 /**
       
  1412  * Adds slashes to escape strings.
       
  1413  *
       
  1414  * Slashes will first be removed if magic_quotes_gpc is set, see {@link
       
  1415  * http://www.php.net/magic_quotes} for more details.
       
  1416  *
       
  1417  * @since 0.71
       
  1418  *
       
  1419  * @param string $gpc The string returned from HTTP request data.
       
  1420  * @return string Returns a string escaped with slashes.
       
  1421  */
       
  1422 function addslashes_gpc($gpc) {
       
  1423 	if ( get_magic_quotes_gpc() )
       
  1424 		$gpc = stripslashes($gpc);
       
  1425 
       
  1426 	return wp_slash($gpc);
       
  1427 }
       
  1428 
       
  1429 /**
       
  1430  * Navigates through an array and removes slashes from the values.
       
  1431  *
       
  1432  * If an array is passed, the array_map() function causes a callback to pass the
       
  1433  * value back to the function. The slashes from this value will removed.
       
  1434  *
       
  1435  * @since 2.0.0
       
  1436  *
       
  1437  * @param mixed $value The value to be stripped.
       
  1438  * @return mixed Stripped value.
       
  1439  */
       
  1440 function stripslashes_deep($value) {
       
  1441 	if ( is_array($value) ) {
       
  1442 		$value = array_map('stripslashes_deep', $value);
       
  1443 	} elseif ( is_object($value) ) {
       
  1444 		$vars = get_object_vars( $value );
       
  1445 		foreach ($vars as $key=>$data) {
       
  1446 			$value->{$key} = stripslashes_deep( $data );
       
  1447 		}
       
  1448 	} elseif ( is_string( $value ) ) {
       
  1449 		$value = stripslashes($value);
       
  1450 	}
       
  1451 
       
  1452 	return $value;
       
  1453 }
       
  1454 
       
  1455 /**
       
  1456  * Navigates through an array and encodes the values to be used in a URL.
       
  1457  *
       
  1458  *
       
  1459  * @since 2.2.0
       
  1460  *
       
  1461  * @param array|string $value The array or string to be encoded.
       
  1462  * @return array|string $value The encoded array (or string from the callback).
       
  1463  */
       
  1464 function urlencode_deep($value) {
       
  1465 	$value = is_array($value) ? array_map('urlencode_deep', $value) : urlencode($value);
       
  1466 	return $value;
       
  1467 }
       
  1468 
       
  1469 /**
       
  1470  * Navigates through an array and raw encodes the values to be used in a URL.
       
  1471  *
       
  1472  * @since 3.4.0
       
  1473  *
       
  1474  * @param array|string $value The array or string to be encoded.
       
  1475  * @return array|string $value The encoded array (or string from the callback).
       
  1476  */
       
  1477 function rawurlencode_deep( $value ) {
       
  1478 	return is_array( $value ) ? array_map( 'rawurlencode_deep', $value ) : rawurlencode( $value );
       
  1479 }
       
  1480 
       
  1481 /**
       
  1482  * Converts email addresses characters to HTML entities to block spam bots.
       
  1483  *
       
  1484  * @since 0.71
       
  1485  *
       
  1486  * @param string $email_address Email address.
       
  1487  * @param int $hex_encoding Optional. Set to 1 to enable hex encoding.
       
  1488  * @return string Converted email address.
       
  1489  */
       
  1490 function antispambot( $email_address, $hex_encoding = 0 ) {
       
  1491 	$email_no_spam_address = '';
       
  1492 	for ( $i = 0; $i < strlen( $email_address ); $i++ ) {
       
  1493 		$j = rand( 0, 1 + $hex_encoding );
       
  1494 		if ( $j == 0 ) {
       
  1495 			$email_no_spam_address .= '&#' . ord( $email_address[$i] ) . ';';
       
  1496 		} elseif ( $j == 1 ) {
       
  1497 			$email_no_spam_address .= $email_address[$i];
       
  1498 		} elseif ( $j == 2 ) {
       
  1499 			$email_no_spam_address .= '%' . zeroise( dechex( ord( $email_address[$i] ) ), 2 );
       
  1500 		}
       
  1501 	}
       
  1502 
       
  1503 	$email_no_spam_address = str_replace( '@', '&#64;', $email_no_spam_address );
       
  1504 
       
  1505 	return $email_no_spam_address;
       
  1506 }
       
  1507 
       
  1508 /**
       
  1509  * Callback to convert URI match to HTML A element.
       
  1510  *
       
  1511  * This function was backported from 2.5.0 to 2.3.2. Regex callback for {@link
       
  1512  * make_clickable()}.
       
  1513  *
       
  1514  * @since 2.3.2
       
  1515  * @access private
       
  1516  *
       
  1517  * @param array $matches Single Regex Match.
       
  1518  * @return string HTML A element with URI address.
       
  1519  */
       
  1520 function _make_url_clickable_cb($matches) {
       
  1521 	$url = $matches[2];
       
  1522 
       
  1523 	if ( ')' == $matches[3] && strpos( $url, '(' ) ) {
       
  1524 		// If the trailing character is a closing parethesis, and the URL has an opening parenthesis in it, add the closing parenthesis to the URL.
       
  1525 		// Then we can let the parenthesis balancer do its thing below.
       
  1526 		$url .= $matches[3];
       
  1527 		$suffix = '';
       
  1528 	} else {
       
  1529 		$suffix = $matches[3];
       
  1530 	}
       
  1531 
       
  1532 	// Include parentheses in the URL only if paired
       
  1533 	while ( substr_count( $url, '(' ) < substr_count( $url, ')' ) ) {
       
  1534 		$suffix = strrchr( $url, ')' ) . $suffix;
       
  1535 		$url = substr( $url, 0, strrpos( $url, ')' ) );
       
  1536 	}
       
  1537 
       
  1538 	$url = esc_url($url);
       
  1539 	if ( empty($url) )
       
  1540 		return $matches[0];
       
  1541 
       
  1542 	return $matches[1] . "<a href=\"$url\" rel=\"nofollow\">$url</a>" . $suffix;
       
  1543 }
       
  1544 
       
  1545 /**
       
  1546  * Callback to convert URL match to HTML A element.
       
  1547  *
       
  1548  * This function was backported from 2.5.0 to 2.3.2. Regex callback for {@link
       
  1549  * make_clickable()}.
       
  1550  *
       
  1551  * @since 2.3.2
       
  1552  * @access private
       
  1553  *
       
  1554  * @param array $matches Single Regex Match.
       
  1555  * @return string HTML A element with URL address.
       
  1556  */
       
  1557 function _make_web_ftp_clickable_cb($matches) {
       
  1558 	$ret = '';
       
  1559 	$dest = $matches[2];
       
  1560 	$dest = 'http://' . $dest;
       
  1561 	$dest = esc_url($dest);
       
  1562 	if ( empty($dest) )
       
  1563 		return $matches[0];
       
  1564 
       
  1565 	// removed trailing [.,;:)] from URL
       
  1566 	if ( in_array( substr($dest, -1), array('.', ',', ';', ':', ')') ) === true ) {
       
  1567 		$ret = substr($dest, -1);
       
  1568 		$dest = substr($dest, 0, strlen($dest)-1);
       
  1569 	}
       
  1570 	return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\">$dest</a>$ret";
       
  1571 }
       
  1572 
       
  1573 /**
       
  1574  * Callback to convert email address match to HTML A element.
       
  1575  *
       
  1576  * This function was backported from 2.5.0 to 2.3.2. Regex callback for {@link
       
  1577  * make_clickable()}.
       
  1578  *
       
  1579  * @since 2.3.2
       
  1580  * @access private
       
  1581  *
       
  1582  * @param array $matches Single Regex Match.
       
  1583  * @return string HTML A element with email address.
       
  1584  */
       
  1585 function _make_email_clickable_cb($matches) {
       
  1586 	$email = $matches[2] . '@' . $matches[3];
       
  1587 	return $matches[1] . "<a href=\"mailto:$email\">$email</a>";
       
  1588 }
       
  1589 
       
  1590 /**
       
  1591  * Convert plaintext URI to HTML links.
       
  1592  *
       
  1593  * Converts URI, www and ftp, and email addresses. Finishes by fixing links
       
  1594  * within links.
       
  1595  *
       
  1596  * @since 0.71
       
  1597  *
       
  1598  * @param string $text Content to convert URIs.
       
  1599  * @return string Content with converted URIs.
       
  1600  */
       
  1601 function make_clickable( $text ) {
       
  1602 	$r = '';
       
  1603 	$textarr = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags
       
  1604 	foreach ( $textarr as $piece ) {
       
  1605 		if ( empty( $piece ) || ( $piece[0] == '<' && ! preg_match('|^<\s*[\w]{1,20}+://|', $piece) ) ) {
       
  1606 			$r .= $piece;
       
  1607 			continue;
       
  1608 		}
       
  1609 
       
  1610 		// Long strings might contain expensive edge cases ...
       
  1611 		if ( 10000 < strlen( $piece ) ) {
       
  1612 			// ... break it up
       
  1613 			foreach ( _split_str_by_whitespace( $piece, 2100 ) as $chunk ) { // 2100: Extra room for scheme and leading and trailing paretheses
       
  1614 				if ( 2101 < strlen( $chunk ) ) {
       
  1615 					$r .= $chunk; // Too big, no whitespace: bail.
       
  1616 				} else {
       
  1617 					$r .= make_clickable( $chunk );
       
  1618 				}
       
  1619 			}
       
  1620 		} else {
       
  1621 			$ret = " $piece "; // Pad with whitespace to simplify the regexes
       
  1622 
       
  1623 			$url_clickable = '~
       
  1624 				([\\s(<.,;:!?])                                        # 1: Leading whitespace, or punctuation
       
  1625 				(                                                      # 2: URL
       
  1626 					[\\w]{1,20}+://                                # Scheme and hier-part prefix
       
  1627 					(?=\S{1,2000}\s)                               # Limit to URLs less than about 2000 characters long
       
  1628 					[\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+         # Non-punctuation URL character
       
  1629 					(?:                                            # Unroll the Loop: Only allow puctuation URL character if followed by a non-punctuation URL character
       
  1630 						[\'.,;:!?)]                            # Punctuation URL character
       
  1631 						[\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character
       
  1632 					)*
       
  1633 				)
       
  1634 				(\)?)                                                  # 3: Trailing closing parenthesis (for parethesis balancing post processing)
       
  1635 			~xS'; // The regex is a non-anchored pattern and does not have a single fixed starting character.
       
  1636 			      // Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times.
       
  1637 
       
  1638 			$ret = preg_replace_callback( $url_clickable, '_make_url_clickable_cb', $ret );
       
  1639 
       
  1640 			$ret = preg_replace_callback( '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', '_make_web_ftp_clickable_cb', $ret );
       
  1641 			$ret = preg_replace_callback( '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $ret );
       
  1642 
       
  1643 			$ret = substr( $ret, 1, -1 ); // Remove our whitespace padding.
       
  1644 			$r .= $ret;
       
  1645 		}
       
  1646 	}
       
  1647 
       
  1648 	// Cleanup of accidental links within links
       
  1649 	$r = preg_replace( '#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i', "$1$3</a>", $r );
       
  1650 	return $r;
       
  1651 }
       
  1652 
       
  1653 /**
       
  1654  * Breaks a string into chunks by splitting at whitespace characters.
       
  1655  * The length of each returned chunk is as close to the specified length goal as possible,
       
  1656  * with the caveat that each chunk includes its trailing delimiter.
       
  1657  * Chunks longer than the goal are guaranteed to not have any inner whitespace.
       
  1658  *
       
  1659  * Joining the returned chunks with empty delimiters reconstructs the input string losslessly.
       
  1660  *
       
  1661  * Input string must have no null characters (or eventual transformations on output chunks must not care about null characters)
       
  1662  *
       
  1663  * <code>
       
  1664  * _split_str_by_whitespace( "1234 67890 1234 67890a cd 1234   890 123456789 1234567890a    45678   1 3 5 7 90 ", 10 ) ==
       
  1665  * array (
       
  1666  *   0 => '1234 67890 ',  // 11 characters: Perfect split
       
  1667  *   1 => '1234 ',        //  5 characters: '1234 67890a' was too long
       
  1668  *   2 => '67890a cd ',   // 10 characters: '67890a cd 1234' was too long
       
  1669  *   3 => '1234   890 ',  // 11 characters: Perfect split
       
  1670  *   4 => '123456789 ',   // 10 characters: '123456789 1234567890a' was too long
       
  1671  *   5 => '1234567890a ', // 12 characters: Too long, but no inner whitespace on which to split
       
  1672  *   6 => '   45678   ',  // 11 characters: Perfect split
       
  1673  *   7 => '1 3 5 7 9',    //  9 characters: End of $string
       
  1674  * );
       
  1675  * </code>
       
  1676  *
       
  1677  * @since 3.4.0
       
  1678  * @access private
       
  1679  *
       
  1680  * @param string $string The string to split.
       
  1681  * @param int $goal The desired chunk length.
       
  1682  * @return array Numeric array of chunks.
       
  1683  */
       
  1684 function _split_str_by_whitespace( $string, $goal ) {
       
  1685 	$chunks = array();
       
  1686 
       
  1687 	$string_nullspace = strtr( $string, "\r\n\t\v\f ", "\000\000\000\000\000\000" );
       
  1688 
       
  1689 	while ( $goal < strlen( $string_nullspace ) ) {
       
  1690 		$pos = strrpos( substr( $string_nullspace, 0, $goal + 1 ), "\000" );
       
  1691 
       
  1692 		if ( false === $pos ) {
       
  1693 			$pos = strpos( $string_nullspace, "\000", $goal + 1 );
       
  1694 			if ( false === $pos ) {
       
  1695 				break;
       
  1696 			}
       
  1697 		}
       
  1698 
       
  1699 		$chunks[] = substr( $string, 0, $pos + 1 );
       
  1700 		$string = substr( $string, $pos + 1 );
       
  1701 		$string_nullspace = substr( $string_nullspace, $pos + 1 );
       
  1702 	}
       
  1703 
       
  1704 	if ( $string ) {
       
  1705 		$chunks[] = $string;
       
  1706 	}
       
  1707 
       
  1708 	return $chunks;
       
  1709 }
       
  1710 
       
  1711 /**
       
  1712  * Adds rel nofollow string to all HTML A elements in content.
       
  1713  *
       
  1714  * @since 1.5.0
       
  1715  *
       
  1716  * @param string $text Content that may contain HTML A elements.
       
  1717  * @return string Converted content.
       
  1718  */
       
  1719 function wp_rel_nofollow( $text ) {
       
  1720 	// This is a pre save filter, so text is already escaped.
       
  1721 	$text = stripslashes($text);
       
  1722 	$text = preg_replace_callback('|<a (.+?)>|i', 'wp_rel_nofollow_callback', $text);
       
  1723 	$text = wp_slash($text);
       
  1724 	return $text;
       
  1725 }
       
  1726 
       
  1727 /**
       
  1728  * Callback to add rel=nofollow string to HTML A element.
       
  1729  *
       
  1730  * Will remove already existing rel="nofollow" and rel='nofollow' from the
       
  1731  * string to prevent from invalidating (X)HTML.
       
  1732  *
       
  1733  * @since 2.3.0
       
  1734  *
       
  1735  * @param array $matches Single Match
       
  1736  * @return string HTML A Element with rel nofollow.
       
  1737  */
       
  1738 function wp_rel_nofollow_callback( $matches ) {
       
  1739 	$text = $matches[1];
       
  1740 	$text = str_replace(array(' rel="nofollow"', " rel='nofollow'"), '', $text);
       
  1741 	return "<a $text rel=\"nofollow\">";
       
  1742 }
       
  1743 
       
  1744 /**
       
  1745  * Convert one smiley code to the icon graphic file equivalent.
       
  1746  *
       
  1747  * Callback handler for {@link convert_smilies()}.
       
  1748  * Looks up one smiley code in the $wpsmiliestrans global array and returns an
       
  1749  * <img> string for that smiley.
       
  1750  *
       
  1751  * @global array $wpsmiliestrans
       
  1752  * @since 2.8.0
       
  1753  *
       
  1754  * @param array $matches Single match. Smiley code to convert to image.
       
  1755  * @return string Image string for smiley.
       
  1756  */
       
  1757 function translate_smiley( $matches ) {
       
  1758 	global $wpsmiliestrans;
       
  1759 
       
  1760 	if ( count( $matches ) == 0 )
       
  1761 		return '';
       
  1762 
       
  1763 	$smiley = trim( reset( $matches ) );
       
  1764 	$img = $wpsmiliestrans[ $smiley ];
       
  1765 	$smiley_masked = esc_attr( $smiley );
       
  1766 
       
  1767 	$src_url = apply_filters( 'smilies_src', includes_url( "images/smilies/$img" ), $img, site_url() );
       
  1768 
       
  1769 	return " <img src='$src_url' alt='$smiley_masked' class='wp-smiley' /> ";
       
  1770 }
       
  1771 
       
  1772 /**
       
  1773  * Convert text equivalent of smilies to images.
       
  1774  *
       
  1775  * Will only convert smilies if the option 'use_smilies' is true and the global
       
  1776  * used in the function isn't empty.
       
  1777  *
       
  1778  * @since 0.71
       
  1779  * @uses $wp_smiliessearch
       
  1780  *
       
  1781  * @param string $text Content to convert smilies from text.
       
  1782  * @return string Converted content with text smilies replaced with images.
       
  1783  */
       
  1784 function convert_smilies($text) {
       
  1785 	global $wp_smiliessearch;
       
  1786 	$output = '';
       
  1787 	if ( get_option('use_smilies') && !empty($wp_smiliessearch) ) {
       
  1788 		// HTML loop taken from texturize function, could possible be consolidated
       
  1789 		$textarr = preg_split("/(<.*>)/U", $text, -1, PREG_SPLIT_DELIM_CAPTURE); // capture the tags as well as in between
       
  1790 		$stop = count($textarr);// loop stuff
       
  1791 		for ($i = 0; $i < $stop; $i++) {
       
  1792 			$content = $textarr[$i];
       
  1793 			if ((strlen($content) > 0) && ('<' != $content[0])) { // If it's not a tag
       
  1794 				$content = preg_replace_callback($wp_smiliessearch, 'translate_smiley', $content);
       
  1795 			}
       
  1796 			$output .= $content;
       
  1797 		}
       
  1798 	} else {
       
  1799 		// return default text.
       
  1800 		$output = $text;
       
  1801 	}
       
  1802 	return $output;
       
  1803 }
       
  1804 
       
  1805 /**
       
  1806  * Verifies that an email is valid.
       
  1807  *
       
  1808  * Does not grok i18n domains. Not RFC compliant.
       
  1809  *
       
  1810  * @since 0.71
       
  1811  *
       
  1812  * @param string $email Email address to verify.
       
  1813  * @param boolean $deprecated Deprecated.
       
  1814  * @return string|bool Either false or the valid email address.
       
  1815  */
       
  1816 function is_email( $email, $deprecated = false ) {
       
  1817 	if ( ! empty( $deprecated ) )
       
  1818 		_deprecated_argument( __FUNCTION__, '3.0' );
       
  1819 
       
  1820 	// Test for the minimum length the email can be
       
  1821 	if ( strlen( $email ) < 3 ) {
       
  1822 		return apply_filters( 'is_email', false, $email, 'email_too_short' );
       
  1823 	}
       
  1824 
       
  1825 	// Test for an @ character after the first position
       
  1826 	if ( strpos( $email, '@', 1 ) === false ) {
       
  1827 		return apply_filters( 'is_email', false, $email, 'email_no_at' );
       
  1828 	}
       
  1829 
       
  1830 	// Split out the local and domain parts
       
  1831 	list( $local, $domain ) = explode( '@', $email, 2 );
       
  1832 
       
  1833 	// LOCAL PART
       
  1834 	// Test for invalid characters
       
  1835 	if ( !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local ) ) {
       
  1836 		return apply_filters( 'is_email', false, $email, 'local_invalid_chars' );
       
  1837 	}
       
  1838 
       
  1839 	// DOMAIN PART
       
  1840 	// Test for sequences of periods
       
  1841 	if ( preg_match( '/\.{2,}/', $domain ) ) {
       
  1842 		return apply_filters( 'is_email', false, $email, 'domain_period_sequence' );
       
  1843 	}
       
  1844 
       
  1845 	// Test for leading and trailing periods and whitespace
       
  1846 	if ( trim( $domain, " \t\n\r\0\x0B." ) !== $domain ) {
       
  1847 		return apply_filters( 'is_email', false, $email, 'domain_period_limits' );
       
  1848 	}
       
  1849 
       
  1850 	// Split the domain into subs
       
  1851 	$subs = explode( '.', $domain );
       
  1852 
       
  1853 	// Assume the domain will have at least two subs
       
  1854 	if ( 2 > count( $subs ) ) {
       
  1855 		return apply_filters( 'is_email', false, $email, 'domain_no_periods' );
       
  1856 	}
       
  1857 
       
  1858 	// Loop through each sub
       
  1859 	foreach ( $subs as $sub ) {
       
  1860 		// Test for leading and trailing hyphens and whitespace
       
  1861 		if ( trim( $sub, " \t\n\r\0\x0B-" ) !== $sub ) {
       
  1862 			return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );
       
  1863 		}
       
  1864 
       
  1865 		// Test for invalid characters
       
  1866 		if ( !preg_match('/^[a-z0-9-]+$/i', $sub ) ) {
       
  1867 			return apply_filters( 'is_email', false, $email, 'sub_invalid_chars' );
       
  1868 		}
       
  1869 	}
       
  1870 
       
  1871 	// Congratulations your email made it!
       
  1872 	return apply_filters( 'is_email', $email, $email, null );
       
  1873 }
       
  1874 
       
  1875 /**
       
  1876  * Convert to ASCII from email subjects.
       
  1877  *
       
  1878  * @since 1.2.0
       
  1879  *
       
  1880  * @param string $string Subject line
       
  1881  * @return string Converted string to ASCII
       
  1882  */
       
  1883 function wp_iso_descrambler($string) {
       
  1884 	/* this may only work with iso-8859-1, I'm afraid */
       
  1885 	if (!preg_match('#\=\?(.+)\?Q\?(.+)\?\=#i', $string, $matches)) {
       
  1886 		return $string;
       
  1887 	} else {
       
  1888 		$subject = str_replace('_', ' ', $matches[2]);
       
  1889 		$subject = preg_replace_callback('#\=([0-9a-f]{2})#i', '_wp_iso_convert', $subject);
       
  1890 		return $subject;
       
  1891 	}
       
  1892 }
       
  1893 
       
  1894 /**
       
  1895  * Helper function to convert hex encoded chars to ASCII
       
  1896  *
       
  1897  * @since 3.1.0
       
  1898  * @access private
       
  1899  *
       
  1900  * @param array $match The preg_replace_callback matches array
       
  1901  * @return array Converted chars
       
  1902  */
       
  1903 function _wp_iso_convert( $match ) {
       
  1904 	return chr( hexdec( strtolower( $match[1] ) ) );
       
  1905 }
       
  1906 
       
  1907 /**
       
  1908  * Returns a date in the GMT equivalent.
       
  1909  *
       
  1910  * Requires and returns a date in the Y-m-d H:i:s format. If there is a
       
  1911  * timezone_string available, the date is assumed to be in that timezone,
       
  1912  * otherwise it simply subtracts the value of the 'gmt_offset' option. Return
       
  1913  * format can be overridden using the $format parameter.
       
  1914  *
       
  1915  * @since 1.2.0
       
  1916  *
       
  1917  * @uses get_option() to retrieve the value of 'gmt_offset'.
       
  1918  * @param string $string The date to be converted.
       
  1919  * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
       
  1920  * @return string GMT version of the date provided.
       
  1921  */
       
  1922 function get_gmt_from_date( $string, $format = 'Y-m-d H:i:s' ) {
       
  1923 	$tz = get_option( 'timezone_string' );
       
  1924 	if ( $tz ) {
       
  1925 		$datetime = date_create( $string, new DateTimeZone( $tz ) );
       
  1926 		if ( ! $datetime )
       
  1927 			return gmdate( $format, 0 );
       
  1928 		$datetime->setTimezone( new DateTimeZone( 'UTC' ) );
       
  1929 		$string_gmt = $datetime->format( $format );
       
  1930 	} else {
       
  1931 		if ( ! preg_match( '#([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})#', $string, $matches ) )
       
  1932 			return gmdate( $format, 0 );
       
  1933 		$string_time = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
       
  1934 		$string_gmt = gmdate( $format, $string_time - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
       
  1935 	}
       
  1936 	return $string_gmt;
       
  1937 }
       
  1938 
       
  1939 /**
       
  1940  * Converts a GMT date into the correct format for the blog.
       
  1941  *
       
  1942  * Requires and returns a date in the Y-m-d H:i:s format. If there is a
       
  1943  * timezone_string available, the returned date is in that timezone, otherwise
       
  1944  * it simply adds the value of gmt_offset. Return format can be overridden
       
  1945  * using the $format parameter
       
  1946  *
       
  1947  * @since 1.2.0
       
  1948  *
       
  1949  * @param string $string The date to be converted.
       
  1950  * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
       
  1951  * @return string Formatted date relative to the timezone / GMT offset.
       
  1952  */
       
  1953 function get_date_from_gmt( $string, $format = 'Y-m-d H:i:s' ) {
       
  1954 	$tz = get_option( 'timezone_string' );
       
  1955 	if ( $tz ) {
       
  1956 		$datetime = date_create( $string, new DateTimeZone( 'UTC' ) );
       
  1957 		if ( ! $datetime )
       
  1958 			return date( $format, 0 );
       
  1959 		$datetime->setTimezone( new DateTimeZone( $tz ) );
       
  1960 		$string_localtime = $datetime->format( $format );
       
  1961 	} else {
       
  1962 		if ( ! preg_match('#([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})#', $string, $matches) )
       
  1963 			return date( $format, 0 );
       
  1964 		$string_time = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
       
  1965 		$string_localtime = gmdate( $format, $string_time + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
       
  1966 	}
       
  1967 	return $string_localtime;
       
  1968 }
       
  1969 
       
  1970 /**
       
  1971  * Computes an offset in seconds from an iso8601 timezone.
       
  1972  *
       
  1973  * @since 1.5.0
       
  1974  *
       
  1975  * @param string $timezone Either 'Z' for 0 offset or '±hhmm'.
       
  1976  * @return int|float The offset in seconds.
       
  1977  */
       
  1978 function iso8601_timezone_to_offset($timezone) {
       
  1979 	// $timezone is either 'Z' or '[+|-]hhmm'
       
  1980 	if ($timezone == 'Z') {
       
  1981 		$offset = 0;
       
  1982 	} else {
       
  1983 		$sign    = (substr($timezone, 0, 1) == '+') ? 1 : -1;
       
  1984 		$hours   = intval(substr($timezone, 1, 2));
       
  1985 		$minutes = intval(substr($timezone, 3, 4)) / 60;
       
  1986 		$offset  = $sign * HOUR_IN_SECONDS * ($hours + $minutes);
       
  1987 	}
       
  1988 	return $offset;
       
  1989 }
       
  1990 
       
  1991 /**
       
  1992  * Converts an iso8601 date to MySQL DateTime format used by post_date[_gmt].
       
  1993  *
       
  1994  * @since 1.5.0
       
  1995  *
       
  1996  * @param string $date_string Date and time in ISO 8601 format {@link http://en.wikipedia.org/wiki/ISO_8601}.
       
  1997  * @param string $timezone Optional. If set to GMT returns the time minus gmt_offset. Default is 'user'.
       
  1998  * @return string The date and time in MySQL DateTime format - Y-m-d H:i:s.
       
  1999  */
       
  2000 function iso8601_to_datetime($date_string, $timezone = 'user') {
       
  2001 	$timezone = strtolower($timezone);
       
  2002 
       
  2003 	if ($timezone == 'gmt') {
       
  2004 
       
  2005 		preg_match('#([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(Z|[\+|\-][0-9]{2,4}){0,1}#', $date_string, $date_bits);
       
  2006 
       
  2007 		if (!empty($date_bits[7])) { // we have a timezone, so let's compute an offset
       
  2008 			$offset = iso8601_timezone_to_offset($date_bits[7]);
       
  2009 		} else { // we don't have a timezone, so we assume user local timezone (not server's!)
       
  2010 			$offset = HOUR_IN_SECONDS * get_option('gmt_offset');
       
  2011 		}
       
  2012 
       
  2013 		$timestamp = gmmktime($date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1]);
       
  2014 		$timestamp -= $offset;
       
  2015 
       
  2016 		return gmdate('Y-m-d H:i:s', $timestamp);
       
  2017 
       
  2018 	} else if ($timezone == 'user') {
       
  2019 		return preg_replace('#([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(Z|[\+|\-][0-9]{2,4}){0,1}#', '$1-$2-$3 $4:$5:$6', $date_string);
       
  2020 	}
       
  2021 }
       
  2022 
       
  2023 /**
       
  2024  * Adds a element attributes to open links in new windows.
       
  2025  *
       
  2026  * Comment text in popup windows should be filtered through this. Right now it's
       
  2027  * a moderately dumb function, ideally it would detect whether a target or rel
       
  2028  * attribute was already there and adjust its actions accordingly.
       
  2029  *
       
  2030  * @since 0.71
       
  2031  *
       
  2032  * @param string $text Content to replace links to open in a new window.
       
  2033  * @return string Content that has filtered links.
       
  2034  */
       
  2035 function popuplinks($text) {
       
  2036 	$text = preg_replace('/<a (.+?)>/i', "<a $1 target='_blank' rel='external'>", $text);
       
  2037 	return $text;
       
  2038 }
       
  2039 
       
  2040 /**
       
  2041  * Strips out all characters that are not allowable in an email.
       
  2042  *
       
  2043  * @since 1.5.0
       
  2044  *
       
  2045  * @param string $email Email address to filter.
       
  2046  * @return string Filtered email address.
       
  2047  */
       
  2048 function sanitize_email( $email ) {
       
  2049 	// Test for the minimum length the email can be
       
  2050 	if ( strlen( $email ) < 3 ) {
       
  2051 		return apply_filters( 'sanitize_email', '', $email, 'email_too_short' );
       
  2052 	}
       
  2053 
       
  2054 	// Test for an @ character after the first position
       
  2055 	if ( strpos( $email, '@', 1 ) === false ) {
       
  2056 		return apply_filters( 'sanitize_email', '', $email, 'email_no_at' );
       
  2057 	}
       
  2058 
       
  2059 	// Split out the local and domain parts
       
  2060 	list( $local, $domain ) = explode( '@', $email, 2 );
       
  2061 
       
  2062 	// LOCAL PART
       
  2063 	// Test for invalid characters
       
  2064 	$local = preg_replace( '/[^a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]/', '', $local );
       
  2065 	if ( '' === $local ) {
       
  2066 		return apply_filters( 'sanitize_email', '', $email, 'local_invalid_chars' );
       
  2067 	}
       
  2068 
       
  2069 	// DOMAIN PART
       
  2070 	// Test for sequences of periods
       
  2071 	$domain = preg_replace( '/\.{2,}/', '', $domain );
       
  2072 	if ( '' === $domain ) {
       
  2073 		return apply_filters( 'sanitize_email', '', $email, 'domain_period_sequence' );
       
  2074 	}
       
  2075 
       
  2076 	// Test for leading and trailing periods and whitespace
       
  2077 	$domain = trim( $domain, " \t\n\r\0\x0B." );
       
  2078 	if ( '' === $domain ) {
       
  2079 		return apply_filters( 'sanitize_email', '', $email, 'domain_period_limits' );
       
  2080 	}
       
  2081 
       
  2082 	// Split the domain into subs
       
  2083 	$subs = explode( '.', $domain );
       
  2084 
       
  2085 	// Assume the domain will have at least two subs
       
  2086 	if ( 2 > count( $subs ) ) {
       
  2087 		return apply_filters( 'sanitize_email', '', $email, 'domain_no_periods' );
       
  2088 	}
       
  2089 
       
  2090 	// Create an array that will contain valid subs
       
  2091 	$new_subs = array();
       
  2092 
       
  2093 	// Loop through each sub
       
  2094 	foreach ( $subs as $sub ) {
       
  2095 		// Test for leading and trailing hyphens
       
  2096 		$sub = trim( $sub, " \t\n\r\0\x0B-" );
       
  2097 
       
  2098 		// Test for invalid characters
       
  2099 		$sub = preg_replace( '/[^a-z0-9-]+/i', '', $sub );
       
  2100 
       
  2101 		// If there's anything left, add it to the valid subs
       
  2102 		if ( '' !== $sub ) {
       
  2103 			$new_subs[] = $sub;
       
  2104 		}
       
  2105 	}
       
  2106 
       
  2107 	// If there aren't 2 or more valid subs
       
  2108 	if ( 2 > count( $new_subs ) ) {
       
  2109 		return apply_filters( 'sanitize_email', '', $email, 'domain_no_valid_subs' );
       
  2110 	}
       
  2111 
       
  2112 	// Join valid subs into the new domain
       
  2113 	$domain = join( '.', $new_subs );
       
  2114 
       
  2115 	// Put the email back together
       
  2116 	$email = $local . '@' . $domain;
       
  2117 
       
  2118 	// Congratulations your email made it!
       
  2119 	return apply_filters( 'sanitize_email', $email, $email, null );
       
  2120 }
       
  2121 
       
  2122 /**
       
  2123  * Determines the difference between two timestamps.
       
  2124  *
       
  2125  * The difference is returned in a human readable format such as "1 hour",
       
  2126  * "5 mins", "2 days".
       
  2127  *
       
  2128  * @since 1.5.0
       
  2129  *
       
  2130  * @param int $from Unix timestamp from which the difference begins.
       
  2131  * @param int $to Optional. Unix timestamp to end the time difference. Default becomes time() if not set.
       
  2132  * @return string Human readable time difference.
       
  2133  */
       
  2134 function human_time_diff( $from, $to = '' ) {
       
  2135 	if ( empty( $to ) )
       
  2136 		$to = time();
       
  2137 
       
  2138 	$diff = (int) abs( $to - $from );
       
  2139 
       
  2140 	if ( $diff < HOUR_IN_SECONDS ) {
       
  2141 		$mins = round( $diff / MINUTE_IN_SECONDS );
       
  2142 		if ( $mins <= 1 )
       
  2143 			$mins = 1;
       
  2144 		/* translators: min=minute */
       
  2145 		$since = sprintf( _n( '%s min', '%s mins', $mins ), $mins );
       
  2146 	} elseif ( $diff < DAY_IN_SECONDS && $diff >= HOUR_IN_SECONDS ) {
       
  2147 		$hours = round( $diff / HOUR_IN_SECONDS );
       
  2148 		if ( $hours <= 1 )
       
  2149 			$hours = 1;
       
  2150 		$since = sprintf( _n( '%s hour', '%s hours', $hours ), $hours );
       
  2151 	} elseif ( $diff < WEEK_IN_SECONDS && $diff >= DAY_IN_SECONDS ) {
       
  2152 		$days = round( $diff / DAY_IN_SECONDS );
       
  2153 		if ( $days <= 1 )
       
  2154 			$days = 1;
       
  2155 		$since = sprintf( _n( '%s day', '%s days', $days ), $days );
       
  2156 	} elseif ( $diff < 30 * DAY_IN_SECONDS && $diff >= WEEK_IN_SECONDS ) {
       
  2157 		$weeks = round( $diff / WEEK_IN_SECONDS );
       
  2158 		if ( $weeks <= 1 )
       
  2159 			$weeks = 1;
       
  2160 		$since = sprintf( _n( '%s week', '%s weeks', $weeks ), $weeks );
       
  2161 	} elseif ( $diff < YEAR_IN_SECONDS && $diff >= 30 * DAY_IN_SECONDS ) {
       
  2162 		$months = round( $diff / ( 30 * DAY_IN_SECONDS ) );
       
  2163 		if ( $months <= 1 )
       
  2164 			$months = 1;
       
  2165 		$since = sprintf( _n( '%s month', '%s months', $months ), $months );
       
  2166 	} elseif ( $diff >= YEAR_IN_SECONDS ) {
       
  2167 		$years = round( $diff / YEAR_IN_SECONDS );
       
  2168 		if ( $years <= 1 )
       
  2169 			$years = 1;
       
  2170 		$since = sprintf( _n( '%s year', '%s years', $years ), $years );
       
  2171 	}
       
  2172 
       
  2173 	return $since;
       
  2174 }
       
  2175 
       
  2176 /**
       
  2177  * Generates an excerpt from the content, if needed.
       
  2178  *
       
  2179  * The excerpt word amount will be 55 words and if the amount is greater than
       
  2180  * that, then the string ' [&hellip;]' will be appended to the excerpt. If the string
       
  2181  * is less than 55 words, then the content will be returned as is.
       
  2182  *
       
  2183  * The 55 word limit can be modified by plugins/themes using the excerpt_length filter
       
  2184  * The ' [&hellip;]' string can be modified by plugins/themes using the excerpt_more filter
       
  2185  *
       
  2186  * @since 1.5.0
       
  2187  *
       
  2188  * @param string $text Optional. The excerpt. If set to empty, an excerpt is generated.
       
  2189  * @return string The excerpt.
       
  2190  */
       
  2191 function wp_trim_excerpt($text = '') {
       
  2192 	$raw_excerpt = $text;
       
  2193 	if ( '' == $text ) {
       
  2194 		$text = get_the_content('');
       
  2195 
       
  2196 		$text = strip_shortcodes( $text );
       
  2197 
       
  2198 		$text = apply_filters('the_content', $text);
       
  2199 		$text = str_replace(']]>', ']]&gt;', $text);
       
  2200 		$excerpt_length = apply_filters('excerpt_length', 55);
       
  2201 		$excerpt_more = apply_filters('excerpt_more', ' ' . '[&hellip;]');
       
  2202 		$text = wp_trim_words( $text, $excerpt_length, $excerpt_more );
       
  2203 	}
       
  2204 	return apply_filters('wp_trim_excerpt', $text, $raw_excerpt);
       
  2205 }
       
  2206 
       
  2207 /**
       
  2208  * Trims text to a certain number of words.
       
  2209  *
       
  2210  * This function is localized. For languages that count 'words' by the individual
       
  2211  * character (such as East Asian languages), the $num_words argument will apply
       
  2212  * to the number of individual characters.
       
  2213  *
       
  2214  * @since 3.3.0
       
  2215  *
       
  2216  * @param string $text Text to trim.
       
  2217  * @param int $num_words Number of words. Default 55.
       
  2218  * @param string $more Optional. What to append if $text needs to be trimmed. Default '&hellip;'.
       
  2219  * @return string Trimmed text.
       
  2220  */
       
  2221 function wp_trim_words( $text, $num_words = 55, $more = null ) {
       
  2222 	if ( null === $more )
       
  2223 		$more = __( '&hellip;' );
       
  2224 	$original_text = $text;
       
  2225 	$text = wp_strip_all_tags( $text );
       
  2226 	/* translators: If your word count is based on single characters (East Asian characters),
       
  2227 	   enter 'characters'. Otherwise, enter 'words'. Do not translate into your own language. */
       
  2228 	if ( 'characters' == _x( 'words', 'word count: words or characters?' ) && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) ) {
       
  2229 		$text = trim( preg_replace( "/[\n\r\t ]+/", ' ', $text ), ' ' );
       
  2230 		preg_match_all( '/./u', $text, $words_array );
       
  2231 		$words_array = array_slice( $words_array[0], 0, $num_words + 1 );
       
  2232 		$sep = '';
       
  2233 	} else {
       
  2234 		$words_array = preg_split( "/[\n\r\t ]+/", $text, $num_words + 1, PREG_SPLIT_NO_EMPTY );
       
  2235 		$sep = ' ';
       
  2236 	}
       
  2237 	if ( count( $words_array ) > $num_words ) {
       
  2238 		array_pop( $words_array );
       
  2239 		$text = implode( $sep, $words_array );
       
  2240 		$text = $text . $more;
       
  2241 	} else {
       
  2242 		$text = implode( $sep, $words_array );
       
  2243 	}
       
  2244 	return apply_filters( 'wp_trim_words', $text, $num_words, $more, $original_text );
       
  2245 }
       
  2246 
       
  2247 /**
       
  2248  * Converts named entities into numbered entities.
       
  2249  *
       
  2250  * @since 1.5.1
       
  2251  *
       
  2252  * @param string $text The text within which entities will be converted.
       
  2253  * @return string Text with converted entities.
       
  2254  */
       
  2255 function ent2ncr($text) {
       
  2256 
       
  2257 	// Allow a plugin to short-circuit and override the mappings.
       
  2258 	$filtered = apply_filters( 'pre_ent2ncr', null, $text );
       
  2259 	if( null !== $filtered )
       
  2260 		return $filtered;
       
  2261 
       
  2262 	$to_ncr = array(
       
  2263 		'&quot;' => '&#34;',
       
  2264 		'&amp;' => '&#38;',
       
  2265 		'&lt;' => '&#60;',
       
  2266 		'&gt;' => '&#62;',
       
  2267 		'|' => '&#124;',
       
  2268 		'&nbsp;' => '&#160;',
       
  2269 		'&iexcl;' => '&#161;',
       
  2270 		'&cent;' => '&#162;',
       
  2271 		'&pound;' => '&#163;',
       
  2272 		'&curren;' => '&#164;',
       
  2273 		'&yen;' => '&#165;',
       
  2274 		'&brvbar;' => '&#166;',
       
  2275 		'&brkbar;' => '&#166;',
       
  2276 		'&sect;' => '&#167;',
       
  2277 		'&uml;' => '&#168;',
       
  2278 		'&die;' => '&#168;',
       
  2279 		'&copy;' => '&#169;',
       
  2280 		'&ordf;' => '&#170;',
       
  2281 		'&laquo;' => '&#171;',
       
  2282 		'&not;' => '&#172;',
       
  2283 		'&shy;' => '&#173;',
       
  2284 		'&reg;' => '&#174;',
       
  2285 		'&macr;' => '&#175;',
       
  2286 		'&hibar;' => '&#175;',
       
  2287 		'&deg;' => '&#176;',
       
  2288 		'&plusmn;' => '&#177;',
       
  2289 		'&sup2;' => '&#178;',
       
  2290 		'&sup3;' => '&#179;',
       
  2291 		'&acute;' => '&#180;',
       
  2292 		'&micro;' => '&#181;',
       
  2293 		'&para;' => '&#182;',
       
  2294 		'&middot;' => '&#183;',
       
  2295 		'&cedil;' => '&#184;',
       
  2296 		'&sup1;' => '&#185;',
       
  2297 		'&ordm;' => '&#186;',
       
  2298 		'&raquo;' => '&#187;',
       
  2299 		'&frac14;' => '&#188;',
       
  2300 		'&frac12;' => '&#189;',
       
  2301 		'&frac34;' => '&#190;',
       
  2302 		'&iquest;' => '&#191;',
       
  2303 		'&Agrave;' => '&#192;',
       
  2304 		'&Aacute;' => '&#193;',
       
  2305 		'&Acirc;' => '&#194;',
       
  2306 		'&Atilde;' => '&#195;',
       
  2307 		'&Auml;' => '&#196;',
       
  2308 		'&Aring;' => '&#197;',
       
  2309 		'&AElig;' => '&#198;',
       
  2310 		'&Ccedil;' => '&#199;',
       
  2311 		'&Egrave;' => '&#200;',
       
  2312 		'&Eacute;' => '&#201;',
       
  2313 		'&Ecirc;' => '&#202;',
       
  2314 		'&Euml;' => '&#203;',
       
  2315 		'&Igrave;' => '&#204;',
       
  2316 		'&Iacute;' => '&#205;',
       
  2317 		'&Icirc;' => '&#206;',
       
  2318 		'&Iuml;' => '&#207;',
       
  2319 		'&ETH;' => '&#208;',
       
  2320 		'&Ntilde;' => '&#209;',
       
  2321 		'&Ograve;' => '&#210;',
       
  2322 		'&Oacute;' => '&#211;',
       
  2323 		'&Ocirc;' => '&#212;',
       
  2324 		'&Otilde;' => '&#213;',
       
  2325 		'&Ouml;' => '&#214;',
       
  2326 		'&times;' => '&#215;',
       
  2327 		'&Oslash;' => '&#216;',
       
  2328 		'&Ugrave;' => '&#217;',
       
  2329 		'&Uacute;' => '&#218;',
       
  2330 		'&Ucirc;' => '&#219;',
       
  2331 		'&Uuml;' => '&#220;',
       
  2332 		'&Yacute;' => '&#221;',
       
  2333 		'&THORN;' => '&#222;',
       
  2334 		'&szlig;' => '&#223;',
       
  2335 		'&agrave;' => '&#224;',
       
  2336 		'&aacute;' => '&#225;',
       
  2337 		'&acirc;' => '&#226;',
       
  2338 		'&atilde;' => '&#227;',
       
  2339 		'&auml;' => '&#228;',
       
  2340 		'&aring;' => '&#229;',
       
  2341 		'&aelig;' => '&#230;',
       
  2342 		'&ccedil;' => '&#231;',
       
  2343 		'&egrave;' => '&#232;',
       
  2344 		'&eacute;' => '&#233;',
       
  2345 		'&ecirc;' => '&#234;',
       
  2346 		'&euml;' => '&#235;',
       
  2347 		'&igrave;' => '&#236;',
       
  2348 		'&iacute;' => '&#237;',
       
  2349 		'&icirc;' => '&#238;',
       
  2350 		'&iuml;' => '&#239;',
       
  2351 		'&eth;' => '&#240;',
       
  2352 		'&ntilde;' => '&#241;',
       
  2353 		'&ograve;' => '&#242;',
       
  2354 		'&oacute;' => '&#243;',
       
  2355 		'&ocirc;' => '&#244;',
       
  2356 		'&otilde;' => '&#245;',
       
  2357 		'&ouml;' => '&#246;',
       
  2358 		'&divide;' => '&#247;',
       
  2359 		'&oslash;' => '&#248;',
       
  2360 		'&ugrave;' => '&#249;',
       
  2361 		'&uacute;' => '&#250;',
       
  2362 		'&ucirc;' => '&#251;',
       
  2363 		'&uuml;' => '&#252;',
       
  2364 		'&yacute;' => '&#253;',
       
  2365 		'&thorn;' => '&#254;',
       
  2366 		'&yuml;' => '&#255;',
       
  2367 		'&OElig;' => '&#338;',
       
  2368 		'&oelig;' => '&#339;',
       
  2369 		'&Scaron;' => '&#352;',
       
  2370 		'&scaron;' => '&#353;',
       
  2371 		'&Yuml;' => '&#376;',
       
  2372 		'&fnof;' => '&#402;',
       
  2373 		'&circ;' => '&#710;',
       
  2374 		'&tilde;' => '&#732;',
       
  2375 		'&Alpha;' => '&#913;',
       
  2376 		'&Beta;' => '&#914;',
       
  2377 		'&Gamma;' => '&#915;',
       
  2378 		'&Delta;' => '&#916;',
       
  2379 		'&Epsilon;' => '&#917;',
       
  2380 		'&Zeta;' => '&#918;',
       
  2381 		'&Eta;' => '&#919;',
       
  2382 		'&Theta;' => '&#920;',
       
  2383 		'&Iota;' => '&#921;',
       
  2384 		'&Kappa;' => '&#922;',
       
  2385 		'&Lambda;' => '&#923;',
       
  2386 		'&Mu;' => '&#924;',
       
  2387 		'&Nu;' => '&#925;',
       
  2388 		'&Xi;' => '&#926;',
       
  2389 		'&Omicron;' => '&#927;',
       
  2390 		'&Pi;' => '&#928;',
       
  2391 		'&Rho;' => '&#929;',
       
  2392 		'&Sigma;' => '&#931;',
       
  2393 		'&Tau;' => '&#932;',
       
  2394 		'&Upsilon;' => '&#933;',
       
  2395 		'&Phi;' => '&#934;',
       
  2396 		'&Chi;' => '&#935;',
       
  2397 		'&Psi;' => '&#936;',
       
  2398 		'&Omega;' => '&#937;',
       
  2399 		'&alpha;' => '&#945;',
       
  2400 		'&beta;' => '&#946;',
       
  2401 		'&gamma;' => '&#947;',
       
  2402 		'&delta;' => '&#948;',
       
  2403 		'&epsilon;' => '&#949;',
       
  2404 		'&zeta;' => '&#950;',
       
  2405 		'&eta;' => '&#951;',
       
  2406 		'&theta;' => '&#952;',
       
  2407 		'&iota;' => '&#953;',
       
  2408 		'&kappa;' => '&#954;',
       
  2409 		'&lambda;' => '&#955;',
       
  2410 		'&mu;' => '&#956;',
       
  2411 		'&nu;' => '&#957;',
       
  2412 		'&xi;' => '&#958;',
       
  2413 		'&omicron;' => '&#959;',
       
  2414 		'&pi;' => '&#960;',
       
  2415 		'&rho;' => '&#961;',
       
  2416 		'&sigmaf;' => '&#962;',
       
  2417 		'&sigma;' => '&#963;',
       
  2418 		'&tau;' => '&#964;',
       
  2419 		'&upsilon;' => '&#965;',
       
  2420 		'&phi;' => '&#966;',
       
  2421 		'&chi;' => '&#967;',
       
  2422 		'&psi;' => '&#968;',
       
  2423 		'&omega;' => '&#969;',
       
  2424 		'&thetasym;' => '&#977;',
       
  2425 		'&upsih;' => '&#978;',
       
  2426 		'&piv;' => '&#982;',
       
  2427 		'&ensp;' => '&#8194;',
       
  2428 		'&emsp;' => '&#8195;',
       
  2429 		'&thinsp;' => '&#8201;',
       
  2430 		'&zwnj;' => '&#8204;',
       
  2431 		'&zwj;' => '&#8205;',
       
  2432 		'&lrm;' => '&#8206;',
       
  2433 		'&rlm;' => '&#8207;',
       
  2434 		'&ndash;' => '&#8211;',
       
  2435 		'&mdash;' => '&#8212;',
       
  2436 		'&lsquo;' => '&#8216;',
       
  2437 		'&rsquo;' => '&#8217;',
       
  2438 		'&sbquo;' => '&#8218;',
       
  2439 		'&ldquo;' => '&#8220;',
       
  2440 		'&rdquo;' => '&#8221;',
       
  2441 		'&bdquo;' => '&#8222;',
       
  2442 		'&dagger;' => '&#8224;',
       
  2443 		'&Dagger;' => '&#8225;',
       
  2444 		'&bull;' => '&#8226;',
       
  2445 		'&hellip;' => '&#8230;',
       
  2446 		'&permil;' => '&#8240;',
       
  2447 		'&prime;' => '&#8242;',
       
  2448 		'&Prime;' => '&#8243;',
       
  2449 		'&lsaquo;' => '&#8249;',
       
  2450 		'&rsaquo;' => '&#8250;',
       
  2451 		'&oline;' => '&#8254;',
       
  2452 		'&frasl;' => '&#8260;',
       
  2453 		'&euro;' => '&#8364;',
       
  2454 		'&image;' => '&#8465;',
       
  2455 		'&weierp;' => '&#8472;',
       
  2456 		'&real;' => '&#8476;',
       
  2457 		'&trade;' => '&#8482;',
       
  2458 		'&alefsym;' => '&#8501;',
       
  2459 		'&crarr;' => '&#8629;',
       
  2460 		'&lArr;' => '&#8656;',
       
  2461 		'&uArr;' => '&#8657;',
       
  2462 		'&rArr;' => '&#8658;',
       
  2463 		'&dArr;' => '&#8659;',
       
  2464 		'&hArr;' => '&#8660;',
       
  2465 		'&forall;' => '&#8704;',
       
  2466 		'&part;' => '&#8706;',
       
  2467 		'&exist;' => '&#8707;',
       
  2468 		'&empty;' => '&#8709;',
       
  2469 		'&nabla;' => '&#8711;',
       
  2470 		'&isin;' => '&#8712;',
       
  2471 		'&notin;' => '&#8713;',
       
  2472 		'&ni;' => '&#8715;',
       
  2473 		'&prod;' => '&#8719;',
       
  2474 		'&sum;' => '&#8721;',
       
  2475 		'&minus;' => '&#8722;',
       
  2476 		'&lowast;' => '&#8727;',
       
  2477 		'&radic;' => '&#8730;',
       
  2478 		'&prop;' => '&#8733;',
       
  2479 		'&infin;' => '&#8734;',
       
  2480 		'&ang;' => '&#8736;',
       
  2481 		'&and;' => '&#8743;',
       
  2482 		'&or;' => '&#8744;',
       
  2483 		'&cap;' => '&#8745;',
       
  2484 		'&cup;' => '&#8746;',
       
  2485 		'&int;' => '&#8747;',
       
  2486 		'&there4;' => '&#8756;',
       
  2487 		'&sim;' => '&#8764;',
       
  2488 		'&cong;' => '&#8773;',
       
  2489 		'&asymp;' => '&#8776;',
       
  2490 		'&ne;' => '&#8800;',
       
  2491 		'&equiv;' => '&#8801;',
       
  2492 		'&le;' => '&#8804;',
       
  2493 		'&ge;' => '&#8805;',
       
  2494 		'&sub;' => '&#8834;',
       
  2495 		'&sup;' => '&#8835;',
       
  2496 		'&nsub;' => '&#8836;',
       
  2497 		'&sube;' => '&#8838;',
       
  2498 		'&supe;' => '&#8839;',
       
  2499 		'&oplus;' => '&#8853;',
       
  2500 		'&otimes;' => '&#8855;',
       
  2501 		'&perp;' => '&#8869;',
       
  2502 		'&sdot;' => '&#8901;',
       
  2503 		'&lceil;' => '&#8968;',
       
  2504 		'&rceil;' => '&#8969;',
       
  2505 		'&lfloor;' => '&#8970;',
       
  2506 		'&rfloor;' => '&#8971;',
       
  2507 		'&lang;' => '&#9001;',
       
  2508 		'&rang;' => '&#9002;',
       
  2509 		'&larr;' => '&#8592;',
       
  2510 		'&uarr;' => '&#8593;',
       
  2511 		'&rarr;' => '&#8594;',
       
  2512 		'&darr;' => '&#8595;',
       
  2513 		'&harr;' => '&#8596;',
       
  2514 		'&loz;' => '&#9674;',
       
  2515 		'&spades;' => '&#9824;',
       
  2516 		'&clubs;' => '&#9827;',
       
  2517 		'&hearts;' => '&#9829;',
       
  2518 		'&diams;' => '&#9830;'
       
  2519 	);
       
  2520 
       
  2521 	return str_replace( array_keys($to_ncr), array_values($to_ncr), $text );
       
  2522 }
       
  2523 
       
  2524 /**
       
  2525  * Formats text for the rich text editor.
       
  2526  *
       
  2527  * The filter 'richedit_pre' is applied here. If $text is empty the filter will
       
  2528  * be applied to an empty string.
       
  2529  *
       
  2530  * @since 2.0.0
       
  2531  *
       
  2532  * @param string $text The text to be formatted.
       
  2533  * @return string The formatted text after filter is applied.
       
  2534  */
       
  2535 function wp_richedit_pre($text) {
       
  2536 	// Filtering a blank results in an annoying <br />\n
       
  2537 	if ( empty($text) ) return apply_filters('richedit_pre', '');
       
  2538 
       
  2539 	$output = convert_chars($text);
       
  2540 	$output = wpautop($output);
       
  2541 	$output = htmlspecialchars($output, ENT_NOQUOTES, get_option( 'blog_charset' ) );
       
  2542 
       
  2543 	return apply_filters('richedit_pre', $output);
       
  2544 }
       
  2545 
       
  2546 /**
       
  2547  * Formats text for the HTML editor.
       
  2548  *
       
  2549  * Unless $output is empty it will pass through htmlspecialchars before the
       
  2550  * 'htmledit_pre' filter is applied.
       
  2551  *
       
  2552  * @since 2.5.0
       
  2553  *
       
  2554  * @param string $output The text to be formatted.
       
  2555  * @return string Formatted text after filter applied.
       
  2556  */
       
  2557 function wp_htmledit_pre($output) {
       
  2558 	if ( !empty($output) )
       
  2559 		$output = htmlspecialchars($output, ENT_NOQUOTES, get_option( 'blog_charset' ) ); // convert only < > &
       
  2560 
       
  2561 	return apply_filters('htmledit_pre', $output);
       
  2562 }
       
  2563 
       
  2564 /**
       
  2565  * Perform a deep string replace operation to ensure the values in $search are no longer present
       
  2566  *
       
  2567  * Repeats the replacement operation until it no longer replaces anything so as to remove "nested" values
       
  2568  * e.g. $subject = '%0%0%0DDD', $search ='%0D', $result ='' rather than the '%0%0DD' that
       
  2569  * str_replace would return
       
  2570  *
       
  2571  * @since 2.8.1
       
  2572  * @access private
       
  2573  *
       
  2574  * @param string|array $search The value being searched for, otherwise known as the needle. An array may be used to designate multiple needles.
       
  2575  * @param string $subject The string being searched and replaced on, otherwise known as the haystack.
       
  2576  * @return string The string with the replaced svalues.
       
  2577  */
       
  2578 function _deep_replace( $search, $subject ) {
       
  2579 	$subject = (string) $subject;
       
  2580 
       
  2581 	$count = 1;
       
  2582 	while ( $count ) {
       
  2583 		$subject = str_replace( $search, '', $subject, $count );
       
  2584 	}
       
  2585 
       
  2586 	return $subject;
       
  2587 }
       
  2588 
       
  2589 /**
       
  2590  * Escapes data for use in a MySQL query.
       
  2591  *
       
  2592  * Usually you should prepare queries using wpdb::prepare().
       
  2593  * Sometimes, spot-escaping is required or useful. One example
       
  2594  * is preparing an array for use in an IN clause.
       
  2595  *
       
  2596  * @since 2.8.0
       
  2597  * @param string|array $data Unescaped data
       
  2598  * @return string|array Escaped data
       
  2599  */
       
  2600 function esc_sql( $data ) {
       
  2601 	global $wpdb;
       
  2602 	return $wpdb->_escape( $data );
       
  2603 }
       
  2604 
       
  2605 /**
       
  2606  * Checks and cleans a URL.
       
  2607  *
       
  2608  * A number of characters are removed from the URL. If the URL is for displaying
       
  2609  * (the default behaviour) ampersands are also replaced. The 'clean_url' filter
       
  2610  * is applied to the returned cleaned URL.
       
  2611  *
       
  2612  * @since 2.8.0
       
  2613  * @uses wp_kses_bad_protocol() To only permit protocols in the URL set
       
  2614  *		via $protocols or the common ones set in the function.
       
  2615  *
       
  2616  * @param string $url The URL to be cleaned.
       
  2617  * @param array $protocols Optional. An array of acceptable protocols.
       
  2618  *		Defaults to 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn' if not set.
       
  2619  * @param string $_context Private. Use esc_url_raw() for database usage.
       
  2620  * @return string The cleaned $url after the 'clean_url' filter is applied.
       
  2621  */
       
  2622 function esc_url( $url, $protocols = null, $_context = 'display' ) {
       
  2623 	$original_url = $url;
       
  2624 
       
  2625 	if ( '' == $url )
       
  2626 		return $url;
       
  2627 	$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url);
       
  2628 	$strip = array('%0d', '%0a', '%0D', '%0A');
       
  2629 	$url = _deep_replace($strip, $url);
       
  2630 	$url = str_replace(';//', '://', $url);
       
  2631 	/* If the URL doesn't appear to contain a scheme, we
       
  2632 	 * presume it needs http:// appended (unless a relative
       
  2633 	 * link starting with /, # or ? or a php file).
       
  2634 	 */
       
  2635 	if ( strpos($url, ':') === false && ! in_array( $url[0], array( '/', '#', '?' ) ) &&
       
  2636 		! preg_match('/^[a-z0-9-]+?\.php/i', $url) )
       
  2637 		$url = 'http://' . $url;
       
  2638 
       
  2639 	// Replace ampersands and single quotes only when displaying.
       
  2640 	if ( 'display' == $_context ) {
       
  2641 		$url = wp_kses_normalize_entities( $url );
       
  2642 		$url = str_replace( '&amp;', '&#038;', $url );
       
  2643 		$url = str_replace( "'", '&#039;', $url );
       
  2644 	}
       
  2645 
       
  2646 	if ( '/' === $url[0] ) {
       
  2647 		$good_protocol_url = $url;
       
  2648 	} else {
       
  2649 		if ( ! is_array( $protocols ) )
       
  2650 			$protocols = wp_allowed_protocols();
       
  2651 		$good_protocol_url = wp_kses_bad_protocol( $url, $protocols );
       
  2652 		if ( strtolower( $good_protocol_url ) != strtolower( $url ) )
       
  2653 			return '';
       
  2654 	}
       
  2655 
       
  2656 	return apply_filters('clean_url', $good_protocol_url, $original_url, $_context);
       
  2657 }
       
  2658 
       
  2659 /**
       
  2660  * Performs esc_url() for database usage.
       
  2661  *
       
  2662  * @since 2.8.0
       
  2663  * @uses esc_url()
       
  2664  *
       
  2665  * @param string $url The URL to be cleaned.
       
  2666  * @param array $protocols An array of acceptable protocols.
       
  2667  * @return string The cleaned URL.
       
  2668  */
       
  2669 function esc_url_raw( $url, $protocols = null ) {
       
  2670 	return esc_url( $url, $protocols, 'db' );
       
  2671 }
       
  2672 
       
  2673 /**
       
  2674  * Convert entities, while preserving already-encoded entities.
       
  2675  *
       
  2676  * @link http://www.php.net/htmlentities Borrowed from the PHP Manual user notes.
       
  2677  *
       
  2678  * @since 1.2.2
       
  2679  *
       
  2680  * @param string $myHTML The text to be converted.
       
  2681  * @return string Converted text.
       
  2682  */
       
  2683 function htmlentities2($myHTML) {
       
  2684 	$translation_table = get_html_translation_table( HTML_ENTITIES, ENT_QUOTES );
       
  2685 	$translation_table[chr(38)] = '&';
       
  2686 	return preg_replace( "/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/", "&amp;", strtr($myHTML, $translation_table) );
       
  2687 }
       
  2688 
       
  2689 /**
       
  2690  * Escape single quotes, htmlspecialchar " < > &, and fix line endings.
       
  2691  *
       
  2692  * Escapes text strings for echoing in JS. It is intended to be used for inline JS
       
  2693  * (in a tag attribute, for example onclick="..."). Note that the strings have to
       
  2694  * be in single quotes. The filter 'js_escape' is also applied here.
       
  2695  *
       
  2696  * @since 2.8.0
       
  2697  *
       
  2698  * @param string $text The text to be escaped.
       
  2699  * @return string Escaped text.
       
  2700  */
       
  2701 function esc_js( $text ) {
       
  2702 	$safe_text = wp_check_invalid_utf8( $text );
       
  2703 	$safe_text = _wp_specialchars( $safe_text, ENT_COMPAT );
       
  2704 	$safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes( $safe_text ) );
       
  2705 	$safe_text = str_replace( "\r", '', $safe_text );
       
  2706 	$safe_text = str_replace( "\n", '\\n', addslashes( $safe_text ) );
       
  2707 	return apply_filters( 'js_escape', $safe_text, $text );
       
  2708 }
       
  2709 
       
  2710 /**
       
  2711  * Escaping for HTML blocks.
       
  2712  *
       
  2713  * @since 2.8.0
       
  2714  *
       
  2715  * @param string $text
       
  2716  * @return string
       
  2717  */
       
  2718 function esc_html( $text ) {
       
  2719 	$safe_text = wp_check_invalid_utf8( $text );
       
  2720 	$safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
       
  2721 	return apply_filters( 'esc_html', $safe_text, $text );
       
  2722 }
       
  2723 
       
  2724 /**
       
  2725  * Escaping for HTML attributes.
       
  2726  *
       
  2727  * @since 2.8.0
       
  2728  *
       
  2729  * @param string $text
       
  2730  * @return string
       
  2731  */
       
  2732 function esc_attr( $text ) {
       
  2733 	$safe_text = wp_check_invalid_utf8( $text );
       
  2734 	$safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
       
  2735 	return apply_filters( 'attribute_escape', $safe_text, $text );
       
  2736 }
       
  2737 
       
  2738 /**
       
  2739  * Escaping for textarea values.
       
  2740  *
       
  2741  * @since 3.1.0
       
  2742  *
       
  2743  * @param string $text
       
  2744  * @return string
       
  2745  */
       
  2746 function esc_textarea( $text ) {
       
  2747 	$safe_text = htmlspecialchars( $text, ENT_QUOTES, get_option( 'blog_charset' ) );
       
  2748 	return apply_filters( 'esc_textarea', $safe_text, $text );
       
  2749 }
       
  2750 
       
  2751 /**
       
  2752  * Escape an HTML tag name.
       
  2753  *
       
  2754  * @since 2.5.0
       
  2755  *
       
  2756  * @param string $tag_name
       
  2757  * @return string
       
  2758  */
       
  2759 function tag_escape($tag_name) {
       
  2760 	$safe_tag = strtolower( preg_replace('/[^a-zA-Z0-9_:]/', '', $tag_name) );
       
  2761 	return apply_filters('tag_escape', $safe_tag, $tag_name);
       
  2762 }
       
  2763 
       
  2764 /**
       
  2765  * Escapes text for SQL LIKE special characters % and _.
       
  2766  *
       
  2767  * @since 2.5.0
       
  2768  *
       
  2769  * @param string $text The text to be escaped.
       
  2770  * @return string text, safe for inclusion in LIKE query.
       
  2771  */
       
  2772 function like_escape($text) {
       
  2773 	return str_replace(array("%", "_"), array("\\%", "\\_"), $text);
       
  2774 }
       
  2775 
       
  2776 /**
       
  2777  * Convert full URL paths to absolute paths.
       
  2778  *
       
  2779  * Removes the http or https protocols and the domain. Keeps the path '/' at the
       
  2780  * beginning, so it isn't a true relative link, but from the web root base.
       
  2781  *
       
  2782  * @since 2.1.0
       
  2783  *
       
  2784  * @param string $link Full URL path.
       
  2785  * @return string Absolute path.
       
  2786  */
       
  2787 function wp_make_link_relative( $link ) {
       
  2788 	return preg_replace( '|https?://[^/]+(/.*)|i', '$1', $link );
       
  2789 }
       
  2790 
       
  2791 /**
       
  2792  * Sanitises various option values based on the nature of the option.
       
  2793  *
       
  2794  * This is basically a switch statement which will pass $value through a number
       
  2795  * of functions depending on the $option.
       
  2796  *
       
  2797  * @since 2.0.5
       
  2798  *
       
  2799  * @param string $option The name of the option.
       
  2800  * @param string $value The unsanitised value.
       
  2801  * @return string Sanitized value.
       
  2802  */
       
  2803 function sanitize_option($option, $value) {
       
  2804 
       
  2805 	switch ( $option ) {
       
  2806 		case 'admin_email' :
       
  2807 		case 'new_admin_email' :
       
  2808 			$value = sanitize_email( $value );
       
  2809 			if ( ! is_email( $value ) ) {
       
  2810 				$value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
       
  2811 				if ( function_exists( 'add_settings_error' ) )
       
  2812 					add_settings_error( $option, 'invalid_admin_email', __( 'The email address entered did not appear to be a valid email address. Please enter a valid email address.' ) );
       
  2813 			}
       
  2814 			break;
       
  2815 
       
  2816 		case 'thumbnail_size_w':
       
  2817 		case 'thumbnail_size_h':
       
  2818 		case 'medium_size_w':
       
  2819 		case 'medium_size_h':
       
  2820 		case 'large_size_w':
       
  2821 		case 'large_size_h':
       
  2822 		case 'mailserver_port':
       
  2823 		case 'comment_max_links':
       
  2824 		case 'page_on_front':
       
  2825 		case 'page_for_posts':
       
  2826 		case 'rss_excerpt_length':
       
  2827 		case 'default_category':
       
  2828 		case 'default_email_category':
       
  2829 		case 'default_link_category':
       
  2830 		case 'close_comments_days_old':
       
  2831 		case 'comments_per_page':
       
  2832 		case 'thread_comments_depth':
       
  2833 		case 'users_can_register':
       
  2834 		case 'start_of_week':
       
  2835 			$value = absint( $value );
       
  2836 			break;
       
  2837 
       
  2838 		case 'posts_per_page':
       
  2839 		case 'posts_per_rss':
       
  2840 			$value = (int) $value;
       
  2841 			if ( empty($value) )
       
  2842 				$value = 1;
       
  2843 			if ( $value < -1 )
       
  2844 				$value = abs($value);
       
  2845 			break;
       
  2846 
       
  2847 		case 'default_ping_status':
       
  2848 		case 'default_comment_status':
       
  2849 			// Options that if not there have 0 value but need to be something like "closed"
       
  2850 			if ( $value == '0' || $value == '')
       
  2851 				$value = 'closed';
       
  2852 			break;
       
  2853 
       
  2854 		case 'blogdescription':
       
  2855 		case 'blogname':
       
  2856 			$value = wp_kses_post( $value );
       
  2857 			$value = esc_html( $value );
       
  2858 			break;
       
  2859 
       
  2860 		case 'blog_charset':
       
  2861 			$value = preg_replace('/[^a-zA-Z0-9_-]/', '', $value); // strips slashes
       
  2862 			break;
       
  2863 
       
  2864 		case 'blog_public':
       
  2865 			// This is the value if the settings checkbox is not checked on POST. Don't rely on this.
       
  2866 			if ( null === $value )
       
  2867 				$value = 1;
       
  2868 			else
       
  2869 				$value = intval( $value );
       
  2870 			break;
       
  2871 
       
  2872 		case 'date_format':
       
  2873 		case 'time_format':
       
  2874 		case 'mailserver_url':
       
  2875 		case 'mailserver_login':
       
  2876 		case 'mailserver_pass':
       
  2877 		case 'upload_path':
       
  2878 			$value = strip_tags( $value );
       
  2879 			$value = wp_kses_data( $value );
       
  2880 			break;
       
  2881 
       
  2882 		case 'ping_sites':
       
  2883 			$value = explode( "\n", $value );
       
  2884 			$value = array_filter( array_map( 'trim', $value ) );
       
  2885 			$value = array_filter( array_map( 'esc_url_raw', $value ) );
       
  2886 			$value = implode( "\n", $value );
       
  2887 			break;
       
  2888 
       
  2889 		case 'gmt_offset':
       
  2890 			$value = preg_replace('/[^0-9:.-]/', '', $value); // strips slashes
       
  2891 			break;
       
  2892 
       
  2893 		case 'siteurl':
       
  2894 			if ( (bool)preg_match( '#http(s?)://(.+)#i', $value) ) {
       
  2895 				$value = esc_url_raw($value);
       
  2896 			} else {
       
  2897 				$value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
       
  2898 				if ( function_exists('add_settings_error') )
       
  2899 					add_settings_error('siteurl', 'invalid_siteurl', __('The WordPress address you entered did not appear to be a valid URL. Please enter a valid URL.'));
       
  2900 			}
       
  2901 			break;
       
  2902 
       
  2903 		case 'home':
       
  2904 			if ( (bool)preg_match( '#http(s?)://(.+)#i', $value) ) {
       
  2905 				$value = esc_url_raw($value);
       
  2906 			} else {
       
  2907 				$value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
       
  2908 				if ( function_exists('add_settings_error') )
       
  2909 					add_settings_error('home', 'invalid_home', __('The Site address you entered did not appear to be a valid URL. Please enter a valid URL.'));
       
  2910 			}
       
  2911 			break;
       
  2912 
       
  2913 		case 'WPLANG':
       
  2914 			$allowed = get_available_languages();
       
  2915 			if ( ! in_array( $value, $allowed ) && ! empty( $value ) )
       
  2916 				$value = get_option( $option );
       
  2917 			break;
       
  2918 
       
  2919 		case 'illegal_names':
       
  2920 			if ( ! is_array( $value ) )
       
  2921 				$value = explode( ' ', $value );
       
  2922 
       
  2923 			$value = array_values( array_filter( array_map( 'trim', $value ) ) );
       
  2924 
       
  2925 			if ( ! $value )
       
  2926 				$value = '';
       
  2927 			break;
       
  2928 
       
  2929 		case 'limited_email_domains':
       
  2930 		case 'banned_email_domains':
       
  2931 			if ( ! is_array( $value ) )
       
  2932 				$value = explode( "\n", $value );
       
  2933 
       
  2934 			$domains = array_values( array_filter( array_map( 'trim', $value ) ) );
       
  2935 			$value = array();
       
  2936 
       
  2937 			foreach ( $domains as $domain ) {
       
  2938 				if ( ! preg_match( '/(--|\.\.)/', $domain ) && preg_match( '|^([a-zA-Z0-9-\.])+$|', $domain ) )
       
  2939 					$value[] = $domain;
       
  2940 			}
       
  2941 			if ( ! $value )
       
  2942 				$value = '';
       
  2943 			break;
       
  2944 
       
  2945 		case 'timezone_string':
       
  2946 			$allowed_zones = timezone_identifiers_list();
       
  2947 			if ( ! in_array( $value, $allowed_zones ) && ! empty( $value ) ) {
       
  2948 				$value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
       
  2949 				if ( function_exists('add_settings_error') )
       
  2950 					add_settings_error('timezone_string', 'invalid_timezone_string', __('The timezone you have entered is not valid. Please select a valid timezone.') );
       
  2951 			}
       
  2952 			break;
       
  2953 
       
  2954 		case 'permalink_structure':
       
  2955 		case 'category_base':
       
  2956 		case 'tag_base':
       
  2957 			$value = esc_url_raw( $value );
       
  2958 			$value = str_replace( 'http://', '', $value );
       
  2959 			break;
       
  2960 
       
  2961 		case 'default_role' :
       
  2962 			if ( ! get_role( $value ) && get_role( 'subscriber' ) )
       
  2963 				$value = 'subscriber';
       
  2964 			break;
       
  2965 	}
       
  2966 
       
  2967 	$value = apply_filters("sanitize_option_{$option}", $value, $option);
       
  2968 
       
  2969 	return $value;
       
  2970 }
       
  2971 
       
  2972 /**
       
  2973  * Parses a string into variables to be stored in an array.
       
  2974  *
       
  2975  * Uses {@link http://www.php.net/parse_str parse_str()} and stripslashes if
       
  2976  * {@link http://www.php.net/magic_quotes magic_quotes_gpc} is on.
       
  2977  *
       
  2978  * @since 2.2.1
       
  2979  * @uses apply_filters() for the 'wp_parse_str' filter.
       
  2980  *
       
  2981  * @param string $string The string to be parsed.
       
  2982  * @param array $array Variables will be stored in this array.
       
  2983  */
       
  2984 function wp_parse_str( $string, &$array ) {
       
  2985 	parse_str( $string, $array );
       
  2986 	if ( get_magic_quotes_gpc() )
       
  2987 		$array = stripslashes_deep( $array );
       
  2988 	$array = apply_filters( 'wp_parse_str', $array );
       
  2989 }
       
  2990 
       
  2991 /**
       
  2992  * Convert lone less than signs.
       
  2993  *
       
  2994  * KSES already converts lone greater than signs.
       
  2995  *
       
  2996  * @uses wp_pre_kses_less_than_callback in the callback function.
       
  2997  * @since 2.3.0
       
  2998  *
       
  2999  * @param string $text Text to be converted.
       
  3000  * @return string Converted text.
       
  3001  */
       
  3002 function wp_pre_kses_less_than( $text ) {
       
  3003 	return preg_replace_callback('%<[^>]*?((?=<)|>|$)%', 'wp_pre_kses_less_than_callback', $text);
       
  3004 }
       
  3005 
       
  3006 /**
       
  3007  * Callback function used by preg_replace.
       
  3008  *
       
  3009  * @uses esc_html to format the $matches text.
       
  3010  * @since 2.3.0
       
  3011  *
       
  3012  * @param array $matches Populated by matches to preg_replace.
       
  3013  * @return string The text returned after esc_html if needed.
       
  3014  */
       
  3015 function wp_pre_kses_less_than_callback( $matches ) {
       
  3016 	if ( false === strpos($matches[0], '>') )
       
  3017 		return esc_html($matches[0]);
       
  3018 	return $matches[0];
       
  3019 }
       
  3020 
       
  3021 /**
       
  3022  * WordPress implementation of PHP sprintf() with filters.
       
  3023  *
       
  3024  * @since 2.5.0
       
  3025  * @link http://www.php.net/sprintf
       
  3026  *
       
  3027  * @param string $pattern The string which formatted args are inserted.
       
  3028  * @param mixed $args,... Arguments to be formatted into the $pattern string.
       
  3029  * @return string The formatted string.
       
  3030  */
       
  3031 function wp_sprintf( $pattern ) {
       
  3032 	$args = func_get_args();
       
  3033 	$len = strlen($pattern);
       
  3034 	$start = 0;
       
  3035 	$result = '';
       
  3036 	$arg_index = 0;
       
  3037 	while ( $len > $start ) {
       
  3038 		// Last character: append and break
       
  3039 		if ( strlen($pattern) - 1 == $start ) {
       
  3040 			$result .= substr($pattern, -1);
       
  3041 			break;
       
  3042 		}
       
  3043 
       
  3044 		// Literal %: append and continue
       
  3045 		if ( substr($pattern, $start, 2) == '%%' ) {
       
  3046 			$start += 2;
       
  3047 			$result .= '%';
       
  3048 			continue;
       
  3049 		}
       
  3050 
       
  3051 		// Get fragment before next %
       
  3052 		$end = strpos($pattern, '%', $start + 1);
       
  3053 		if ( false === $end )
       
  3054 			$end = $len;
       
  3055 		$fragment = substr($pattern, $start, $end - $start);
       
  3056 
       
  3057 		// Fragment has a specifier
       
  3058 		if ( $pattern[$start] == '%' ) {
       
  3059 			// Find numbered arguments or take the next one in order
       
  3060 			if ( preg_match('/^%(\d+)\$/', $fragment, $matches) ) {
       
  3061 				$arg = isset($args[$matches[1]]) ? $args[$matches[1]] : '';
       
  3062 				$fragment = str_replace("%{$matches[1]}$", '%', $fragment);
       
  3063 			} else {
       
  3064 				++$arg_index;
       
  3065 				$arg = isset($args[$arg_index]) ? $args[$arg_index] : '';
       
  3066 			}
       
  3067 
       
  3068 			// Apply filters OR sprintf
       
  3069 			$_fragment = apply_filters( 'wp_sprintf', $fragment, $arg );
       
  3070 			if ( $_fragment != $fragment )
       
  3071 				$fragment = $_fragment;
       
  3072 			else
       
  3073 				$fragment = sprintf($fragment, strval($arg) );
       
  3074 		}
       
  3075 
       
  3076 		// Append to result and move to next fragment
       
  3077 		$result .= $fragment;
       
  3078 		$start = $end;
       
  3079 	}
       
  3080 	return $result;
       
  3081 }
       
  3082 
       
  3083 /**
       
  3084  * Localize list items before the rest of the content.
       
  3085  *
       
  3086  * The '%l' must be at the first characters can then contain the rest of the
       
  3087  * content. The list items will have ', ', ', and', and ' and ' added depending
       
  3088  * on the amount of list items in the $args parameter.
       
  3089  *
       
  3090  * @since 2.5.0
       
  3091  *
       
  3092  * @param string $pattern Content containing '%l' at the beginning.
       
  3093  * @param array $args List items to prepend to the content and replace '%l'.
       
  3094  * @return string Localized list items and rest of the content.
       
  3095  */
       
  3096 function wp_sprintf_l($pattern, $args) {
       
  3097 	// Not a match
       
  3098 	if ( substr($pattern, 0, 2) != '%l' )
       
  3099 		return $pattern;
       
  3100 
       
  3101 	// Nothing to work with
       
  3102 	if ( empty($args) )
       
  3103 		return '';
       
  3104 
       
  3105 	// Translate and filter the delimiter set (avoid ampersands and entities here)
       
  3106 	$l = apply_filters('wp_sprintf_l', array(
       
  3107 		/* translators: used between list items, there is a space after the comma */
       
  3108 		'between'          => __(', '),
       
  3109 		/* translators: used between list items, there is a space after the and */
       
  3110 		'between_last_two' => __(', and '),
       
  3111 		/* translators: used between only two list items, there is a space after the and */
       
  3112 		'between_only_two' => __(' and '),
       
  3113 		));
       
  3114 
       
  3115 	$args = (array) $args;
       
  3116 	$result = array_shift($args);
       
  3117 	if ( count($args) == 1 )
       
  3118 		$result .= $l['between_only_two'] . array_shift($args);
       
  3119 	// Loop when more than two args
       
  3120 	$i = count($args);
       
  3121 	while ( $i ) {
       
  3122 		$arg = array_shift($args);
       
  3123 		$i--;
       
  3124 		if ( 0 == $i )
       
  3125 			$result .= $l['between_last_two'] . $arg;
       
  3126 		else
       
  3127 			$result .= $l['between'] . $arg;
       
  3128 	}
       
  3129 	return $result . substr($pattern, 2);
       
  3130 }
       
  3131 
       
  3132 /**
       
  3133  * Safely extracts not more than the first $count characters from html string.
       
  3134  *
       
  3135  * UTF-8, tags and entities safe prefix extraction. Entities inside will *NOT*
       
  3136  * be counted as one character. For example &amp; will be counted as 4, &lt; as
       
  3137  * 3, etc.
       
  3138  *
       
  3139  * @since 2.5.0
       
  3140  *
       
  3141  * @param string $str String to get the excerpt from.
       
  3142  * @param integer $count Maximum number of characters to take.
       
  3143  * @param string $more Optional. What to append if $str needs to be trimmed. Defaults to empty string.
       
  3144  * @return string The excerpt.
       
  3145  */
       
  3146 function wp_html_excerpt( $str, $count, $more = null ) {
       
  3147 	if ( null === $more )
       
  3148 		$more = '';
       
  3149 	$str = wp_strip_all_tags( $str, true );
       
  3150 	$excerpt = mb_substr( $str, 0, $count );
       
  3151 	// remove part of an entity at the end
       
  3152 	$excerpt = preg_replace( '/&[^;\s]{0,6}$/', '', $excerpt );
       
  3153 	if ( $str != $excerpt )
       
  3154 		$excerpt = trim( $excerpt ) . $more;
       
  3155 	return $excerpt;
       
  3156 }
       
  3157 
       
  3158 /**
       
  3159  * Add a Base url to relative links in passed content.
       
  3160  *
       
  3161  * By default it supports the 'src' and 'href' attributes. However this can be
       
  3162  * changed via the 3rd param.
       
  3163  *
       
  3164  * @since 2.7.0
       
  3165  *
       
  3166  * @param string $content String to search for links in.
       
  3167  * @param string $base The base URL to prefix to links.
       
  3168  * @param array $attrs The attributes which should be processed.
       
  3169  * @return string The processed content.
       
  3170  */
       
  3171 function links_add_base_url( $content, $base, $attrs = array('src', 'href') ) {
       
  3172 	global $_links_add_base;
       
  3173 	$_links_add_base = $base;
       
  3174 	$attrs = implode('|', (array)$attrs);
       
  3175 	return preg_replace_callback( "!($attrs)=(['\"])(.+?)\\2!i", '_links_add_base', $content );
       
  3176 }
       
  3177 
       
  3178 /**
       
  3179  * Callback to add a base url to relative links in passed content.
       
  3180  *
       
  3181  * @since 2.7.0
       
  3182  * @access private
       
  3183  *
       
  3184  * @param string $m The matched link.
       
  3185  * @return string The processed link.
       
  3186  */
       
  3187 function _links_add_base($m) {
       
  3188 	global $_links_add_base;
       
  3189 	//1 = attribute name  2 = quotation mark  3 = URL
       
  3190 	return $m[1] . '=' . $m[2] .
       
  3191 		( preg_match( '#^(\w{1,20}):#', $m[3], $protocol ) && in_array( $protocol[1], wp_allowed_protocols() ) ?
       
  3192 			$m[3] :
       
  3193 			path_join( $_links_add_base, $m[3] ) )
       
  3194 		. $m[2];
       
  3195 }
       
  3196 
       
  3197 /**
       
  3198  * Adds a Target attribute to all links in passed content.
       
  3199  *
       
  3200  * This function by default only applies to <a> tags, however this can be
       
  3201  * modified by the 3rd param.
       
  3202  *
       
  3203  * <b>NOTE:</b> Any current target attributed will be stripped and replaced.
       
  3204  *
       
  3205  * @since 2.7.0
       
  3206  *
       
  3207  * @param string $content String to search for links in.
       
  3208  * @param string $target The Target to add to the links.
       
  3209  * @param array $tags An array of tags to apply to.
       
  3210  * @return string The processed content.
       
  3211  */
       
  3212 function links_add_target( $content, $target = '_blank', $tags = array('a') ) {
       
  3213 	global $_links_add_target;
       
  3214 	$_links_add_target = $target;
       
  3215 	$tags = implode('|', (array)$tags);
       
  3216 	return preg_replace_callback( "!<($tags)(.+?)>!i", '_links_add_target', $content );
       
  3217 }
       
  3218 
       
  3219 /**
       
  3220  * Callback to add a target attribute to all links in passed content.
       
  3221  *
       
  3222  * @since 2.7.0
       
  3223  * @access private
       
  3224  *
       
  3225  * @param string $m The matched link.
       
  3226  * @return string The processed link.
       
  3227  */
       
  3228 function _links_add_target( $m ) {
       
  3229 	global $_links_add_target;
       
  3230 	$tag = $m[1];
       
  3231 	$link = preg_replace('|(target=([\'"])(.*?)\2)|i', '', $m[2]);
       
  3232 	return '<' . $tag . $link . ' target="' . esc_attr( $_links_add_target ) . '">';
       
  3233 }
       
  3234 
       
  3235 /**
       
  3236  * Normalize EOL characters and strip duplicate whitespace.
       
  3237  *
       
  3238  * @since 2.7.0
       
  3239  *
       
  3240  * @param string $str The string to normalize.
       
  3241  * @return string The normalized string.
       
  3242  */
       
  3243 function normalize_whitespace( $str ) {
       
  3244 	$str  = trim( $str );
       
  3245 	$str  = str_replace( "\r", "\n", $str );
       
  3246 	$str  = preg_replace( array( '/\n+/', '/[ \t]+/' ), array( "\n", ' ' ), $str );
       
  3247 	return $str;
       
  3248 }
       
  3249 
       
  3250 /**
       
  3251  * Properly strip all HTML tags including script and style
       
  3252  *
       
  3253  * @since 2.9.0
       
  3254  *
       
  3255  * @param string $string String containing HTML tags
       
  3256  * @param bool $remove_breaks optional Whether to remove left over line breaks and white space chars
       
  3257  * @return string The processed string.
       
  3258  */
       
  3259 function wp_strip_all_tags($string, $remove_breaks = false) {
       
  3260 	$string = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $string );
       
  3261 	$string = strip_tags($string);
       
  3262 
       
  3263 	if ( $remove_breaks )
       
  3264 		$string = preg_replace('/[\r\n\t ]+/', ' ', $string);
       
  3265 
       
  3266 	return trim( $string );
       
  3267 }
       
  3268 
       
  3269 /**
       
  3270  * Sanitize a string from user input or from the db
       
  3271  *
       
  3272  * check for invalid UTF-8,
       
  3273  * Convert single < characters to entity,
       
  3274  * strip all tags,
       
  3275  * remove line breaks, tabs and extra white space,
       
  3276  * strip octets.
       
  3277  *
       
  3278  * @since 2.9.0
       
  3279  *
       
  3280  * @param string $str
       
  3281  * @return string
       
  3282  */
       
  3283 function sanitize_text_field($str) {
       
  3284 	$filtered = wp_check_invalid_utf8( $str );
       
  3285 
       
  3286 	if ( strpos($filtered, '<') !== false ) {
       
  3287 		$filtered = wp_pre_kses_less_than( $filtered );
       
  3288 		// This will strip extra whitespace for us.
       
  3289 		$filtered = wp_strip_all_tags( $filtered, true );
       
  3290 	} else {
       
  3291 		$filtered = trim( preg_replace('/[\r\n\t ]+/', ' ', $filtered) );
       
  3292 	}
       
  3293 
       
  3294 	$found = false;
       
  3295 	while ( preg_match('/%[a-f0-9]{2}/i', $filtered, $match) ) {
       
  3296 		$filtered = str_replace($match[0], '', $filtered);
       
  3297 		$found = true;
       
  3298 	}
       
  3299 
       
  3300 	if ( $found ) {
       
  3301 		// Strip out the whitespace that may now exist after removing the octets.
       
  3302 		$filtered = trim( preg_replace('/ +/', ' ', $filtered) );
       
  3303 	}
       
  3304 
       
  3305 	return apply_filters('sanitize_text_field', $filtered, $str);
       
  3306 }
       
  3307 
       
  3308 /**
       
  3309  * i18n friendly version of basename()
       
  3310  *
       
  3311  * @since 3.1.0
       
  3312  *
       
  3313  * @param string $path A path.
       
  3314  * @param string $suffix If the filename ends in suffix this will also be cut off.
       
  3315  * @return string
       
  3316  */
       
  3317 function wp_basename( $path, $suffix = '' ) {
       
  3318 	return urldecode( basename( str_replace( array( '%2F', '%5C' ), '/', urlencode( $path ) ), $suffix ) );
       
  3319 }
       
  3320 
       
  3321 /**
       
  3322  * Forever eliminate "Wordpress" from the planet (or at least the little bit we can influence).
       
  3323  *
       
  3324  * Violating our coding standards for a good function name.
       
  3325  *
       
  3326  * @since 3.0.0
       
  3327  */
       
  3328 function capital_P_dangit( $text ) {
       
  3329 	// Simple replacement for titles
       
  3330 	if ( 'the_title' === current_filter() )
       
  3331 		return str_replace( 'Wordpress', 'WordPress', $text );
       
  3332 	// Still here? Use the more judicious replacement
       
  3333 	static $dblq = false;
       
  3334 	if ( false === $dblq )
       
  3335 		$dblq = _x( '&#8220;', 'opening curly double quote' );
       
  3336 	return str_replace(
       
  3337 		array( ' Wordpress', '&#8216;Wordpress', $dblq . 'Wordpress', '>Wordpress', '(Wordpress' ),
       
  3338 		array( ' WordPress', '&#8216;WordPress', $dblq . 'WordPress', '>WordPress', '(WordPress' ),
       
  3339 	$text );
       
  3340 
       
  3341 }
       
  3342 
       
  3343 /**
       
  3344  * Sanitize a mime type
       
  3345  *
       
  3346  * @since 3.1.3
       
  3347  *
       
  3348  * @param string $mime_type Mime type
       
  3349  * @return string Sanitized mime type
       
  3350  */
       
  3351 function sanitize_mime_type( $mime_type ) {
       
  3352 	$sani_mime_type = preg_replace( '/[^-+*.a-zA-Z0-9\/]/', '', $mime_type );
       
  3353 	return apply_filters( 'sanitize_mime_type', $sani_mime_type, $mime_type );
       
  3354 }
       
  3355 
       
  3356 /**
       
  3357  * Sanitize space or carriage return separated URLs that are used to send trackbacks.
       
  3358  *
       
  3359  * @since 3.4.0
       
  3360  *
       
  3361  * @param string $to_ping Space or carriage return separated URLs
       
  3362  * @return string URLs starting with the http or https protocol, separated by a carriage return.
       
  3363  */
       
  3364 function sanitize_trackback_urls( $to_ping ) {
       
  3365 	$urls_to_ping = preg_split( '/[\r\n\t ]/', trim( $to_ping ), -1, PREG_SPLIT_NO_EMPTY );
       
  3366 	foreach ( $urls_to_ping as $k => $url ) {
       
  3367 		if ( !preg_match( '#^https?://.#i', $url ) )
       
  3368 			unset( $urls_to_ping[$k] );
       
  3369 	}
       
  3370 	$urls_to_ping = array_map( 'esc_url_raw', $urls_to_ping );
       
  3371 	$urls_to_ping = implode( "\n", $urls_to_ping );
       
  3372 	return apply_filters( 'sanitize_trackback_urls', $urls_to_ping, $to_ping );
       
  3373 }
       
  3374 
       
  3375 /**
       
  3376  * Add slashes to a string or array of strings.
       
  3377  *
       
  3378  * This should be used when preparing data for core API that expects slashed data.
       
  3379  * This should not be used to escape data going directly into an SQL query.
       
  3380  *
       
  3381  * @since 3.6.0
       
  3382  *
       
  3383  * @param string|array $value String or array of strings to slash.
       
  3384  * @return string|array Slashed $value
       
  3385  */
       
  3386 function wp_slash( $value ) {
       
  3387 	if ( is_array( $value ) ) {
       
  3388 		foreach ( $value as $k => $v ) {
       
  3389 			if ( is_array( $v ) ) {
       
  3390 				$value[$k] = wp_slash( $v );
       
  3391 			} else {
       
  3392 				$value[$k] = addslashes( $v );
       
  3393 			}
       
  3394 		}
       
  3395 	} else {
       
  3396 		$value = addslashes( $value );
       
  3397 	}
       
  3398 
       
  3399 	return $value;
       
  3400 }
       
  3401 
       
  3402 /**
       
  3403  * Remove slashes from a string or array of strings.
       
  3404  *
       
  3405  * This should be used to remove slashes from data passed to core API that
       
  3406  * expects data to be unslashed.
       
  3407  *
       
  3408  * @since 3.6.0
       
  3409  *
       
  3410  * @param string|array $value String or array of strings to unslash.
       
  3411  * @return string|array Unslashed $value
       
  3412  */
       
  3413 function wp_unslash( $value ) {
       
  3414 	return stripslashes_deep( $value );
       
  3415 }
       
  3416 
       
  3417 /**
       
  3418  * Extract and return the first URL from passed content.
       
  3419  *
       
  3420  * @since 3.6.0
       
  3421  *
       
  3422  * @param string $content A string which might contain a URL.
       
  3423  * @return string The found URL.
       
  3424  */
       
  3425 function get_url_in_content( $content ) {
       
  3426 	if ( empty( $content ) )
       
  3427 		return '';
       
  3428 
       
  3429 	if ( preg_match( '/<a\s[^>]*?href=([\'"])(.+?)\1/is', $content, $matches ) )
       
  3430 		return esc_url_raw( $matches[2] );
       
  3431 
       
  3432 	return false;
       
  3433 }