wp/wp-includes/formatting.php
changeset 5 5e2f62d02dcd
parent 0 d970ebf37754
child 7 cf61fcea0001
equal deleted inserted replaced
4:346c88efed21 5:5e2f62d02dcd
     9 
     9 
    10 /**
    10 /**
    11  * Replaces common plain text characters into formatted entities
    11  * Replaces common plain text characters into formatted entities
    12  *
    12  *
    13  * As an example,
    13  * As an example,
    14  * <code>
    14  *
    15  * 'cause today's effort makes it worth tomorrow's "holiday"...
    15  *     'cause today's effort makes it worth tomorrow's "holiday" ...
    16  * </code>
    16  *
    17  * Becomes:
    17  * Becomes:
    18  * <code>
    18  *
    19  * &#8217;cause today&#8217;s effort makes it worth tomorrow&#8217;s &#8220;holiday&#8221;&#8230;
    19  *     &#8217;cause today&#8217;s effort makes it worth tomorrow&#8217;s &#8220;holiday&#8221; &#8230;
    20  * </code>
    20  *
    21  * Code within certain html blocks are skipped.
    21  * Code within certain html blocks are skipped.
    22  *
    22  *
    23  * @since 0.71
    23  * @since 0.71
    24  * @uses $wp_cockneyreplace Array of formatted entities for certain common phrases
    24  * @uses $wp_cockneyreplace Array of formatted entities for certain common phrases
    25  *
    25  *
    26  * @param string $text The text to be formatted
    26  * @param string $text The text to be formatted
       
    27  * @param bool $reset Set to true for unit testing. Translated patterns will reset.
    27  * @return string The string replaced with html entities
    28  * @return string The string replaced with html entities
    28  */
    29  */
    29 function wptexturize($text) {
    30 function wptexturize($text, $reset = false) {
    30 	global $wp_cockneyreplace;
    31 	global $wp_cockneyreplace, $shortcode_tags;
    31 	static $static_characters, $static_replacements, $dynamic_characters, $dynamic_replacements,
    32 	static $static_characters, $static_replacements, $dynamic_characters, $dynamic_replacements,
    32 		$default_no_texturize_tags, $default_no_texturize_shortcodes;
    33 		$default_no_texturize_tags, $default_no_texturize_shortcodes, $run_texturize = true;
    33 
    34 
    34 	// No need to set up these static variables more than once
    35 	// If there's nothing to do, just stop.
    35 	if ( ! isset( $static_characters ) ) {
    36 	if ( empty( $text ) || false === $run_texturize ) {
       
    37 		return $text;
       
    38 	}
       
    39 
       
    40 	// Set up static variables. Run once only.
       
    41 	if ( $reset || ! isset( $static_characters ) ) {
       
    42 		/**
       
    43 		 * Filter whether to skip running wptexturize().
       
    44 		 *
       
    45 		 * Passing false to the filter will effectively short-circuit wptexturize().
       
    46 		 * returning the original text passed to the function instead.
       
    47 		 *
       
    48 		 * The filter runs only once, the first time wptexturize() is called.
       
    49 		 *
       
    50 		 * @since 4.0.0
       
    51 		 *
       
    52 		 * @see wptexturize()
       
    53 		 *
       
    54 		 * @param bool $run_texturize Whether to short-circuit wptexturize().
       
    55 		 */
       
    56 		$run_texturize = apply_filters( 'run_wptexturize', $run_texturize );
       
    57 		if ( false === $run_texturize ) {
       
    58 			return $text;
       
    59 		}
       
    60 
    36 		/* translators: opening curly double quote */
    61 		/* translators: opening curly double quote */
    37 		$opening_quote = _x( '&#8220;', 'opening curly double quote' );
    62 		$opening_quote = _x( '&#8220;', 'opening curly double quote' );
    38 		/* translators: closing curly double quote */
    63 		/* translators: closing curly double quote */
    39 		$closing_quote = _x( '&#8221;', 'closing curly double quote' );
    64 		$closing_quote = _x( '&#8221;', 'closing curly double quote' );
    40 
    65 
    59 		$default_no_texturize_tags = array('pre', 'code', 'kbd', 'style', 'script', 'tt');
    84 		$default_no_texturize_tags = array('pre', 'code', 'kbd', 'style', 'script', 'tt');
    60 		$default_no_texturize_shortcodes = array('code');
    85 		$default_no_texturize_shortcodes = array('code');
    61 
    86 
    62 		// if a plugin has provided an autocorrect array, use it
    87 		// if a plugin has provided an autocorrect array, use it
    63 		if ( isset($wp_cockneyreplace) ) {
    88 		if ( isset($wp_cockneyreplace) ) {
    64 			$cockney = array_keys($wp_cockneyreplace);
    89 			$cockney = array_keys( $wp_cockneyreplace );
    65 			$cockneyreplace = array_values($wp_cockneyreplace);
    90 			$cockneyreplace = array_values( $wp_cockneyreplace );
    66 		} elseif ( "'" != $apos ) { // Only bother if we're doing a replacement.
    91 		} elseif ( "'" != $apos ) { // Only bother if we're doing a replacement.
    67 			$cockney = array( "'tain't", "'twere", "'twas", "'tis", "'twill", "'til", "'bout", "'nuff", "'round", "'cause" );
    92 			$cockney = array( "'tain't", "'twere", "'twas", "'tis", "'twill", "'til", "'bout", "'nuff", "'round", "'cause", "'em" );
    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" );
    93 			$cockneyreplace = array( $apos . "tain" . $apos . "t", $apos . "twere", $apos . "twas", $apos . "tis", $apos . "twill", $apos . "til", $apos . "bout", $apos . "nuff", $apos . "round", $apos . "cause", $apos . "em" );
    69 		} else {
    94 		} else {
    70 			$cockney = $cockneyreplace = array();
    95 			$cockney = $cockneyreplace = array();
    71 		}
    96 		}
    72 
    97 
    73 		$static_characters = array_merge( array( '---', ' -- ', '--', ' - ', 'xn&#8211;', '...', '``', '\'\'', ' (tm)' ), $cockney );
    98 		$static_characters = array_merge( array( '...', '``', '\'\'', ' (tm)' ), $cockney );
    74 		$static_replacements = array_merge( array( $em_dash, ' ' . $em_dash . ' ', $en_dash, ' ' . $en_dash . ' ', 'xn--', '&#8230;', $opening_quote, $closing_quote, ' &#8482;' ), $cockneyreplace );
    99 		$static_replacements = array_merge( array( '&#8230;', $opening_quote, $closing_quote, ' &#8482;' ), $cockneyreplace );
    75 
   100 
       
   101 
       
   102 		// Pattern-based replacements of characters.
       
   103 		// Sort the remaining patterns into several arrays for performance tuning.
       
   104 		$dynamic_characters = array( 'apos' => array(), 'quote' => array(), 'dash' => array() );
       
   105 		$dynamic_replacements = array( 'apos' => array(), 'quote' => array(), 'dash' => array() );
    76 		$dynamic = array();
   106 		$dynamic = array();
    77 		if ( "'" != $apos ) {
   107 		$spaces = wp_spaces_regexp();
    78 			$dynamic[ '/\'(\d\d(?:&#8217;|\')?s)/' ] = $apos . '$1'; // '99's
   108 
    79 			$dynamic[ '/\'(\d)/'                   ] = $apos . '$1'; // '99
   109 		// '99' and '99" are ambiguous among other patterns; assume it's an abbreviated year at the end of a quotation.
    80 		}
   110 		if ( "'" !== $apos || "'" !== $closing_single_quote ) {
    81 		if ( "'" != $opening_single_quote )
   111 			$dynamic[ '/\'(\d\d)\'(?=\Z|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $apos . '$1' . $closing_single_quote;
    82 			$dynamic[ '/(\s|\A|[([{<]|")\'/'       ] = '$1' . $opening_single_quote; // opening single quote, even after (, {, <, [
   112 		}
    83 		if ( '"' != $double_prime )
   113 		if ( "'" !== $apos || '"' !== $closing_quote ) {
    84 			$dynamic[ '/(\d)"/'                    ] = '$1' . $double_prime; // 9" (double prime)
   114 			$dynamic[ '/\'(\d\d)"(?=\Z|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $apos . '$1' . $closing_quote;
    85 		if ( "'" != $prime )
   115 		}
    86 			$dynamic[ '/(\d)\'/'                   ] = '$1' . $prime; // 9' (prime)
   116 
    87 		if ( "'" != $apos )
   117 		// '99 '99s '99's (apostrophe)  But never '9 or '99% or '999 or '99.0.
    88 			$dynamic[ '/(\S)\'([^\'\s])/'          ] = '$1' . $apos . '$2'; // apostrophe in a word
   118 		if ( "'" !== $apos ) {
    89 		if ( '"' != $opening_quote )
   119 			$dynamic[ '/\'(?=\d\d(?:\Z|(?![%\d]|[.,]\d)))/' ] = $apos;
    90 			$dynamic[ '/(\s|\A|[([{<])"(?!\s)/'    ] = '$1' . $opening_quote . '$2'; // opening double quote, even after (, {, <, [
   120 		}
    91 		if ( '"' != $closing_quote )
   121 
    92 			$dynamic[ '/"(\s|\S|\Z)/'              ] = $closing_quote . '$1'; // closing double quote
   122 		// Quoted Numbers like '0.42'
    93 		if ( "'" != $closing_single_quote )
   123 		if ( "'" !== $opening_single_quote && "'" !== $closing_single_quote ) {
    94 			$dynamic[ '/\'([\s.]|\Z)/'             ] = $closing_single_quote . '$1'; // closing single quote
   124 			$dynamic[ '/(?<=\A|' . $spaces . ')\'(\d[.,\d]*)\'/' ] = $opening_single_quote . '$1' . $closing_single_quote;
    95 
   125 		}
    96 		$dynamic[ '/\b(\d+)x(\d+)\b/'              ] = '$1&#215;$2'; // 9x9 (times)
   126 
    97 
   127 		// Single quote at start, or preceded by (, {, <, [, ", -, or spaces.
    98 		$dynamic_characters = array_keys( $dynamic );
   128 		if ( "'" !== $opening_single_quote ) {
    99 		$dynamic_replacements = array_values( $dynamic );
   129 			$dynamic[ '/(?<=\A|[([{"\-]|&lt;|' . $spaces . ')\'/' ] = $opening_single_quote;
   100 	}
   130 		}
   101 
   131 
   102 	// Transform into regexp sub-expression used in _wptexturize_pushpop_element
   132 		// Apostrophe in a word.  No spaces, double apostrophes, or other punctuation.
       
   133 		if ( "'" !== $apos ) {
       
   134 			$dynamic[ '/(?<!' . $spaces . ')\'(?!\Z|[.,:;"\'(){}[\]\-]|&[lg]t;|' . $spaces . ')/' ] = $apos;
       
   135 		}
       
   136 
       
   137 		// 9' (prime)
       
   138 		if ( "'" !== $prime ) {
       
   139 			$dynamic[ '/(?<=\d)\'/' ] = $prime;
       
   140 		}
       
   141 
       
   142 		// Single quotes followed by spaces or ending punctuation.
       
   143 		if ( "'" !== $closing_single_quote ) {
       
   144 			$dynamic[ '/\'(?=\Z|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $closing_single_quote;
       
   145 		}
       
   146 
       
   147 		$dynamic_characters['apos'] = array_keys( $dynamic );
       
   148 		$dynamic_replacements['apos'] = array_values( $dynamic );
       
   149 		$dynamic = array();
       
   150 
       
   151 		// Quoted Numbers like "42"
       
   152 		if ( '"' !== $opening_quote && '"' !== $closing_quote ) {
       
   153 			$dynamic[ '/(?<=\A|' . $spaces . ')"(\d[.,\d]*)"/' ] = $opening_quote . '$1' . $closing_quote;
       
   154 		}
       
   155 
       
   156 		// 9" (double prime)
       
   157 		if ( '"' !== $double_prime ) {
       
   158 			$dynamic[ '/(?<=\d)"/' ] = $double_prime;
       
   159 		}
       
   160 
       
   161 		// Double quote at start, or preceded by (, {, <, [, -, or spaces, and not followed by spaces.
       
   162 		if ( '"' !== $opening_quote ) {
       
   163 			$dynamic[ '/(?<=\A|[([{\-]|&lt;|' . $spaces . ')"(?!' . $spaces . ')/' ] = $opening_quote;
       
   164 		}
       
   165 
       
   166 		// Any remaining double quotes.
       
   167 		if ( '"' !== $closing_quote ) {
       
   168 			$dynamic[ '/"/' ] = $closing_quote;
       
   169 		}
       
   170 
       
   171 		$dynamic_characters['quote'] = array_keys( $dynamic );
       
   172 		$dynamic_replacements['quote'] = array_values( $dynamic );
       
   173 		$dynamic = array();
       
   174 
       
   175 		// Dashes and spaces
       
   176 		$dynamic[ '/---/' ] = $em_dash;
       
   177 		$dynamic[ '/(?<=^|' . $spaces . ')--(?=$|' . $spaces . ')/' ] = $em_dash;
       
   178 		$dynamic[ '/(?<!xn)--/' ] = $en_dash;
       
   179 		$dynamic[ '/(?<=^|' . $spaces . ')-(?=$|' . $spaces . ')/' ] = $en_dash;
       
   180 
       
   181 		$dynamic_characters['dash'] = array_keys( $dynamic );
       
   182 		$dynamic_replacements['dash'] = array_values( $dynamic );
       
   183 	}
       
   184 
   103 	// Must do this every time in case plugins use these filters in a context sensitive manner
   185 	// 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) ) . ')';
   186 	/**
   105 	$no_texturize_shortcodes = '(' . implode('|', apply_filters('no_texturize_shortcodes', $default_no_texturize_shortcodes) ) . ')';
   187 	 * Filter the list of HTML elements not to texturize.
       
   188 	 *
       
   189 	 * @since 2.8.0
       
   190 	 *
       
   191 	 * @param array $default_no_texturize_tags An array of HTML element names.
       
   192 	 */
       
   193 	$no_texturize_tags = apply_filters( 'no_texturize_tags', $default_no_texturize_tags );
       
   194 	/**
       
   195 	 * Filter the list of shortcodes not to texturize.
       
   196 	 *
       
   197 	 * @since 2.8.0
       
   198 	 *
       
   199 	 * @param array $default_no_texturize_shortcodes An array of shortcode names.
       
   200 	 */
       
   201 	$no_texturize_shortcodes = apply_filters( 'no_texturize_shortcodes', $default_no_texturize_shortcodes );
   106 
   202 
   107 	$no_texturize_tags_stack = array();
   203 	$no_texturize_tags_stack = array();
   108 	$no_texturize_shortcodes_stack = array();
   204 	$no_texturize_shortcodes_stack = array();
   109 
   205 
   110 	$textarr = preg_split('/(<.*>|\[.*\])/Us', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
   206 	// Look for shortcodes and HTML elements.
       
   207 
       
   208 	$tagnames = array_keys( $shortcode_tags );
       
   209 	$tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) );
       
   210 	$tagregexp = "(?:$tagregexp)(?![\\w-])"; // Excerpt of get_shortcode_regex().
       
   211 
       
   212 	$comment_regex =
       
   213 		  '!'           // Start of comment, after the <.
       
   214 		. '(?:'         // Unroll the loop: Consume everything until --> is found.
       
   215 		.     '-(?!->)' // Dash not followed by end of comment.
       
   216 		.     '[^\-]*+' // Consume non-dashes.
       
   217 		. ')*+'         // Loop possessively.
       
   218 		. '(?:-->)?';   // End of comment. If not found, match all input.
       
   219 
       
   220 	$shortcode_regex =
       
   221 		  '\['              // Find start of shortcode.
       
   222 		. '[\/\[]?'         // Shortcodes may begin with [/ or [[
       
   223 		. $tagregexp        // Only match registered shortcodes, because performance.
       
   224 		. '(?:'
       
   225 		.     '[^\[\]<>]+'  // Shortcodes do not contain other shortcodes. Quantifier critical.
       
   226 		. '|'
       
   227 		.     '<[^\[\]>]*>' // HTML elements permitted. Prevents matching ] before >.
       
   228 		. ')*+'             // Possessive critical.
       
   229 		. '\]'              // Find end of shortcode.
       
   230 		. '\]?';            // Shortcodes may end with ]]
       
   231 
       
   232 	$regex =
       
   233 		  '/('                   // Capture the entire match.
       
   234 		.     '<'                // Find start of element.
       
   235 		.     '(?(?=!--)'        // Is this a comment?
       
   236 		.         $comment_regex // Find end of comment.
       
   237 		.     '|'
       
   238 		.         '[^>]*>'       // Find end of element.
       
   239 		.     ')'
       
   240 		. '|'
       
   241 		.     $shortcode_regex   // Find shortcodes.
       
   242 		. ')/s';
       
   243 
       
   244 	$textarr = preg_split( $regex, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
   111 
   245 
   112 	foreach ( $textarr as &$curl ) {
   246 	foreach ( $textarr as &$curl ) {
   113 		if ( empty( $curl ) )
   247 		// Only call _wptexturize_pushpop_element if $curl is a delimiter.
       
   248 		$first = $curl[0];
       
   249 		if ( '<' === $first && '<!--' === substr( $curl, 0, 4 ) ) {
       
   250 			// This is an HTML comment delimeter.
       
   251 
   114 			continue;
   252 			continue;
   115 
   253 
   116 		// Only call _wptexturize_pushpop_element if first char is correct tag opening
   254 		} elseif ( '<' === $first && '>' === substr( $curl, -1 ) ) {
   117 		$first = $curl[0];
   255 			// This is an HTML element delimiter.
   118 		if ( '<' === $first ) {
   256 
   119 			_wptexturize_pushpop_element($curl, $no_texturize_tags_stack, $no_texturize_tags, '<', '>');
   257 			_wptexturize_pushpop_element( $curl, $no_texturize_tags_stack, $no_texturize_tags );
   120 		} elseif ( '[' === $first ) {
   258 
   121 			_wptexturize_pushpop_element($curl, $no_texturize_shortcodes_stack, $no_texturize_shortcodes, '[', ']');
   259 		} elseif ( '' === trim( $curl ) ) {
   122 		} elseif ( empty($no_texturize_shortcodes_stack) && empty($no_texturize_tags_stack) ) {
   260 			// This is a newline between delimiters.  Performance improves when we check this.
   123 			// This is not a tag, nor is the texturization disabled static strings
   261 
   124 			$curl = str_replace($static_characters, $static_replacements, $curl);
   262 			continue;
   125 			// regular expressions
   263 
   126 			$curl = preg_replace($dynamic_characters, $dynamic_replacements, $curl);
   264 		} elseif ( '[' === $first && 1 === preg_match( '/^' . $shortcode_regex . '$/', $curl ) ) {
   127 		}
   265 			// This is a shortcode delimiter.
   128 		$curl = preg_replace('/&([^#])(?![a-zA-Z1-4]{1,8};)/', '&#038;$1', $curl);
   266 
   129 	}
   267 			if ( '[[' !== substr( $curl, 0, 2 ) && ']]' !== substr( $curl, -2 ) ) {
   130 	return implode( '', $textarr );
   268 				// Looks like a normal shortcode.
       
   269 				_wptexturize_pushpop_element( $curl, $no_texturize_shortcodes_stack, $no_texturize_shortcodes );
       
   270 			} else {
       
   271 				// Looks like an escaped shortcode.
       
   272 				continue;
       
   273 			}
       
   274 
       
   275 		} elseif ( empty( $no_texturize_shortcodes_stack ) && empty( $no_texturize_tags_stack ) ) {
       
   276 			// This is neither a delimiter, nor is this content inside of no_texturize pairs.  Do texturize.
       
   277 
       
   278 			$curl = str_replace( $static_characters, $static_replacements, $curl );
       
   279 
       
   280 			if ( false !== strpos( $curl, "'" ) ) {
       
   281 				$curl = preg_replace( $dynamic_characters['apos'], $dynamic_replacements['apos'], $curl );
       
   282 			}
       
   283 			if ( false !== strpos( $curl, '"' ) ) {
       
   284 				$curl = preg_replace( $dynamic_characters['quote'], $dynamic_replacements['quote'], $curl );
       
   285 			}
       
   286 			if ( false !== strpos( $curl, '-' ) ) {
       
   287 				$curl = preg_replace( $dynamic_characters['dash'], $dynamic_replacements['dash'], $curl );
       
   288 			}
       
   289 
       
   290 			// 9x9 (times), but never 0x9999
       
   291 			if ( 1 === preg_match( '/(?<=\d)x\d/', $curl ) ) {
       
   292 				// Searching for a digit is 10 times more expensive than for the x, so we avoid doing this one!
       
   293 				$curl = preg_replace( '/\b(\d(?(?<=0)[\d\.,]+|[\d\.,]*))x(\d[\d\.,]*)\b/', '$1&#215;$2', $curl );
       
   294 			}
       
   295 		}
       
   296 	}
       
   297 	$text = implode( '', $textarr );
       
   298 
       
   299 	// Replace each & with &#038; unless it already looks like an entity.
       
   300 	$text = preg_replace('/&(?!#(?:\d+|x[a-f0-9]+);|[a-z1-4]{1,8};)/i', '&#038;', $text);
       
   301 
       
   302 	return $text;
   131 }
   303 }
   132 
   304 
   133 /**
   305 /**
   134  * Search for disabled element tags. Push element to stack on tag open and pop
   306  * 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.
   307  * on tag close.
       
   308  *
       
   309  * Assumes first char of $text is tag opening and last char is tag closing.
       
   310  * Assumes second char of $text is optionally '/' to indicate closing as in </html>.
   136  *
   311  *
   137  * @since 2.9.0
   312  * @since 2.9.0
   138  * @access private
   313  * @access private
   139  *
   314  *
   140  * @param string $text Text to check. First character is assumed to be $opening
   315  * @param string $text Text to check. Must be a tag like `<html>` or `[shortcode]`.
   141  * @param array $stack Array used as stack of opened tag elements
   316  * @param array $stack List of open tag elements.
   142  * @param string $disabled_elements Tags to match against formatted as regexp sub-expression
   317  * @param array $disabled_elements The tag names to match against. Spaces are not allowed in tag names.
   143  * @param string $opening Tag opening character, assumed to be 1 character long
   318  */
   144  * @param string $closing Tag closing character
   319 function _wptexturize_pushpop_element($text, &$stack, $disabled_elements) {
   145  */
   320 	// Is it an opening tag or closing tag?
   146 function _wptexturize_pushpop_element($text, &$stack, $disabled_elements, $opening = '<', $closing = '>') {
   321 	if ( '/' !== $text[1] ) {
   147 	// Check if it is a closing tag -- otherwise assume opening tag
   322 		$opening_tag = true;
   148 	if (strncmp($opening . '/', $text, 2)) {
   323 		$name_offset = 1;
   149 		// Opening? Check $text+1 against disabled elements
   324 	} elseif ( 0 == count( $stack ) ) {
   150 		if (preg_match('/^' . $disabled_elements . '\b/', substr($text, 1), $matches)) {
   325 		// Stack is empty. Just stop.
       
   326 		return;
       
   327 	} else {
       
   328 		$opening_tag = false;
       
   329 		$name_offset = 2;
       
   330 	}
       
   331 
       
   332 	// Parse out the tag name.
       
   333 	$space = strpos( $text, ' ' );
       
   334 	if ( false === $space ) {
       
   335 		$space = -1;
       
   336 	} else {
       
   337 		$space -= $name_offset;
       
   338 	}
       
   339 	$tag = substr( $text, $name_offset, $space );
       
   340 
       
   341 	// Handle disabled tags.
       
   342 	if ( in_array( $tag, $disabled_elements ) ) {
       
   343 		if ( $opening_tag ) {
   151 			/*
   344 			/*
   152 			 * This disables texturize until we find a closing tag of our type
   345 			 * This disables texturize until we find a closing tag of our type
   153 			 * (e.g. <pre>) even if there was invalid nesting before that
   346 			 * (e.g. <pre>) even if there was invalid nesting before that
   154 			 *
   347 			 *
   155 			 * Example: in the case <pre>sadsadasd</code>"baba"</pre>
   348 			 * Example: in the case <pre>sadsadasd</code>"baba"</pre>
   156 			 *          "baba" won't be texturize
   349 			 *          "baba" won't be texturize
   157 			 */
   350 			 */
   158 
   351 
   159 			array_push($stack, $matches[1]);
   352 			array_push( $stack, $tag );
   160 		}
   353 		} elseif ( end( $stack ) == $tag ) {
   161 	} else {
   354 			array_pop( $stack );
   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 		}
   355 		}
   171 	}
   356 	}
   172 }
   357 }
   173 
   358 
   174 /**
   359 /**
   175  * Replaces double line-breaks with paragraph elements.
   360  * Replaces double line-breaks with paragraph elements.
   176  *
   361  *
   177  * A group of regex replaces used to identify text formatted with newlines and
   362  * A group of regex replaces used to identify text formatted with newlines and
   178  * replace double line-breaks with HTML paragraph tags. The remaining
   363  * replace double line-breaks with HTML paragraph tags. The remaining line-breaks
   179  * line-breaks after conversion become <<br />> tags, unless $br is set to '0'
   364  * after conversion become <<br />> tags, unless $br is set to '0' or 'false'.
   180  * or 'false'.
       
   181  *
   365  *
   182  * @since 0.71
   366  * @since 0.71
   183  *
   367  *
   184  * @param string $pee The text which has to be formatted.
   368  * @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.
   369  * @param bool   $br  Optional. If set, this will convert all remaining line-breaks
       
   370  *                    after paragraphing. Default true.
   186  * @return string Text which has been converted into correct paragraph tags.
   371  * @return string Text which has been converted into correct paragraph tags.
   187  */
   372  */
   188 function wpautop($pee, $br = true) {
   373 function wpautop($pee, $br = true) {
   189 	$pre_tags = array();
   374 	$pre_tags = array();
   190 
   375 
   191 	if ( trim($pee) === '' )
   376 	if ( trim($pee) === '' )
   192 		return '';
   377 		return '';
   193 
   378 
   194 	$pee = $pee . "\n"; // just to make things a little easier, pad the end
   379 	// Just to make things a little easier, pad the end.
   195 
   380 	$pee = $pee . "\n";
       
   381 
       
   382 	/*
       
   383 	 * Pre tags shouldn't be touched by autop.
       
   384 	 * Replace pre tags with placeholders and bring them back after autop.
       
   385 	 */
   196 	if ( strpos($pee, '<pre') !== false ) {
   386 	if ( strpos($pee, '<pre') !== false ) {
   197 		$pee_parts = explode( '</pre>', $pee );
   387 		$pee_parts = explode( '</pre>', $pee );
   198 		$last_pee = array_pop($pee_parts);
   388 		$last_pee = array_pop($pee_parts);
   199 		$pee = '';
   389 		$pee = '';
   200 		$i = 0;
   390 		$i = 0;
   215 			$i++;
   405 			$i++;
   216 		}
   406 		}
   217 
   407 
   218 		$pee .= $last_pee;
   408 		$pee .= $last_pee;
   219 	}
   409 	}
   220 
   410 	// Change multiple <br>s into two line breaks, which will turn into paragraphs.
   221 	$pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
   411 	$pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
   222 	// Space things out a little
   412 
   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)';
   413 	$allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)';
       
   414 
       
   415 	// Add a single line break above block-level opening tags.
   224 	$pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee);
   416 	$pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee);
       
   417 
       
   418 	// Add a double line break below block-level closing tags.
   225 	$pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
   419 	$pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
   226 	$pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines
   420 
   227 	if ( strpos($pee, '<object') !== false ) {
   421 	// Standardize newline characters to "\n".
   228 		$pee = preg_replace('|\s*<param([^>]*)>\s*|', "<param$1>", $pee); // no pee inside object/embed
   422 	$pee = str_replace(array("\r\n", "\r"), "\n", $pee); 
   229 		$pee = preg_replace('|\s*</embed>\s*|', '</embed>', $pee);
   423 
   230 	}
   424 	// Collapse line breaks before and after <option> elements so they don't get autop'd.
   231 	$pee = preg_replace("/\n\n+/", "\n\n", $pee); // take care of duplicates
   425 	if ( strpos( $pee, '<option' ) !== false ) {
   232 	// make paragraphs, including one at the end
   426 		$pee = preg_replace( '|\s*<option|', '<option', $pee );
       
   427 		$pee = preg_replace( '|</option>\s*|', '</option>', $pee );
       
   428 	}
       
   429 
       
   430 	/*
       
   431 	 * Collapse line breaks inside <object> elements, before <param> and <embed> elements
       
   432 	 * so they don't get autop'd.
       
   433 	 */
       
   434 	if ( strpos( $pee, '</object>' ) !== false ) {
       
   435 		$pee = preg_replace( '|(<object[^>]*>)\s*|', '$1', $pee );
       
   436 		$pee = preg_replace( '|\s*</object>|', '</object>', $pee );
       
   437 		$pee = preg_replace( '%\s*(</?(?:param|embed)[^>]*>)\s*%', '$1', $pee );
       
   438 	}
       
   439 
       
   440 	/*
       
   441 	 * Collapse line breaks inside <audio> and <video> elements,
       
   442 	 * before and after <source> and <track> elements.
       
   443 	 */
       
   444 	if ( strpos( $pee, '<source' ) !== false || strpos( $pee, '<track' ) !== false ) {
       
   445 		$pee = preg_replace( '%([<\[](?:audio|video)[^>\]]*[>\]])\s*%', '$1', $pee );
       
   446 		$pee = preg_replace( '%\s*([<\[]/(?:audio|video)[>\]])%', '$1', $pee );
       
   447 		$pee = preg_replace( '%\s*(<(?:source|track)[^>]*>)\s*%', '$1', $pee );
       
   448 	}
       
   449 
       
   450 	// Remove more than two contiguous line breaks.
       
   451 	$pee = preg_replace("/\n\n+/", "\n\n", $pee);
       
   452 
       
   453 	// Split up the contents into an array of strings, separated by double line breaks.
   233 	$pees = preg_split('/\n\s*\n/', $pee, -1, PREG_SPLIT_NO_EMPTY);
   454 	$pees = preg_split('/\n\s*\n/', $pee, -1, PREG_SPLIT_NO_EMPTY);
       
   455 
       
   456 	// Reset $pee prior to rebuilding.
   234 	$pee = '';
   457 	$pee = '';
   235 	foreach ( $pees as $tinkle )
   458 
       
   459 	// Rebuild the content as a string, wrapping every bit with a <p>.
       
   460 	foreach ( $pees as $tinkle ) {
   236 		$pee .= '<p>' . trim($tinkle, "\n") . "</p>\n";
   461 		$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
   462 	}
       
   463 
       
   464 	// Under certain strange conditions it could create a P of entirely whitespace.
       
   465 	$pee = preg_replace('|<p>\s*</p>|', '', $pee); 
       
   466 
       
   467 	// Add a closing <p> inside <div>, <address>, or <form> tag if missing.
   238 	$pee = preg_replace('!<p>([^<]+)</(div|address|form)>!', "<p>$1</p></$2>", $pee);
   468 	$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
   469 	
   240 	$pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists
   470 	// If an opening or closing block element tag is wrapped in a <p>, unwrap it.
       
   471 	$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); 
       
   472 	
       
   473 	// In some cases <li> may get wrapped in <p>, fix them.
       
   474 	$pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); 
       
   475 	
       
   476 	// If a <blockquote> is wrapped with a <p>, move it inside the <blockquote>.
   241 	$pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
   477 	$pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
   242 	$pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
   478 	$pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
       
   479 	
       
   480 	// If an opening or closing block element tag is preceded by an opening <p> tag, remove it.
   243 	$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
   481 	$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
       
   482 	
       
   483 	// If an opening or closing block element tag is followed by a closing <p> tag, remove it.
   244 	$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
   484 	$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
       
   485 
       
   486 	// Optionally insert line breaks.
   245 	if ( $br ) {
   487 	if ( $br ) {
       
   488 		// Replace newlines that shouldn't be touched with a placeholder.
   246 		$pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', '_autop_newline_preservation_helper', $pee);
   489 		$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
   490 
       
   491 		// Replace any new line characters that aren't preceded by a <br /> with a <br />.
       
   492 		$pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); 
       
   493 
       
   494 		// Replace newline placeholders with newlines.
   248 		$pee = str_replace('<WPPreserveNewline />', "\n", $pee);
   495 		$pee = str_replace('<WPPreserveNewline />', "\n", $pee);
   249 	}
   496 	}
       
   497 
       
   498 	// If a <br /> tag is after an opening or closing block tag, remove it.
   250 	$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
   499 	$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
       
   500 	
       
   501 	// If a <br /> tag is before a subset of opening or closing block tags, remove it.
   251 	$pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
   502 	$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 );
   503 	$pee = preg_replace( "|\n</p>$|", '</p>', $pee );
   253 
   504 
       
   505 	// Replace placeholder <pre> tags with their original content.
   254 	if ( !empty($pre_tags) )
   506 	if ( !empty($pre_tags) )
   255 		$pee = str_replace(array_keys($pre_tags), array_values($pre_tags), $pee);
   507 		$pee = str_replace(array_keys($pre_tags), array_values($pre_tags), $pee);
   256 
   508 
   257 	return $pee;
   509 	return $pee;
   258 }
   510 }
   271 }
   523 }
   272 
   524 
   273 /**
   525 /**
   274  * Don't auto-p wrap shortcodes that stand alone
   526  * Don't auto-p wrap shortcodes that stand alone
   275  *
   527  *
   276  * Ensures that shortcodes are not wrapped in <<p>>...<</p>>.
   528  * Ensures that shortcodes are not wrapped in `<p>...</p>`.
   277  *
   529  *
   278  * @since 2.9.0
   530  * @since 2.9.0
   279  *
   531  *
   280  * @param string $pee The content.
   532  * @param string $pee The content.
   281  * @return string The filtered content.
   533  * @return string The filtered content.
   286 	if ( empty( $shortcode_tags ) || !is_array( $shortcode_tags ) ) {
   538 	if ( empty( $shortcode_tags ) || !is_array( $shortcode_tags ) ) {
   287 		return $pee;
   539 		return $pee;
   288 	}
   540 	}
   289 
   541 
   290 	$tagregexp = join( '|', array_map( 'preg_quote', array_keys( $shortcode_tags ) ) );
   542 	$tagregexp = join( '|', array_map( 'preg_quote', array_keys( $shortcode_tags ) ) );
       
   543 	$spaces = wp_spaces_regexp();
   291 
   544 
   292 	$pattern =
   545 	$pattern =
   293 		  '/'
   546 		  '/'
   294 		. '<p>'                              // Opening paragraph
   547 		. '<p>'                              // Opening paragraph
   295 		. '\\s*+'                            // Optional leading whitespace
   548 		. '(?:' . $spaces . ')*+'            // Optional leading whitespace
   296 		. '('                                // 1: The shortcode
   549 		. '('                                // 1: The shortcode
   297 		.     '\\['                          // Opening bracket
   550 		.     '\\['                          // Opening bracket
   298 		.     "($tagregexp)"                 // 2: Shortcode name
   551 		.     "($tagregexp)"                 // 2: Shortcode name
   299 		.     '(?![\\w-])'                   // Not followed by word character or hyphen
   552 		.     '(?![\\w-])'                   // Not followed by word character or hyphen
   300 		                                     // Unroll the loop: Inside the opening shortcode tag
   553 		                                     // Unroll the loop: Inside the opening shortcode tag
   315 		.             ')*+'
   568 		.             ')*+'
   316 		.             '\\[\\/\\2\\]'         // Closing shortcode tag
   569 		.             '\\[\\/\\2\\]'         // Closing shortcode tag
   317 		.         ')?'
   570 		.         ')?'
   318 		.     ')'
   571 		.     ')'
   319 		. ')'
   572 		. ')'
   320 		. '\\s*+'                            // optional trailing whitespace
   573 		. '(?:' . $spaces . ')*+'            // optional trailing whitespace
   321 		. '<\\/p>'                           // closing paragraph
   574 		. '<\\/p>'                           // closing paragraph
   322 		. '/s';
   575 		. '/s';
   323 
   576 
   324 	return preg_replace( $pattern, '$1', $pee );
   577 	return preg_replace( $pattern, '$1', $pee );
   325 }
   578 }
   335  *
   588  *
   336  * @param string $str The string to be checked
   589  * @param string $str The string to be checked
   337  * @return bool True if $str fits a UTF-8 model, false otherwise.
   590  * @return bool True if $str fits a UTF-8 model, false otherwise.
   338  */
   591  */
   339 function seems_utf8($str) {
   592 function seems_utf8($str) {
       
   593 	mbstring_binary_safe_encoding();
   340 	$length = strlen($str);
   594 	$length = strlen($str);
       
   595 	reset_mbstring_encoding();
   341 	for ($i=0; $i < $length; $i++) {
   596 	for ($i=0; $i < $length; $i++) {
   342 		$c = ord($str[$i]);
   597 		$c = ord($str[$i]);
   343 		if ($c < 0x80) $n = 0; # 0bbbbbbb
   598 		if ($c < 0x80) $n = 0; // 0bbbbbbb
   344 		elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb
   599 		elseif (($c & 0xE0) == 0xC0) $n=1; // 110bbbbb
   345 		elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb
   600 		elseif (($c & 0xF0) == 0xE0) $n=2; // 1110bbbb
   346 		elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb
   601 		elseif (($c & 0xF8) == 0xF0) $n=3; // 11110bbb
   347 		elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb
   602 		elseif (($c & 0xFC) == 0xF8) $n=4; // 111110bb
   348 		elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b
   603 		elseif (($c & 0xFE) == 0xFC) $n=5; // 1111110b
   349 		else return false; # Does not match any model
   604 		else return false; // Does not match any model
   350 		for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
   605 		for ($j=0; $j<$n; $j++) { // n bytes matching 10bbbbbb follow ?
   351 			if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
   606 			if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
   352 				return false;
   607 				return false;
   353 		}
   608 		}
   354 	}
   609 	}
   355 	return true;
   610 	return true;
   365  *
   620  *
   366  * @since 1.2.2
   621  * @since 1.2.2
   367  * @access private
   622  * @access private
   368  *
   623  *
   369  * @param string $string The text which is to be encoded.
   624  * @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.
   625  * @param int $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.
   626  * @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.
   627  * @param boolean $double_encode Optional. Whether to encode existing html entities. Default is false.
   373  * @return string The encoded text with HTML entities.
   628  * @return string The encoded text with HTML entities.
   374  */
   629  */
   375 function _wp_specialchars( $string, $quote_style = ENT_NOQUOTES, $charset = false, $double_encode = false ) {
   630 function _wp_specialchars( $string, $quote_style = ENT_NOQUOTES, $charset = false, $double_encode = false ) {
   421 		$string = wp_kses_normalize_entities( $string );
   676 		$string = wp_kses_normalize_entities( $string );
   422 
   677 
   423 		// Now re-encode everything except &entity;
   678 		// Now re-encode everything except &entity;
   424 		$string = preg_split( '/(&#?x?[0-9a-z]+;)/i', $string, -1, PREG_SPLIT_DELIM_CAPTURE );
   679 		$string = preg_split( '/(&#?x?[0-9a-z]+;)/i', $string, -1, PREG_SPLIT_DELIM_CAPTURE );
   425 
   680 
   426 		for ( $i = 0; $i < count( $string ); $i += 2 )
   681 		for ( $i = 0, $c = count( $string ); $i < $c; $i += 2 ) {
   427 			$string[$i] = @htmlspecialchars( $string[$i], $quote_style, $charset );
   682 			$string[$i] = @htmlspecialchars( $string[$i], $quote_style, $charset );
   428 
   683 		}
   429 		$string = implode( '', $string );
   684 		$string = implode( '', $string );
   430 	}
   685 	}
   431 
   686 
   432 	// Backwards compatibility
   687 	// Backwards compatibility
   433 	if ( 'single' === $_quote_style )
   688 	if ( 'single' === $_quote_style )
   559 	$unicode = '';
   814 	$unicode = '';
   560 	$values = array();
   815 	$values = array();
   561 	$num_octets = 1;
   816 	$num_octets = 1;
   562 	$unicode_length = 0;
   817 	$unicode_length = 0;
   563 
   818 
       
   819 	mbstring_binary_safe_encoding();
   564 	$string_length = strlen( $utf8_string );
   820 	$string_length = strlen( $utf8_string );
       
   821 	reset_mbstring_encoding();
       
   822 
   565 	for ($i = 0; $i < $string_length; $i++ ) {
   823 	for ($i = 0; $i < $string_length; $i++ ) {
   566 
   824 
   567 		$value = ord( $utf8_string[ $i ] );
   825 		$value = ord( $utf8_string[ $i ] );
   568 
   826 
   569 		if ( $value < 128 ) {
   827 		if ( $value < 128 ) {
   570 			if ( $length && ( $unicode_length >= $length ) )
   828 			if ( $length && ( $unicode_length >= $length ) )
   571 				break;
   829 				break;
   572 			$unicode .= chr($value);
   830 			$unicode .= chr($value);
   573 			$unicode_length++;
   831 			$unicode_length++;
   574 		} else {
   832 		} else {
   575 			if ( count( $values ) == 0 ) $num_octets = ( $value < 224 ) ? 2 : 3;
   833 			if ( count( $values ) == 0 ) {
       
   834 				if ( $value < 224 ) {
       
   835 					$num_octets = 2;
       
   836 				} elseif ( $value < 240 ) {
       
   837 					$num_octets = 3;
       
   838 				} else {
       
   839 					$num_octets = 4;
       
   840 				}
       
   841 			}
   576 
   842 
   577 			$values[] = $value;
   843 			$values[] = $value;
   578 
   844 
   579 			if ( $length && ( $unicode_length + ($num_octets * 3) ) > $length )
   845 			if ( $length && ( $unicode_length + ($num_octets * 3) ) > $length )
   580 				break;
   846 				break;
   581 			if ( count( $values ) == $num_octets ) {
   847 			if ( count( $values ) == $num_octets ) {
   582 				if ($num_octets == 3) {
   848 				for ( $j = 0; $j < $num_octets; $j++ ) {
   583 					$unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]) . '%' . dechex($values[2]);
   849 					$unicode .= '%' . dechex( $values[ $j ] );
   584 					$unicode_length += 9;
       
   585 				} else {
       
   586 					$unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]);
       
   587 					$unicode_length += 6;
       
   588 				}
   850 				}
       
   851 
       
   852 				$unicode_length += $num_octets * 3;
   589 
   853 
   590 				$values = array();
   854 				$values = array();
   591 				$num_octets = 1;
   855 				$num_octets = 1;
   592 			}
   856 			}
   593 		}
   857 		}
   796 			$chars[ chr(195).chr(150) ] = 'Oe';
  1060 			$chars[ chr(195).chr(150) ] = 'Oe';
   797 			$chars[ chr(195).chr(182) ] = 'oe';
  1061 			$chars[ chr(195).chr(182) ] = 'oe';
   798 			$chars[ chr(195).chr(156) ] = 'Ue';
  1062 			$chars[ chr(195).chr(156) ] = 'Ue';
   799 			$chars[ chr(195).chr(188) ] = 'ue';
  1063 			$chars[ chr(195).chr(188) ] = 'ue';
   800 			$chars[ chr(195).chr(159) ] = 'ss';
  1064 			$chars[ chr(195).chr(159) ] = 'ss';
       
  1065 		} elseif ( 'da_DK' === $locale ) {
       
  1066 			$chars[ chr(195).chr(134) ] = 'Ae';
       
  1067  			$chars[ chr(195).chr(166) ] = 'ae';
       
  1068 			$chars[ chr(195).chr(152) ] = 'Oe';
       
  1069 			$chars[ chr(195).chr(184) ] = 'oe';
       
  1070 			$chars[ chr(195).chr(133) ] = 'Aa';
       
  1071 			$chars[ chr(195).chr(165) ] = 'aa';
   801 		}
  1072 		}
   802 
  1073 
   803 		$string = strtr($string, $chars);
  1074 		$string = strtr($string, $chars);
   804 	} else {
  1075 	} else {
       
  1076 		$chars = array();
   805 		// Assume ISO-8859-1 if not UTF-8
  1077 		// Assume ISO-8859-1 if not UTF-8
   806 		$chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158)
  1078 		$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)
  1079 			.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)
  1080 			.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)
  1081 			.chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210)
   815 			.chr(252).chr(253).chr(255);
  1087 			.chr(252).chr(253).chr(255);
   816 
  1088 
   817 		$chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
  1089 		$chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
   818 
  1090 
   819 		$string = strtr($string, $chars['in'], $chars['out']);
  1091 		$string = strtr($string, $chars['in'], $chars['out']);
       
  1092 		$double_chars = array();
   820 		$double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
  1093 		$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');
  1094 		$double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
   822 		$string = str_replace($double_chars['in'], $double_chars['out'], $string);
  1095 		$string = str_replace($double_chars['in'], $double_chars['out'], $string);
   823 	}
  1096 	}
   824 
  1097 
   840  * @return string The sanitized filename
  1113  * @return string The sanitized filename
   841  */
  1114  */
   842 function sanitize_file_name( $filename ) {
  1115 function sanitize_file_name( $filename ) {
   843 	$filename_raw = $filename;
  1116 	$filename_raw = $filename;
   844 	$special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", chr(0));
  1117 	$special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", chr(0));
   845 	$special_chars = apply_filters('sanitize_file_name_chars', $special_chars, $filename_raw);
  1118 	/**
   846 	$filename = str_replace($special_chars, '', $filename);
  1119 	 * Filter the list of characters to remove from a filename.
   847 	$filename = preg_replace('/[\s-]+/', '-', $filename);
  1120 	 *
   848 	$filename = trim($filename, '.-_');
  1121 	 * @since 2.8.0
       
  1122 	 *
       
  1123 	 * @param array  $special_chars Characters to remove.
       
  1124 	 * @param string $filename_raw  Filename as it was passed into sanitize_file_name().
       
  1125 	 */
       
  1126 	$special_chars = apply_filters( 'sanitize_file_name_chars', $special_chars, $filename_raw );
       
  1127 	$filename = preg_replace( "#\x{00a0}#siu", ' ', $filename );
       
  1128 	$filename = str_replace( $special_chars, '', $filename );
       
  1129 	$filename = str_replace( array( '%20', '+' ), '-', $filename );
       
  1130 	$filename = preg_replace( '/[\r\n\t -]+/', '-', $filename );
       
  1131 	$filename = trim( $filename, '.-_' );
   849 
  1132 
   850 	// Split the filename into a base and extension[s]
  1133 	// Split the filename into a base and extension[s]
   851 	$parts = explode('.', $filename);
  1134 	$parts = explode('.', $filename);
   852 
  1135 
   853 	// Return if only one extension
  1136 	// Return if only one extension
   854 	if ( count($parts) <= 2 )
  1137 	if ( count( $parts ) <= 2 ) {
   855 		return apply_filters('sanitize_file_name', $filename, $filename_raw);
  1138 		/**
       
  1139 		 * Filter a sanitized filename string.
       
  1140 		 *
       
  1141 		 * @since 2.8.0
       
  1142 		 *
       
  1143 		 * @param string $filename     Sanitized filename.
       
  1144 		 * @param string $filename_raw The filename prior to sanitization.
       
  1145 		 */
       
  1146 		return apply_filters( 'sanitize_file_name', $filename, $filename_raw );
       
  1147 	}
   856 
  1148 
   857 	// Process multiple extensions
  1149 	// Process multiple extensions
   858 	$filename = array_shift($parts);
  1150 	$filename = array_shift($parts);
   859 	$extension = array_pop($parts);
  1151 	$extension = array_pop($parts);
   860 	$mimes = get_allowed_mime_types();
  1152 	$mimes = get_allowed_mime_types();
   861 
  1153 
   862 	// Loop over any intermediate extensions. Munge them with a trailing underscore if they are a 2 - 5 character
  1154 	/*
   863 	// long alpha string not in the extension whitelist.
  1155 	 * Loop over any intermediate extensions. Postfix them with a trailing underscore
       
  1156 	 * if they are a 2 - 5 character long alpha string not in the extension whitelist.
       
  1157 	 */
   864 	foreach ( (array) $parts as $part) {
  1158 	foreach ( (array) $parts as $part) {
   865 		$filename .= '.' . $part;
  1159 		$filename .= '.' . $part;
   866 
  1160 
   867 		if ( preg_match("/^[a-zA-Z]{2,5}\d?$/", $part) ) {
  1161 		if ( preg_match("/^[a-zA-Z]{2,5}\d?$/", $part) ) {
   868 			$allowed = false;
  1162 			$allowed = false;
   876 			if ( !$allowed )
  1170 			if ( !$allowed )
   877 				$filename .= '_';
  1171 				$filename .= '_';
   878 		}
  1172 		}
   879 	}
  1173 	}
   880 	$filename .= '.' . $extension;
  1174 	$filename .= '.' . $extension;
   881 
  1175 	/** This filter is documented in wp-includes/formatting.php */
   882 	return apply_filters('sanitize_file_name', $filename, $filename_raw);
  1176 	return apply_filters('sanitize_file_name', $filename, $filename_raw);
   883 }
  1177 }
   884 
  1178 
   885 /**
  1179 /**
   886  * Sanitizes a username, stripping out unsafe characters.
  1180  * Sanitizes a username, stripping out unsafe characters.
   889  * alphanumeric, _, space, ., -, @. After sanitizing, it passes the username,
  1183  * alphanumeric, _, space, ., -, @. After sanitizing, it passes the username,
   890  * raw username (the username in the parameter), and the value of $strict as
  1184  * raw username (the username in the parameter), and the value of $strict as
   891  * parameters for the 'sanitize_user' filter.
  1185  * parameters for the 'sanitize_user' filter.
   892  *
  1186  *
   893  * @since 2.0.0
  1187  * @since 2.0.0
   894  * @uses apply_filters() Calls 'sanitize_user' hook on username, raw username,
       
   895  *		and $strict parameter.
       
   896  *
  1188  *
   897  * @param string $username The username to be sanitized.
  1189  * @param string $username The username to be sanitized.
   898  * @param bool $strict If set limits $username to specific characters. Default false.
  1190  * @param bool $strict If set limits $username to specific characters. Default false.
   899  * @return string The sanitized username, after passing through filters.
  1191  * @return string The sanitized username, after passing through filters.
   900  */
  1192  */
   912 
  1204 
   913 	$username = trim( $username );
  1205 	$username = trim( $username );
   914 	// Consolidate contiguous whitespace
  1206 	// Consolidate contiguous whitespace
   915 	$username = preg_replace( '|\s+|', ' ', $username );
  1207 	$username = preg_replace( '|\s+|', ' ', $username );
   916 
  1208 
       
  1209 	/**
       
  1210 	 * Filter a sanitized username string.
       
  1211 	 *
       
  1212 	 * @since 2.0.1
       
  1213 	 *
       
  1214 	 * @param string $username     Sanitized username.
       
  1215 	 * @param string $raw_username The username prior to sanitization.
       
  1216 	 * @param bool   $strict       Whether to limit the sanitization to specific characters. Default false.
       
  1217 	 */
   917 	return apply_filters( 'sanitize_user', $username, $raw_username, $strict );
  1218 	return apply_filters( 'sanitize_user', $username, $raw_username, $strict );
   918 }
  1219 }
   919 
  1220 
   920 /**
  1221 /**
   921  * Sanitizes a string key.
  1222  * Sanitizes a string key.
   929  */
  1230  */
   930 function sanitize_key( $key ) {
  1231 function sanitize_key( $key ) {
   931 	$raw_key = $key;
  1232 	$raw_key = $key;
   932 	$key = strtolower( $key );
  1233 	$key = strtolower( $key );
   933 	$key = preg_replace( '/[^a-z0-9_\-]/', '', $key );
  1234 	$key = preg_replace( '/[^a-z0-9_\-]/', '', $key );
       
  1235 
       
  1236 	/**
       
  1237 	 * Filter a sanitized key string.
       
  1238 	 *
       
  1239 	 * @since 3.0.0
       
  1240 	 *
       
  1241 	 * @param string $key     Sanitized key.
       
  1242 	 * @param string $raw_key The key prior to sanitization.
       
  1243 	 */
   934 	return apply_filters( 'sanitize_key', $key, $raw_key );
  1244 	return apply_filters( 'sanitize_key', $key, $raw_key );
   935 }
  1245 }
   936 
  1246 
   937 /**
  1247 /**
   938  * Sanitizes a title, or returns a fallback title.
  1248  * Sanitizes a title, or returns a fallback title.
   952 	$raw_title = $title;
  1262 	$raw_title = $title;
   953 
  1263 
   954 	if ( 'save' == $context )
  1264 	if ( 'save' == $context )
   955 		$title = remove_accents($title);
  1265 		$title = remove_accents($title);
   956 
  1266 
   957 	$title = apply_filters('sanitize_title', $title, $raw_title, $context);
  1267 	/**
       
  1268 	 * Filter a sanitized title string.
       
  1269 	 *
       
  1270 	 * @since 1.2.0
       
  1271 	 *
       
  1272 	 * @param string $title     Sanitized title.
       
  1273 	 * @param string $raw_title The title prior to sanitization.
       
  1274 	 * @param string $context   The context for which the title is being sanitized.
       
  1275 	 */
       
  1276 	$title = apply_filters( 'sanitize_title', $title, $raw_title, $context );
   958 
  1277 
   959 	if ( '' === $title || false === $title )
  1278 	if ( '' === $title || false === $title )
   960 		$title = $fallback_title;
  1279 		$title = $fallback_title;
   961 
  1280 
   962 	return $title;
  1281 	return $title;
   966  * Sanitizes a title with the 'query' context.
  1285  * Sanitizes a title with the 'query' context.
   967  *
  1286  *
   968  * Used for querying the database for a value from URL.
  1287  * Used for querying the database for a value from URL.
   969  *
  1288  *
   970  * @since 3.1.0
  1289  * @since 3.1.0
   971  * @uses sanitize_title()
       
   972  *
  1290  *
   973  * @param string $title The string to be sanitized.
  1291  * @param string $title The string to be sanitized.
   974  * @return string The sanitized string.
  1292  * @return string The sanitized string.
   975  */
  1293  */
   976 function sanitize_title_for_query( $title ) {
  1294 function sanitize_title_for_query( $title ) {
  1042 
  1360 
  1043 	return $title;
  1361 	return $title;
  1044 }
  1362 }
  1045 
  1363 
  1046 /**
  1364 /**
  1047  * Ensures a string is a valid SQL order by clause.
  1365  * Ensures a string is a valid SQL 'order by' clause.
  1048  *
  1366  *
  1049  * Accepts one or more columns, with or without ASC/DESC, and also accepts
  1367  * Accepts one or more columns, with or without a sort order (ASC / DESC).
  1050  * RAND().
  1368  * e.g. 'column_1', 'column_1, column_2', 'column_1 ASC, column_2 DESC' etc.
       
  1369  *
       
  1370  * Also accepts 'RAND()'.
  1051  *
  1371  *
  1052  * @since 2.5.1
  1372  * @since 2.5.1
  1053  *
  1373  *
  1054  * @param string $orderby Order by string to be checked.
  1374  * @param string $orderby Order by clause to be validated.
  1055  * @return string|bool Returns the order by clause if it is a match, false otherwise.
  1375  * @return string|bool Returns $orderby if valid, false otherwise.
  1056  */
  1376  */
  1057 function sanitize_sql_orderby( $orderby ){
  1377 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);
  1378 	if ( preg_match( '/^\s*(([a-z0-9_]+|`[a-z0-9_]+`)(\s+(ASC|DESC))?\s*(,\s*(?=[a-z0-9_`])|$))+$/i', $orderby ) || preg_match( '/^\s*RAND\(\s*\)\s*$/i', $orderby ) ) {
  1059 	if ( !$obmatches )
  1379 		return $orderby;
  1060 		return false;
  1380 	}
  1061 	return $orderby;
  1381 	return false;
  1062 }
  1382 }
  1063 
  1383 
  1064 /**
  1384 /**
  1065  * Sanitizes an HTML classname to ensure it only contains valid characters.
  1385  * Sanitizes an HTML classname to ensure it only contains valid characters.
  1066  *
  1386  *
  1070  * @todo Expand to support the full range of CDATA that a class attribute can contain.
  1390  * @todo Expand to support the full range of CDATA that a class attribute can contain.
  1071  *
  1391  *
  1072  * @since 2.8.0
  1392  * @since 2.8.0
  1073  *
  1393  *
  1074  * @param string $class The classname to be sanitized
  1394  * @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.
  1395  * @param string $fallback Optional. The value to return if the sanitization ends up as an empty string.
  1076  * 	Defaults to an empty string.
  1396  * 	Defaults to an empty string.
  1077  * @return string The sanitized value
  1397  * @return string The sanitized value
  1078  */
  1398  */
  1079 function sanitize_html_class( $class, $fallback = '' ) {
  1399 function sanitize_html_class( $class, $fallback = '' ) {
  1080 	//Strip out any % encoded octets
  1400 	//Strip out any % encoded octets
  1084 	$sanitized = preg_replace( '/[^A-Za-z0-9_-]/', '', $sanitized );
  1404 	$sanitized = preg_replace( '/[^A-Za-z0-9_-]/', '', $sanitized );
  1085 
  1405 
  1086 	if ( '' == $sanitized )
  1406 	if ( '' == $sanitized )
  1087 		$sanitized = $fallback;
  1407 		$sanitized = $fallback;
  1088 
  1408 
       
  1409 	/**
       
  1410 	 * Filter a sanitized HTML class string.
       
  1411 	 *
       
  1412 	 * @since 2.8.0
       
  1413 	 *
       
  1414 	 * @param string $sanitized The sanitized HTML class.
       
  1415 	 * @param string $class     HTML class before sanitization.
       
  1416 	 * @param string $fallback  The fallback string.
       
  1417 	 */
  1089 	return apply_filters( 'sanitize_html_class', $sanitized, $class, $fallback );
  1418 	return apply_filters( 'sanitize_html_class', $sanitized, $class, $fallback );
  1090 }
  1419 }
  1091 
  1420 
  1092 /**
  1421 /**
  1093  * Converts a number of characters from a string.
  1422  * Converts a number of characters from a string.
  1094  *
  1423  *
  1095  * Metadata tags <<title>> and <<category>> are removed, <<br>> and <<hr>> are
  1424  * Metadata tags `<title>` and `<category>` are removed, `<br>` and `<hr>` are
  1096  * converted into correct XHTML and Unicode characters are converted to the
  1425  * converted into correct XHTML and Unicode characters are converted to the
  1097  * valid range.
  1426  * valid range.
  1098  *
  1427  *
  1099  * @since 0.71
  1428  * @since 0.71
  1100  *
  1429  *
  1167  * @param string $text Text to be balanced
  1496  * @param string $text Text to be balanced
  1168  * @param bool $force If true, forces balancing, ignoring the value of the option. Default false.
  1497  * @param bool $force If true, forces balancing, ignoring the value of the option. Default false.
  1169  * @return string Balanced text
  1498  * @return string Balanced text
  1170  */
  1499  */
  1171 function balanceTags( $text, $force = false ) {
  1500 function balanceTags( $text, $force = false ) {
  1172 	if ( $force || get_option('use_balanceTags') == 1 )
  1501 	if ( $force || get_option('use_balanceTags') == 1 ) {
  1173 		return force_balance_tags( $text );
  1502 		return force_balance_tags( $text );
  1174 	else
  1503 	} else {
  1175 		return $text;
  1504 		return $text;
       
  1505 	}
  1176 }
  1506 }
  1177 
  1507 
  1178 /**
  1508 /**
  1179  * Balances tags of string using a modified stack.
  1509  * Balances tags of string using a modified stack.
  1180  *
  1510  *
  1223 			if( $stacksize <= 0 ) {
  1553 			if( $stacksize <= 0 ) {
  1224 				$tag = '';
  1554 				$tag = '';
  1225 				// or close to be safe $tag = '/' . $tag;
  1555 				// or close to be safe $tag = '/' . $tag;
  1226 			}
  1556 			}
  1227 			// if stacktop value = tag close value then pop
  1557 			// if stacktop value = tag close value then pop
  1228 			else if ( $tagstack[$stacksize - 1] == $tag ) { // found closing tag
  1558 			elseif ( $tagstack[$stacksize - 1] == $tag ) { // found closing tag
  1229 				$tag = '</' . $tag . '>'; // Close Tag
  1559 				$tag = '</' . $tag . '>'; // Close Tag
  1230 				// Pop
  1560 				// Pop
  1231 				array_pop( $tagstack );
  1561 				array_pop( $tagstack );
  1232 				$stacksize--;
  1562 				$stacksize--;
  1233 			} else { // closing tag not at top, search for it
  1563 			} else { // closing tag not at top, search for it
  1318  * @param string $content The text about to be edited.
  1648  * @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).
  1649  * @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.
  1650  * @return string The text after the filter (and possibly htmlspecialchars()) has been run.
  1321  */
  1651  */
  1322 function format_to_edit( $content, $richedit = false ) {
  1652 function format_to_edit( $content, $richedit = false ) {
       
  1653 	/**
       
  1654 	 * Filter the text to be formatted for editing.
       
  1655 	 *
       
  1656 	 * @since 1.2.0
       
  1657 	 *
       
  1658 	 * @param string $content The text, prior to formatting for editing.
       
  1659 	 */
  1323 	$content = apply_filters( 'format_to_edit', $content );
  1660 	$content = apply_filters( 'format_to_edit', $content );
  1324 	if ( ! $richedit )
  1661 	if ( ! $richedit )
  1325 		$content = esc_textarea( $content );
  1662 		$content = esc_textarea( $content );
  1326 	return $content;
  1663 	return $content;
  1327 }
  1664 }
  1328 
  1665 
  1329 /**
  1666 /**
  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.
  1667  * Add leading zeros when necessary.
  1344  *
  1668  *
  1345  * If you set the threshold to '4' and the number is '10', then you will get
  1669  * 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
  1670  * back '0010'. If you set the threshold to '4' and the number is '5000', then you
  1347  * will get back '5000'.
  1671  * will get back '5000'.
  1375 }
  1699 }
  1376 
  1700 
  1377 /**
  1701 /**
  1378  * Appends a trailing slash.
  1702  * Appends a trailing slash.
  1379  *
  1703  *
  1380  * Will remove trailing slash if it exists already before adding a trailing
  1704  * Will remove trailing forward and backslashes if it exists already before adding
  1381  * slash. This prevents double slashing a string or path.
  1705  * a trailing forward slash. This prevents double slashing a string or path.
  1382  *
  1706  *
  1383  * The primary use of this is for paths and thus should be used for paths. It is
  1707  * 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.
  1708  * not restricted to paths and offers no specific path support.
  1385  *
  1709  *
  1386  * @since 1.2.0
  1710  * @since 1.2.0
  1387  * @uses untrailingslashit() Unslashes string if it was slashed already.
       
  1388  *
  1711  *
  1389  * @param string $string What to add the trailing slash to.
  1712  * @param string $string What to add the trailing slash to.
  1390  * @return string String with trailing slash added.
  1713  * @return string String with trailing slash added.
  1391  */
  1714  */
  1392 function trailingslashit($string) {
  1715 function trailingslashit( $string ) {
  1393 	return untrailingslashit($string) . '/';
  1716 	return untrailingslashit( $string ) . '/';
  1394 }
  1717 }
  1395 
  1718 
  1396 /**
  1719 /**
  1397  * Removes trailing slash if it exists.
  1720  * Removes trailing forward slashes and backslashes if they exist.
  1398  *
  1721  *
  1399  * The primary use of this is for paths and thus should be used for paths. It is
  1722  * 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.
  1723  * not restricted to paths and offers no specific path support.
  1401  *
  1724  *
  1402  * @since 2.2.0
  1725  * @since 2.2.0
  1403  *
  1726  *
  1404  * @param string $string What to remove the trailing slash from.
  1727  * @param string $string What to remove the trailing slashes from.
  1405  * @return string String without the trailing slash.
  1728  * @return string String without the trailing slashes.
  1406  */
  1729  */
  1407 function untrailingslashit($string) {
  1730 function untrailingslashit( $string ) {
  1408 	return rtrim($string, '/');
  1731 	return rtrim( $string, '/\\' );
  1409 }
  1732 }
  1410 
  1733 
  1411 /**
  1734 /**
  1412  * Adds slashes to escape strings.
  1735  * Adds slashes to escape strings.
  1413  *
  1736  *
  1487  * @param int $hex_encoding Optional. Set to 1 to enable hex encoding.
  1810  * @param int $hex_encoding Optional. Set to 1 to enable hex encoding.
  1488  * @return string Converted email address.
  1811  * @return string Converted email address.
  1489  */
  1812  */
  1490 function antispambot( $email_address, $hex_encoding = 0 ) {
  1813 function antispambot( $email_address, $hex_encoding = 0 ) {
  1491 	$email_no_spam_address = '';
  1814 	$email_no_spam_address = '';
  1492 	for ( $i = 0; $i < strlen( $email_address ); $i++ ) {
  1815 	for ( $i = 0, $len = strlen( $email_address ); $i < $len; $i++ ) {
  1493 		$j = rand( 0, 1 + $hex_encoding );
  1816 		$j = rand( 0, 1 + $hex_encoding );
  1494 		if ( $j == 0 ) {
  1817 		if ( $j == 0 ) {
  1495 			$email_no_spam_address .= '&#' . ord( $email_address[$i] ) . ';';
  1818 			$email_no_spam_address .= '&#' . ord( $email_address[$i] ) . ';';
  1496 		} elseif ( $j == 1 ) {
  1819 		} elseif ( $j == 1 ) {
  1497 			$email_no_spam_address .= $email_address[$i];
  1820 			$email_no_spam_address .= $email_address[$i];
  1599  * @return string Content with converted URIs.
  1922  * @return string Content with converted URIs.
  1600  */
  1923  */
  1601 function make_clickable( $text ) {
  1924 function make_clickable( $text ) {
  1602 	$r = '';
  1925 	$r = '';
  1603 	$textarr = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags
  1926 	$textarr = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags
       
  1927 	$nested_code_pre = 0; // Keep track of how many levels link is nested inside <pre> or <code>
  1604 	foreach ( $textarr as $piece ) {
  1928 	foreach ( $textarr as $piece ) {
  1605 		if ( empty( $piece ) || ( $piece[0] == '<' && ! preg_match('|^<\s*[\w]{1,20}+://|', $piece) ) ) {
  1929 
       
  1930 		if ( preg_match( '|^<code[\s>]|i', $piece ) || preg_match( '|^<pre[\s>]|i', $piece ) )
       
  1931 			$nested_code_pre++;
       
  1932 		elseif ( ( '</code>' === strtolower( $piece ) || '</pre>' === strtolower( $piece ) ) && $nested_code_pre )
       
  1933 			$nested_code_pre--;
       
  1934 
       
  1935 		if ( $nested_code_pre || empty( $piece ) || ( $piece[0] === '<' && ! preg_match( '|^<\s*[\w]{1,20}+://|', $piece ) ) ) {
  1606 			$r .= $piece;
  1936 			$r .= $piece;
  1607 			continue;
  1937 			continue;
  1608 		}
  1938 		}
  1609 
  1939 
  1610 		// Long strings might contain expensive edge cases ...
  1940 		// Long strings might contain expensive edge cases ...
  1644 			$r .= $ret;
  1974 			$r .= $ret;
  1645 		}
  1975 		}
  1646 	}
  1976 	}
  1647 
  1977 
  1648 	// Cleanup of accidental links within links
  1978 	// Cleanup of accidental links within links
  1649 	$r = preg_replace( '#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i', "$1$3</a>", $r );
  1979 	$r = preg_replace( '#(<a([ \r\n\t]+[^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i', "$1$3</a>", $r );
  1650 	return $r;
  1980 	return $r;
  1651 }
  1981 }
  1652 
  1982 
  1653 /**
  1983 /**
  1654  * Breaks a string into chunks by splitting at whitespace characters.
  1984  * Breaks a string into chunks by splitting at whitespace characters.
  1658  *
  1988  *
  1659  * Joining the returned chunks with empty delimiters reconstructs the input string losslessly.
  1989  * Joining the returned chunks with empty delimiters reconstructs the input string losslessly.
  1660  *
  1990  *
  1661  * Input string must have no null characters (or eventual transformations on output chunks must not care about null characters)
  1991  * Input string must have no null characters (or eventual transformations on output chunks must not care about null characters)
  1662  *
  1992  *
  1663  * <code>
  1993  *     _split_str_by_whitespace( "1234 67890 1234 67890a cd 1234   890 123456789 1234567890a    45678   1 3 5 7 90 ", 10 ) ==
  1664  * _split_str_by_whitespace( "1234 67890 1234 67890a cd 1234   890 123456789 1234567890a    45678   1 3 5 7 90 ", 10 ) ==
  1994  *     array (
  1665  * array (
  1995  *         0 => '1234 67890 ',  // 11 characters: Perfect split
  1666  *   0 => '1234 67890 ',  // 11 characters: Perfect split
  1996  *         1 => '1234 ',        //  5 characters: '1234 67890a' was too long
  1667  *   1 => '1234 ',        //  5 characters: '1234 67890a' was too long
  1997  *         2 => '67890a cd ',   // 10 characters: '67890a cd 1234' was too long
  1668  *   2 => '67890a cd ',   // 10 characters: '67890a cd 1234' was too long
  1998  *         3 => '1234   890 ',  // 11 characters: Perfect split
  1669  *   3 => '1234   890 ',  // 11 characters: Perfect split
  1999  *         4 => '123456789 ',   // 10 characters: '123456789 1234567890a' was too long
  1670  *   4 => '123456789 ',   // 10 characters: '123456789 1234567890a' was too long
  2000  *         5 => '1234567890a ', // 12 characters: Too long, but no inner whitespace on which to split
  1671  *   5 => '1234567890a ', // 12 characters: Too long, but no inner whitespace on which to split
  2001  *         6 => '   45678   ',  // 11 characters: Perfect split
  1672  *   6 => '   45678   ',  // 11 characters: Perfect split
  2002  *         7 => '1 3 5 7 90 ',  // 11 characters: End of $string
  1673  *   7 => '1 3 5 7 9',    //  9 characters: End of $string
  2003  *     );
  1674  * );
       
  1675  * </code>
       
  1676  *
  2004  *
  1677  * @since 3.4.0
  2005  * @since 3.4.0
  1678  * @access private
  2006  * @access private
  1679  *
  2007  *
  1680  * @param string $string The string to split.
  2008  * @param string $string The string to split.
  1744 /**
  2072 /**
  1745  * Convert one smiley code to the icon graphic file equivalent.
  2073  * Convert one smiley code to the icon graphic file equivalent.
  1746  *
  2074  *
  1747  * Callback handler for {@link convert_smilies()}.
  2075  * Callback handler for {@link convert_smilies()}.
  1748  * Looks up one smiley code in the $wpsmiliestrans global array and returns an
  2076  * Looks up one smiley code in the $wpsmiliestrans global array and returns an
  1749  * <img> string for that smiley.
  2077  * `<img>` string for that smiley.
  1750  *
  2078  *
  1751  * @global array $wpsmiliestrans
  2079  * @global array $wpsmiliestrans
  1752  * @since 2.8.0
  2080  * @since 2.8.0
  1753  *
  2081  *
  1754  * @param array $matches Single match. Smiley code to convert to image.
  2082  * @param array $matches Single match. Smiley code to convert to image.
  1760 	if ( count( $matches ) == 0 )
  2088 	if ( count( $matches ) == 0 )
  1761 		return '';
  2089 		return '';
  1762 
  2090 
  1763 	$smiley = trim( reset( $matches ) );
  2091 	$smiley = trim( reset( $matches ) );
  1764 	$img = $wpsmiliestrans[ $smiley ];
  2092 	$img = $wpsmiliestrans[ $smiley ];
  1765 	$smiley_masked = esc_attr( $smiley );
  2093 
  1766 
  2094 	$matches = array();
       
  2095 	$ext = preg_match( '/\.([^.]+)$/', $img, $matches ) ? strtolower( $matches[1] ) : false;
       
  2096 	$image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' );
       
  2097 
       
  2098 	// Don't convert smilies that aren't images - they're probably emoji.
       
  2099 	if ( ! in_array( $ext, $image_exts ) ) {
       
  2100 		return $img;
       
  2101 	}
       
  2102 
       
  2103 	/**
       
  2104 	 * Filter the Smiley image URL before it's used in the image element.
       
  2105 	 *
       
  2106 	 * @since 2.9.0
       
  2107 	 *
       
  2108 	 * @param string $smiley_url URL for the smiley image.
       
  2109 	 * @param string $img        Filename for the smiley image.
       
  2110 	 * @param string $site_url   Site URL, as returned by site_url().
       
  2111 	 */
  1767 	$src_url = apply_filters( 'smilies_src', includes_url( "images/smilies/$img" ), $img, site_url() );
  2112 	$src_url = apply_filters( 'smilies_src', includes_url( "images/smilies/$img" ), $img, site_url() );
  1768 
  2113 
  1769 	return " <img src='$src_url' alt='$smiley_masked' class='wp-smiley' /> ";
  2114 	return sprintf( '<img src="%s" alt="%s" class="wp-smiley" style="height: 1em; max-height: 1em;" />', esc_url( $src_url ), esc_attr( $smiley ) );
  1770 }
  2115 }
  1771 
  2116 
  1772 /**
  2117 /**
  1773  * Convert text equivalent of smilies to images.
  2118  * Convert text equivalent of smilies to images.
  1774  *
  2119  *
  1779  * @uses $wp_smiliessearch
  2124  * @uses $wp_smiliessearch
  1780  *
  2125  *
  1781  * @param string $text Content to convert smilies from text.
  2126  * @param string $text Content to convert smilies from text.
  1782  * @return string Converted content with text smilies replaced with images.
  2127  * @return string Converted content with text smilies replaced with images.
  1783  */
  2128  */
  1784 function convert_smilies($text) {
  2129 function convert_smilies( $text ) {
  1785 	global $wp_smiliessearch;
  2130 	global $wp_smiliessearch;
  1786 	$output = '';
  2131 	$output = '';
  1787 	if ( get_option('use_smilies') && !empty($wp_smiliessearch) ) {
  2132 	if ( get_option( 'use_smilies' ) && ! empty( $wp_smiliessearch ) ) {
  1788 		// HTML loop taken from texturize function, could possible be consolidated
  2133 		// 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
  2134 		$textarr = preg_split( '/(<.*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // capture the tags as well as in between
  1790 		$stop = count($textarr);// loop stuff
  2135 		$stop = count( $textarr );// loop stuff
  1791 		for ($i = 0; $i < $stop; $i++) {
  2136 
       
  2137 		// Ignore proessing of specific tags
       
  2138 		$tags_to_ignore = 'code|pre|style|script|textarea';
       
  2139 		$ignore_block_element = '';
       
  2140 
       
  2141 		for ( $i = 0; $i < $stop; $i++ ) {
  1792 			$content = $textarr[$i];
  2142 			$content = $textarr[$i];
  1793 			if ((strlen($content) > 0) && ('<' != $content[0])) { // If it's not a tag
  2143 
  1794 				$content = preg_replace_callback($wp_smiliessearch, 'translate_smiley', $content);
  2144 			// If we're in an ignore block, wait until we find its closing tag
       
  2145 			if ( '' == $ignore_block_element && preg_match( '/^<(' . $tags_to_ignore . ')>/', $content, $matches ) )  {
       
  2146 				$ignore_block_element = $matches[1];
  1795 			}
  2147 			}
       
  2148 
       
  2149 			// If it's not a tag and not in ignore block
       
  2150 			if ( '' ==  $ignore_block_element && strlen( $content ) > 0 && '<' != $content[0] ) {
       
  2151 				$content = preg_replace_callback( $wp_smiliessearch, 'translate_smiley', $content );
       
  2152 			}
       
  2153 
       
  2154 			// did we exit ignore block
       
  2155 			if ( '' != $ignore_block_element && '</' . $ignore_block_element . '>' == $content )  {
       
  2156 				$ignore_block_element = '';
       
  2157 			}
       
  2158 
  1796 			$output .= $content;
  2159 			$output .= $content;
  1797 		}
  2160 		}
  1798 	} else {
  2161 	} else {
  1799 		// return default text.
  2162 		// return default text.
  1800 		$output = $text;
  2163 		$output = $text;
  1817 	if ( ! empty( $deprecated ) )
  2180 	if ( ! empty( $deprecated ) )
  1818 		_deprecated_argument( __FUNCTION__, '3.0' );
  2181 		_deprecated_argument( __FUNCTION__, '3.0' );
  1819 
  2182 
  1820 	// Test for the minimum length the email can be
  2183 	// Test for the minimum length the email can be
  1821 	if ( strlen( $email ) < 3 ) {
  2184 	if ( strlen( $email ) < 3 ) {
       
  2185 		/**
       
  2186 		 * Filter whether an email address is valid.
       
  2187 		 *
       
  2188 		 * This filter is evaluated under several different contexts, such as 'email_too_short',
       
  2189 		 * 'email_no_at', 'local_invalid_chars', 'domain_period_sequence', 'domain_period_limits',
       
  2190 		 * 'domain_no_periods', 'sub_hyphen_limits', 'sub_invalid_chars', or no specific context.
       
  2191 		 *
       
  2192 		 * @since 2.8.0
       
  2193 		 *
       
  2194 		 * @param bool   $is_email Whether the email address has passed the is_email() checks. Default false.
       
  2195 		 * @param string $email    The email address being checked.
       
  2196 		 * @param string $message  An explanatory message to the user.
       
  2197 		 * @param string $context  Context under which the email was tested.
       
  2198 		 */
  1822 		return apply_filters( 'is_email', false, $email, 'email_too_short' );
  2199 		return apply_filters( 'is_email', false, $email, 'email_too_short' );
  1823 	}
  2200 	}
  1824 
  2201 
  1825 	// Test for an @ character after the first position
  2202 	// Test for an @ character after the first position
  1826 	if ( strpos( $email, '@', 1 ) === false ) {
  2203 	if ( strpos( $email, '@', 1 ) === false ) {
       
  2204 		/** This filter is documented in wp-includes/formatting.php */
  1827 		return apply_filters( 'is_email', false, $email, 'email_no_at' );
  2205 		return apply_filters( 'is_email', false, $email, 'email_no_at' );
  1828 	}
  2206 	}
  1829 
  2207 
  1830 	// Split out the local and domain parts
  2208 	// Split out the local and domain parts
  1831 	list( $local, $domain ) = explode( '@', $email, 2 );
  2209 	list( $local, $domain ) = explode( '@', $email, 2 );
  1832 
  2210 
  1833 	// LOCAL PART
  2211 	// LOCAL PART
  1834 	// Test for invalid characters
  2212 	// Test for invalid characters
  1835 	if ( !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local ) ) {
  2213 	if ( !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local ) ) {
       
  2214 		/** This filter is documented in wp-includes/formatting.php */
  1836 		return apply_filters( 'is_email', false, $email, 'local_invalid_chars' );
  2215 		return apply_filters( 'is_email', false, $email, 'local_invalid_chars' );
  1837 	}
  2216 	}
  1838 
  2217 
  1839 	// DOMAIN PART
  2218 	// DOMAIN PART
  1840 	// Test for sequences of periods
  2219 	// Test for sequences of periods
  1841 	if ( preg_match( '/\.{2,}/', $domain ) ) {
  2220 	if ( preg_match( '/\.{2,}/', $domain ) ) {
       
  2221 		/** This filter is documented in wp-includes/formatting.php */
  1842 		return apply_filters( 'is_email', false, $email, 'domain_period_sequence' );
  2222 		return apply_filters( 'is_email', false, $email, 'domain_period_sequence' );
  1843 	}
  2223 	}
  1844 
  2224 
  1845 	// Test for leading and trailing periods and whitespace
  2225 	// Test for leading and trailing periods and whitespace
  1846 	if ( trim( $domain, " \t\n\r\0\x0B." ) !== $domain ) {
  2226 	if ( trim( $domain, " \t\n\r\0\x0B." ) !== $domain ) {
       
  2227 		/** This filter is documented in wp-includes/formatting.php */
  1847 		return apply_filters( 'is_email', false, $email, 'domain_period_limits' );
  2228 		return apply_filters( 'is_email', false, $email, 'domain_period_limits' );
  1848 	}
  2229 	}
  1849 
  2230 
  1850 	// Split the domain into subs
  2231 	// Split the domain into subs
  1851 	$subs = explode( '.', $domain );
  2232 	$subs = explode( '.', $domain );
  1852 
  2233 
  1853 	// Assume the domain will have at least two subs
  2234 	// Assume the domain will have at least two subs
  1854 	if ( 2 > count( $subs ) ) {
  2235 	if ( 2 > count( $subs ) ) {
       
  2236 		/** This filter is documented in wp-includes/formatting.php */
  1855 		return apply_filters( 'is_email', false, $email, 'domain_no_periods' );
  2237 		return apply_filters( 'is_email', false, $email, 'domain_no_periods' );
  1856 	}
  2238 	}
  1857 
  2239 
  1858 	// Loop through each sub
  2240 	// Loop through each sub
  1859 	foreach ( $subs as $sub ) {
  2241 	foreach ( $subs as $sub ) {
  1860 		// Test for leading and trailing hyphens and whitespace
  2242 		// Test for leading and trailing hyphens and whitespace
  1861 		if ( trim( $sub, " \t\n\r\0\x0B-" ) !== $sub ) {
  2243 		if ( trim( $sub, " \t\n\r\0\x0B-" ) !== $sub ) {
       
  2244 			/** This filter is documented in wp-includes/formatting.php */
  1862 			return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );
  2245 			return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );
  1863 		}
  2246 		}
  1864 
  2247 
  1865 		// Test for invalid characters
  2248 		// Test for invalid characters
  1866 		if ( !preg_match('/^[a-z0-9-]+$/i', $sub ) ) {
  2249 		if ( !preg_match('/^[a-z0-9-]+$/i', $sub ) ) {
       
  2250 			/** This filter is documented in wp-includes/formatting.php */
  1867 			return apply_filters( 'is_email', false, $email, 'sub_invalid_chars' );
  2251 			return apply_filters( 'is_email', false, $email, 'sub_invalid_chars' );
  1868 		}
  2252 		}
  1869 	}
  2253 	}
  1870 
  2254 
  1871 	// Congratulations your email made it!
  2255 	// Congratulations your email made it!
       
  2256 	/** This filter is documented in wp-includes/formatting.php */
  1872 	return apply_filters( 'is_email', $email, $email, null );
  2257 	return apply_filters( 'is_email', $email, $email, null );
  1873 }
  2258 }
  1874 
  2259 
  1875 /**
  2260 /**
  1876  * Convert to ASCII from email subjects.
  2261  * Convert to ASCII from email subjects.
  1896  *
  2281  *
  1897  * @since 3.1.0
  2282  * @since 3.1.0
  1898  * @access private
  2283  * @access private
  1899  *
  2284  *
  1900  * @param array $match The preg_replace_callback matches array
  2285  * @param array $match The preg_replace_callback matches array
  1901  * @return array Converted chars
  2286  * @return string Converted chars
  1902  */
  2287  */
  1903 function _wp_iso_convert( $match ) {
  2288 function _wp_iso_convert( $match ) {
  1904 	return chr( hexdec( strtolower( $match[1] ) ) );
  2289 	return chr( hexdec( strtolower( $match[1] ) ) );
  1905 }
  2290 }
  1906 
  2291 
  1912  * otherwise it simply subtracts the value of the 'gmt_offset' option. Return
  2297  * otherwise it simply subtracts the value of the 'gmt_offset' option. Return
  1913  * format can be overridden using the $format parameter.
  2298  * format can be overridden using the $format parameter.
  1914  *
  2299  *
  1915  * @since 1.2.0
  2300  * @since 1.2.0
  1916  *
  2301  *
  1917  * @uses get_option() to retrieve the value of 'gmt_offset'.
       
  1918  * @param string $string The date to be converted.
  2302  * @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)
  2303  * @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.
  2304  * @return string GMT version of the date provided.
  1921  */
  2305  */
  1922 function get_gmt_from_date( $string, $format = 'Y-m-d H:i:s' ) {
  2306 function get_gmt_from_date( $string, $format = 'Y-m-d H:i:s' ) {
  2013 		$timestamp = gmmktime($date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1]);
  2397 		$timestamp = gmmktime($date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1]);
  2014 		$timestamp -= $offset;
  2398 		$timestamp -= $offset;
  2015 
  2399 
  2016 		return gmdate('Y-m-d H:i:s', $timestamp);
  2400 		return gmdate('Y-m-d H:i:s', $timestamp);
  2017 
  2401 
  2018 	} else if ($timezone == 'user') {
  2402 	} elseif ($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);
  2403 		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 	}
  2404 	}
  2021 }
  2405 }
  2022 
  2406 
  2023 /**
  2407 /**
  2046  * @return string Filtered email address.
  2430  * @return string Filtered email address.
  2047  */
  2431  */
  2048 function sanitize_email( $email ) {
  2432 function sanitize_email( $email ) {
  2049 	// Test for the minimum length the email can be
  2433 	// Test for the minimum length the email can be
  2050 	if ( strlen( $email ) < 3 ) {
  2434 	if ( strlen( $email ) < 3 ) {
       
  2435 		/**
       
  2436 		 * Filter a sanitized email address.
       
  2437 		 *
       
  2438 		 * This filter is evaluated under several contexts, including 'email_too_short',
       
  2439 		 * 'email_no_at', 'local_invalid_chars', 'domain_period_sequence', 'domain_period_limits',
       
  2440 		 * 'domain_no_periods', 'domain_no_valid_subs', or no context.
       
  2441 		 *
       
  2442 		 * @since 2.8.0
       
  2443 		 *
       
  2444 		 * @param string $email   The sanitized email address.
       
  2445 		 * @param string $email   The email address, as provided to sanitize_email().
       
  2446 		 * @param string $message A message to pass to the user.
       
  2447 		 */
  2051 		return apply_filters( 'sanitize_email', '', $email, 'email_too_short' );
  2448 		return apply_filters( 'sanitize_email', '', $email, 'email_too_short' );
  2052 	}
  2449 	}
  2053 
  2450 
  2054 	// Test for an @ character after the first position
  2451 	// Test for an @ character after the first position
  2055 	if ( strpos( $email, '@', 1 ) === false ) {
  2452 	if ( strpos( $email, '@', 1 ) === false ) {
       
  2453 		/** This filter is documented in wp-includes/formatting.php */
  2056 		return apply_filters( 'sanitize_email', '', $email, 'email_no_at' );
  2454 		return apply_filters( 'sanitize_email', '', $email, 'email_no_at' );
  2057 	}
  2455 	}
  2058 
  2456 
  2059 	// Split out the local and domain parts
  2457 	// Split out the local and domain parts
  2060 	list( $local, $domain ) = explode( '@', $email, 2 );
  2458 	list( $local, $domain ) = explode( '@', $email, 2 );
  2061 
  2459 
  2062 	// LOCAL PART
  2460 	// LOCAL PART
  2063 	// Test for invalid characters
  2461 	// Test for invalid characters
  2064 	$local = preg_replace( '/[^a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]/', '', $local );
  2462 	$local = preg_replace( '/[^a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]/', '', $local );
  2065 	if ( '' === $local ) {
  2463 	if ( '' === $local ) {
       
  2464 		/** This filter is documented in wp-includes/formatting.php */
  2066 		return apply_filters( 'sanitize_email', '', $email, 'local_invalid_chars' );
  2465 		return apply_filters( 'sanitize_email', '', $email, 'local_invalid_chars' );
  2067 	}
  2466 	}
  2068 
  2467 
  2069 	// DOMAIN PART
  2468 	// DOMAIN PART
  2070 	// Test for sequences of periods
  2469 	// Test for sequences of periods
  2071 	$domain = preg_replace( '/\.{2,}/', '', $domain );
  2470 	$domain = preg_replace( '/\.{2,}/', '', $domain );
  2072 	if ( '' === $domain ) {
  2471 	if ( '' === $domain ) {
       
  2472 		/** This filter is documented in wp-includes/formatting.php */
  2073 		return apply_filters( 'sanitize_email', '', $email, 'domain_period_sequence' );
  2473 		return apply_filters( 'sanitize_email', '', $email, 'domain_period_sequence' );
  2074 	}
  2474 	}
  2075 
  2475 
  2076 	// Test for leading and trailing periods and whitespace
  2476 	// Test for leading and trailing periods and whitespace
  2077 	$domain = trim( $domain, " \t\n\r\0\x0B." );
  2477 	$domain = trim( $domain, " \t\n\r\0\x0B." );
  2078 	if ( '' === $domain ) {
  2478 	if ( '' === $domain ) {
       
  2479 		/** This filter is documented in wp-includes/formatting.php */
  2079 		return apply_filters( 'sanitize_email', '', $email, 'domain_period_limits' );
  2480 		return apply_filters( 'sanitize_email', '', $email, 'domain_period_limits' );
  2080 	}
  2481 	}
  2081 
  2482 
  2082 	// Split the domain into subs
  2483 	// Split the domain into subs
  2083 	$subs = explode( '.', $domain );
  2484 	$subs = explode( '.', $domain );
  2084 
  2485 
  2085 	// Assume the domain will have at least two subs
  2486 	// Assume the domain will have at least two subs
  2086 	if ( 2 > count( $subs ) ) {
  2487 	if ( 2 > count( $subs ) ) {
       
  2488 		/** This filter is documented in wp-includes/formatting.php */
  2087 		return apply_filters( 'sanitize_email', '', $email, 'domain_no_periods' );
  2489 		return apply_filters( 'sanitize_email', '', $email, 'domain_no_periods' );
  2088 	}
  2490 	}
  2089 
  2491 
  2090 	// Create an array that will contain valid subs
  2492 	// Create an array that will contain valid subs
  2091 	$new_subs = array();
  2493 	$new_subs = array();
  2104 		}
  2506 		}
  2105 	}
  2507 	}
  2106 
  2508 
  2107 	// If there aren't 2 or more valid subs
  2509 	// If there aren't 2 or more valid subs
  2108 	if ( 2 > count( $new_subs ) ) {
  2510 	if ( 2 > count( $new_subs ) ) {
       
  2511 		/** This filter is documented in wp-includes/formatting.php */
  2109 		return apply_filters( 'sanitize_email', '', $email, 'domain_no_valid_subs' );
  2512 		return apply_filters( 'sanitize_email', '', $email, 'domain_no_valid_subs' );
  2110 	}
  2513 	}
  2111 
  2514 
  2112 	// Join valid subs into the new domain
  2515 	// Join valid subs into the new domain
  2113 	$domain = join( '.', $new_subs );
  2516 	$domain = join( '.', $new_subs );
  2114 
  2517 
  2115 	// Put the email back together
  2518 	// Put the email back together
  2116 	$email = $local . '@' . $domain;
  2519 	$email = $local . '@' . $domain;
  2117 
  2520 
  2118 	// Congratulations your email made it!
  2521 	// Congratulations your email made it!
       
  2522 	/** This filter is documented in wp-includes/formatting.php */
  2119 	return apply_filters( 'sanitize_email', $email, $email, null );
  2523 	return apply_filters( 'sanitize_email', $email, $email, null );
  2120 }
  2524 }
  2121 
  2525 
  2122 /**
  2526 /**
  2123  * Determines the difference between two timestamps.
  2527  * Determines the difference between two timestamps.
  2130  * @param int $from Unix timestamp from which the difference begins.
  2534  * @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.
  2535  * @param int $to Optional. Unix timestamp to end the time difference. Default becomes time() if not set.
  2132  * @return string Human readable time difference.
  2536  * @return string Human readable time difference.
  2133  */
  2537  */
  2134 function human_time_diff( $from, $to = '' ) {
  2538 function human_time_diff( $from, $to = '' ) {
  2135 	if ( empty( $to ) )
  2539 	if ( empty( $to ) ) {
  2136 		$to = time();
  2540 		$to = time();
       
  2541 	}
  2137 
  2542 
  2138 	$diff = (int) abs( $to - $from );
  2543 	$diff = (int) abs( $to - $from );
  2139 
  2544 
  2140 	if ( $diff < HOUR_IN_SECONDS ) {
  2545 	if ( $diff < HOUR_IN_SECONDS ) {
  2141 		$mins = round( $diff / MINUTE_IN_SECONDS );
  2546 		$mins = round( $diff / MINUTE_IN_SECONDS );
  2168 		if ( $years <= 1 )
  2573 		if ( $years <= 1 )
  2169 			$years = 1;
  2574 			$years = 1;
  2170 		$since = sprintf( _n( '%s year', '%s years', $years ), $years );
  2575 		$since = sprintf( _n( '%s year', '%s years', $years ), $years );
  2171 	}
  2576 	}
  2172 
  2577 
  2173 	return $since;
  2578 	/**
       
  2579 	 * Filter the human readable difference between two timestamps.
       
  2580 	 *
       
  2581 	 * @since 4.0.0
       
  2582 	 *
       
  2583 	 * @param string $since The difference in human readable text.
       
  2584 	 * @param int    $diff  The difference in seconds.
       
  2585 	 * @param int    $from  Unix timestamp from which the difference begins.
       
  2586 	 * @param int    $to    Unix timestamp to end the time difference.
       
  2587 	 */
       
  2588 	return apply_filters( 'human_time_diff', $since, $diff, $from, $to );
  2174 }
  2589 }
  2175 
  2590 
  2176 /**
  2591 /**
  2177  * Generates an excerpt from the content, if needed.
  2592  * Generates an excerpt from the content, if needed.
  2178  *
  2593  *
  2193 	if ( '' == $text ) {
  2608 	if ( '' == $text ) {
  2194 		$text = get_the_content('');
  2609 		$text = get_the_content('');
  2195 
  2610 
  2196 		$text = strip_shortcodes( $text );
  2611 		$text = strip_shortcodes( $text );
  2197 
  2612 
  2198 		$text = apply_filters('the_content', $text);
  2613 		/** This filter is documented in wp-includes/post-template.php */
       
  2614 		$text = apply_filters( 'the_content', $text );
  2199 		$text = str_replace(']]>', ']]&gt;', $text);
  2615 		$text = str_replace(']]>', ']]&gt;', $text);
  2200 		$excerpt_length = apply_filters('excerpt_length', 55);
  2616 
  2201 		$excerpt_more = apply_filters('excerpt_more', ' ' . '[&hellip;]');
  2617 		/**
       
  2618 		 * Filter the number of words in an excerpt.
       
  2619 		 *
       
  2620 		 * @since 2.7.0
       
  2621 		 *
       
  2622 		 * @param int $number The number of words. Default 55.
       
  2623 		 */
       
  2624 		$excerpt_length = apply_filters( 'excerpt_length', 55 );
       
  2625 		/**
       
  2626 		 * Filter the string in the "more" link displayed after a trimmed excerpt.
       
  2627 		 *
       
  2628 		 * @since 2.9.0
       
  2629 		 *
       
  2630 		 * @param string $more_string The string shown within the more link.
       
  2631 		 */
       
  2632 		$excerpt_more = apply_filters( 'excerpt_more', ' ' . '[&hellip;]' );
  2202 		$text = wp_trim_words( $text, $excerpt_length, $excerpt_more );
  2633 		$text = wp_trim_words( $text, $excerpt_length, $excerpt_more );
  2203 	}
  2634 	}
  2204 	return apply_filters('wp_trim_excerpt', $text, $raw_excerpt);
  2635 	/**
       
  2636 	 * Filter the trimmed excerpt string.
       
  2637 	 *
       
  2638 	 * @since 2.8.0
       
  2639 	 *
       
  2640 	 * @param string $text        The trimmed text.
       
  2641 	 * @param string $raw_excerpt The text prior to trimming.
       
  2642 	 */
       
  2643 	return apply_filters( 'wp_trim_excerpt', $text, $raw_excerpt );
  2205 }
  2644 }
  2206 
  2645 
  2207 /**
  2646 /**
  2208  * Trims text to a certain number of words.
  2647  * Trims text to a certain number of words.
  2209  *
  2648  *
  2239 		$text = implode( $sep, $words_array );
  2678 		$text = implode( $sep, $words_array );
  2240 		$text = $text . $more;
  2679 		$text = $text . $more;
  2241 	} else {
  2680 	} else {
  2242 		$text = implode( $sep, $words_array );
  2681 		$text = implode( $sep, $words_array );
  2243 	}
  2682 	}
       
  2683 	/**
       
  2684 	 * Filter the text content after words have been trimmed.
       
  2685 	 *
       
  2686 	 * @since 3.3.0
       
  2687 	 *
       
  2688 	 * @param string $text          The trimmed text.
       
  2689 	 * @param int    $num_words     The number of words to trim the text to. Default 5.
       
  2690 	 * @param string $more          An optional string to append to the end of the trimmed text, e.g. &hellip;.
       
  2691 	 * @param string $original_text The text before it was trimmed.
       
  2692 	 */
  2244 	return apply_filters( 'wp_trim_words', $text, $num_words, $more, $original_text );
  2693 	return apply_filters( 'wp_trim_words', $text, $num_words, $more, $original_text );
  2245 }
  2694 }
  2246 
  2695 
  2247 /**
  2696 /**
  2248  * Converts named entities into numbered entities.
  2697  * Converts named entities into numbered entities.
  2252  * @param string $text The text within which entities will be converted.
  2701  * @param string $text The text within which entities will be converted.
  2253  * @return string Text with converted entities.
  2702  * @return string Text with converted entities.
  2254  */
  2703  */
  2255 function ent2ncr($text) {
  2704 function ent2ncr($text) {
  2256 
  2705 
  2257 	// Allow a plugin to short-circuit and override the mappings.
  2706 	/**
       
  2707 	 * Filter text before named entities are converted into numbered entities.
       
  2708 	 *
       
  2709 	 * A non-null string must be returned for the filter to be evaluated.
       
  2710 	 *
       
  2711 	 * @since 3.3.0
       
  2712 	 *
       
  2713 	 * @param null   $converted_text The text to be converted. Default null.
       
  2714 	 * @param string $text           The text prior to entity conversion.
       
  2715 	 */
  2258 	$filtered = apply_filters( 'pre_ent2ncr', null, $text );
  2716 	$filtered = apply_filters( 'pre_ent2ncr', null, $text );
  2259 	if( null !== $filtered )
  2717 	if( null !== $filtered )
  2260 		return $filtered;
  2718 		return $filtered;
  2261 
  2719 
  2262 	$to_ncr = array(
  2720 	$to_ncr = array(
  2531  *
  2989  *
  2532  * @param string $text The text to be formatted.
  2990  * @param string $text The text to be formatted.
  2533  * @return string The formatted text after filter is applied.
  2991  * @return string The formatted text after filter is applied.
  2534  */
  2992  */
  2535 function wp_richedit_pre($text) {
  2993 function wp_richedit_pre($text) {
  2536 	// Filtering a blank results in an annoying <br />\n
  2994 	if ( empty( $text ) ) {
  2537 	if ( empty($text) ) return apply_filters('richedit_pre', '');
  2995 		/**
       
  2996 		 * Filter text returned for the rich text editor.
       
  2997 		 *
       
  2998 		 * This filter is first evaluated, and the value returned, if an empty string
       
  2999 		 * is passed to wp_richedit_pre(). If an empty string is passed, it results
       
  3000 		 * in a break tag and line feed.
       
  3001 		 *
       
  3002 		 * If a non-empty string is passed, the filter is evaluated on the wp_richedit_pre()
       
  3003 		 * return after being formatted.
       
  3004 		 *
       
  3005 		 * @since 2.0.0
       
  3006 		 *
       
  3007 		 * @param string $output Text for the rich text editor.
       
  3008 		 */
       
  3009 		return apply_filters( 'richedit_pre', '' );
       
  3010 	}
  2538 
  3011 
  2539 	$output = convert_chars($text);
  3012 	$output = convert_chars($text);
  2540 	$output = wpautop($output);
  3013 	$output = wpautop($output);
  2541 	$output = htmlspecialchars($output, ENT_NOQUOTES, get_option( 'blog_charset' ) );
  3014 	$output = htmlspecialchars($output, ENT_NOQUOTES, get_option( 'blog_charset' ) );
  2542 
  3015 
  2543 	return apply_filters('richedit_pre', $output);
  3016 	/** This filter is documented in wp-includes/formatting.php */
       
  3017 	return apply_filters( 'richedit_pre', $output );
  2544 }
  3018 }
  2545 
  3019 
  2546 /**
  3020 /**
  2547  * Formats text for the HTML editor.
  3021  * Formats text for the HTML editor.
  2548  *
  3022  *
  2556  */
  3030  */
  2557 function wp_htmledit_pre($output) {
  3031 function wp_htmledit_pre($output) {
  2558 	if ( !empty($output) )
  3032 	if ( !empty($output) )
  2559 		$output = htmlspecialchars($output, ENT_NOQUOTES, get_option( 'blog_charset' ) ); // convert only < > &
  3033 		$output = htmlspecialchars($output, ENT_NOQUOTES, get_option( 'blog_charset' ) ); // convert only < > &
  2560 
  3034 
  2561 	return apply_filters('htmledit_pre', $output);
  3035 	/**
       
  3036 	 * Filter the text before it is formatted for the HTML editor.
       
  3037 	 *
       
  3038 	 * @since 2.5.0
       
  3039 	 *
       
  3040 	 * @param string $output The HTML-formatted text.
       
  3041 	 */
       
  3042 	return apply_filters( 'htmledit_pre', $output );
  2562 }
  3043 }
  2563 
  3044 
  2564 /**
  3045 /**
  2565  * Perform a deep string replace operation to ensure the values in $search are no longer present
  3046  * Perform a deep string replace operation to ensure the values in $search are no longer present
  2566  *
  3047  *
  2608  * A number of characters are removed from the URL. If the URL is for displaying
  3089  * 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
  3090  * (the default behaviour) ampersands are also replaced. The 'clean_url' filter
  2610  * is applied to the returned cleaned URL.
  3091  * is applied to the returned cleaned URL.
  2611  *
  3092  *
  2612  * @since 2.8.0
  3093  * @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  *
  3094  *
  2616  * @param string $url The URL to be cleaned.
  3095  * @param string $url The URL to be cleaned.
  2617  * @param array $protocols Optional. An array of acceptable protocols.
  3096  * @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.
  3097  *		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.
  3098  * @param string $_context Private. Use esc_url_raw() for database usage.
  2651 		$good_protocol_url = wp_kses_bad_protocol( $url, $protocols );
  3130 		$good_protocol_url = wp_kses_bad_protocol( $url, $protocols );
  2652 		if ( strtolower( $good_protocol_url ) != strtolower( $url ) )
  3131 		if ( strtolower( $good_protocol_url ) != strtolower( $url ) )
  2653 			return '';
  3132 			return '';
  2654 	}
  3133 	}
  2655 
  3134 
  2656 	return apply_filters('clean_url', $good_protocol_url, $original_url, $_context);
  3135 	/**
       
  3136 	 * Filter a string cleaned and escaped for output as a URL.
       
  3137 	 *
       
  3138 	 * @since 2.3.0
       
  3139 	 *
       
  3140 	 * @param string $good_protocol_url The cleaned URL to be returned.
       
  3141 	 * @param string $original_url      The URL prior to cleaning.
       
  3142 	 * @param string $_context          If 'display', replace ampersands and single quotes only.
       
  3143 	 */
       
  3144 	return apply_filters( 'clean_url', $good_protocol_url, $original_url, $_context );
  2657 }
  3145 }
  2658 
  3146 
  2659 /**
  3147 /**
  2660  * Performs esc_url() for database usage.
  3148  * Performs esc_url() for database usage.
  2661  *
  3149  *
  2662  * @since 2.8.0
  3150  * @since 2.8.0
  2663  * @uses esc_url()
       
  2664  *
  3151  *
  2665  * @param string $url The URL to be cleaned.
  3152  * @param string $url The URL to be cleaned.
  2666  * @param array $protocols An array of acceptable protocols.
  3153  * @param array $protocols An array of acceptable protocols.
  2667  * @return string The cleaned URL.
  3154  * @return string The cleaned URL.
  2668  */
  3155  */
  2702 	$safe_text = wp_check_invalid_utf8( $text );
  3189 	$safe_text = wp_check_invalid_utf8( $text );
  2703 	$safe_text = _wp_specialchars( $safe_text, ENT_COMPAT );
  3190 	$safe_text = _wp_specialchars( $safe_text, ENT_COMPAT );
  2704 	$safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes( $safe_text ) );
  3191 	$safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes( $safe_text ) );
  2705 	$safe_text = str_replace( "\r", '', $safe_text );
  3192 	$safe_text = str_replace( "\r", '', $safe_text );
  2706 	$safe_text = str_replace( "\n", '\\n', addslashes( $safe_text ) );
  3193 	$safe_text = str_replace( "\n", '\\n', addslashes( $safe_text ) );
       
  3194 	/**
       
  3195 	 * Filter a string cleaned and escaped for output in JavaScript.
       
  3196 	 *
       
  3197 	 * Text passed to esc_js() is stripped of invalid or special characters,
       
  3198 	 * and properly slashed for output.
       
  3199 	 *
       
  3200 	 * @since 2.0.6
       
  3201 	 *
       
  3202 	 * @param string $safe_text The text after it has been escaped.
       
  3203  	 * @param string $text      The text prior to being escaped.
       
  3204 	 */
  2707 	return apply_filters( 'js_escape', $safe_text, $text );
  3205 	return apply_filters( 'js_escape', $safe_text, $text );
  2708 }
  3206 }
  2709 
  3207 
  2710 /**
  3208 /**
  2711  * Escaping for HTML blocks.
  3209  * Escaping for HTML blocks.
  2716  * @return string
  3214  * @return string
  2717  */
  3215  */
  2718 function esc_html( $text ) {
  3216 function esc_html( $text ) {
  2719 	$safe_text = wp_check_invalid_utf8( $text );
  3217 	$safe_text = wp_check_invalid_utf8( $text );
  2720 	$safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
  3218 	$safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
       
  3219 	/**
       
  3220 	 * Filter a string cleaned and escaped for output in HTML.
       
  3221 	 *
       
  3222 	 * Text passed to esc_html() is stripped of invalid or special characters
       
  3223 	 * before output.
       
  3224 	 *
       
  3225 	 * @since 2.8.0
       
  3226 	 *
       
  3227 	 * @param string $safe_text The text after it has been escaped.
       
  3228  	 * @param string $text      The text prior to being escaped.
       
  3229 	 */
  2721 	return apply_filters( 'esc_html', $safe_text, $text );
  3230 	return apply_filters( 'esc_html', $safe_text, $text );
  2722 }
  3231 }
  2723 
  3232 
  2724 /**
  3233 /**
  2725  * Escaping for HTML attributes.
  3234  * Escaping for HTML attributes.
  2730  * @return string
  3239  * @return string
  2731  */
  3240  */
  2732 function esc_attr( $text ) {
  3241 function esc_attr( $text ) {
  2733 	$safe_text = wp_check_invalid_utf8( $text );
  3242 	$safe_text = wp_check_invalid_utf8( $text );
  2734 	$safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
  3243 	$safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
       
  3244 	/**
       
  3245 	 * Filter a string cleaned and escaped for output in an HTML attribute.
       
  3246 	 *
       
  3247 	 * Text passed to esc_attr() is stripped of invalid or special characters
       
  3248 	 * before output.
       
  3249 	 *
       
  3250 	 * @since 2.0.6
       
  3251 	 *
       
  3252 	 * @param string $safe_text The text after it has been escaped.
       
  3253  	 * @param string $text      The text prior to being escaped.
       
  3254 	 */
  2735 	return apply_filters( 'attribute_escape', $safe_text, $text );
  3255 	return apply_filters( 'attribute_escape', $safe_text, $text );
  2736 }
  3256 }
  2737 
  3257 
  2738 /**
  3258 /**
  2739  * Escaping for textarea values.
  3259  * Escaping for textarea values.
  2743  * @param string $text
  3263  * @param string $text
  2744  * @return string
  3264  * @return string
  2745  */
  3265  */
  2746 function esc_textarea( $text ) {
  3266 function esc_textarea( $text ) {
  2747 	$safe_text = htmlspecialchars( $text, ENT_QUOTES, get_option( 'blog_charset' ) );
  3267 	$safe_text = htmlspecialchars( $text, ENT_QUOTES, get_option( 'blog_charset' ) );
       
  3268 	/**
       
  3269 	 * Filter a string cleaned and escaped for output in a textarea element.
       
  3270 	 *
       
  3271 	 * @since 3.1.0
       
  3272 	 *
       
  3273 	 * @param string $safe_text The text after it has been escaped.
       
  3274  	 * @param string $text      The text prior to being escaped.
       
  3275 	 */
  2748 	return apply_filters( 'esc_textarea', $safe_text, $text );
  3276 	return apply_filters( 'esc_textarea', $safe_text, $text );
  2749 }
  3277 }
  2750 
  3278 
  2751 /**
  3279 /**
  2752  * Escape an HTML tag name.
  3280  * Escape an HTML tag name.
  2756  * @param string $tag_name
  3284  * @param string $tag_name
  2757  * @return string
  3285  * @return string
  2758  */
  3286  */
  2759 function tag_escape($tag_name) {
  3287 function tag_escape($tag_name) {
  2760 	$safe_tag = strtolower( preg_replace('/[^a-zA-Z0-9_:]/', '', $tag_name) );
  3288 	$safe_tag = strtolower( preg_replace('/[^a-zA-Z0-9_:]/', '', $tag_name) );
  2761 	return apply_filters('tag_escape', $safe_tag, $tag_name);
  3289 	/**
  2762 }
  3290 	 * Filter a string cleaned and escaped for output as an HTML tag.
  2763 
  3291 	 *
  2764 /**
  3292 	 * @since 2.8.0
  2765  * Escapes text for SQL LIKE special characters % and _.
  3293 	 *
  2766  *
  3294 	 * @param string $safe_tag The tag name after it has been escaped.
  2767  * @since 2.5.0
  3295  	 * @param string $tag_name The text before it was escaped.
  2768  *
  3296 	 */
  2769  * @param string $text The text to be escaped.
  3297 	return apply_filters( 'tag_escape', $safe_tag, $tag_name );
  2770  * @return string text, safe for inclusion in LIKE query.
       
  2771  */
       
  2772 function like_escape($text) {
       
  2773 	return str_replace(array("%", "_"), array("\\%", "\\_"), $text);
       
  2774 }
  3298 }
  2775 
  3299 
  2776 /**
  3300 /**
  2777  * Convert full URL paths to absolute paths.
  3301  * Convert full URL paths to absolute paths.
  2778  *
  3302  *
  2779  * Removes the http or https protocols and the domain. Keeps the path '/' at the
  3303  * 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.
  3304  * beginning, so it isn't a true relative link, but from the web root base.
  2781  *
  3305  *
  2782  * @since 2.1.0
  3306  * @since 2.1.0
       
  3307  * @since 4.1.0 Support was added for relative URLs.
  2783  *
  3308  *
  2784  * @param string $link Full URL path.
  3309  * @param string $link Full URL path.
  2785  * @return string Absolute path.
  3310  * @return string Absolute path.
  2786  */
  3311  */
  2787 function wp_make_link_relative( $link ) {
  3312 function wp_make_link_relative( $link ) {
  2788 	return preg_replace( '|https?://[^/]+(/.*)|i', '$1', $link );
  3313 	return preg_replace( '|^(https?:)?//[^/]+(/.*)|i', '$2', $link );
  2789 }
  3314 }
  2790 
  3315 
  2791 /**
  3316 /**
  2792  * Sanitises various option values based on the nature of the option.
  3317  * Sanitises various option values based on the nature of the option.
  2793  *
  3318  *
  2799  * @param string $option The name of the option.
  3324  * @param string $option The name of the option.
  2800  * @param string $value The unsanitised value.
  3325  * @param string $value The unsanitised value.
  2801  * @return string Sanitized value.
  3326  * @return string Sanitized value.
  2802  */
  3327  */
  2803 function sanitize_option($option, $value) {
  3328 function sanitize_option($option, $value) {
       
  3329 	global $wpdb;
  2804 
  3330 
  2805 	switch ( $option ) {
  3331 	switch ( $option ) {
  2806 		case 'admin_email' :
  3332 		case 'admin_email' :
  2807 		case 'new_admin_email' :
  3333 		case 'new_admin_email' :
       
  3334 			$value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  2808 			$value = sanitize_email( $value );
  3335 			$value = sanitize_email( $value );
  2809 			if ( ! is_email( $value ) ) {
  3336 			if ( ! is_email( $value ) ) {
  2810 				$value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
  3337 				$value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
  2811 				if ( function_exists( 'add_settings_error' ) )
  3338 				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.' ) );
  3339 					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.' ) );
  2851 				$value = 'closed';
  3378 				$value = 'closed';
  2852 			break;
  3379 			break;
  2853 
  3380 
  2854 		case 'blogdescription':
  3381 		case 'blogdescription':
  2855 		case 'blogname':
  3382 		case 'blogname':
       
  3383 			$value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  2856 			$value = wp_kses_post( $value );
  3384 			$value = wp_kses_post( $value );
  2857 			$value = esc_html( $value );
  3385 			$value = esc_html( $value );
  2858 			break;
  3386 			break;
  2859 
  3387 
  2860 		case 'blog_charset':
  3388 		case 'blog_charset':
  2873 		case 'time_format':
  3401 		case 'time_format':
  2874 		case 'mailserver_url':
  3402 		case 'mailserver_url':
  2875 		case 'mailserver_login':
  3403 		case 'mailserver_login':
  2876 		case 'mailserver_pass':
  3404 		case 'mailserver_pass':
  2877 		case 'upload_path':
  3405 		case 'upload_path':
       
  3406 			$value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  2878 			$value = strip_tags( $value );
  3407 			$value = strip_tags( $value );
  2879 			$value = wp_kses_data( $value );
  3408 			$value = wp_kses_data( $value );
  2880 			break;
  3409 			break;
  2881 
  3410 
  2882 		case 'ping_sites':
  3411 		case 'ping_sites':
  2889 		case 'gmt_offset':
  3418 		case 'gmt_offset':
  2890 			$value = preg_replace('/[^0-9:.-]/', '', $value); // strips slashes
  3419 			$value = preg_replace('/[^0-9:.-]/', '', $value); // strips slashes
  2891 			break;
  3420 			break;
  2892 
  3421 
  2893 		case 'siteurl':
  3422 		case 'siteurl':
       
  3423 			$value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  2894 			if ( (bool)preg_match( '#http(s?)://(.+)#i', $value) ) {
  3424 			if ( (bool)preg_match( '#http(s?)://(.+)#i', $value) ) {
  2895 				$value = esc_url_raw($value);
  3425 				$value = esc_url_raw($value);
  2896 			} else {
  3426 			} else {
  2897 				$value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
  3427 				$value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
  2898 				if ( function_exists('add_settings_error') )
  3428 				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.'));
  3429 					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 			}
  3430 			}
  2901 			break;
  3431 			break;
  2902 
  3432 
  2903 		case 'home':
  3433 		case 'home':
       
  3434 			$value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  2904 			if ( (bool)preg_match( '#http(s?)://(.+)#i', $value) ) {
  3435 			if ( (bool)preg_match( '#http(s?)://(.+)#i', $value) ) {
  2905 				$value = esc_url_raw($value);
  3436 				$value = esc_url_raw($value);
  2906 			} else {
  3437 			} else {
  2907 				$value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
  3438 				$value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
  2908 				if ( function_exists('add_settings_error') )
  3439 				if ( function_exists('add_settings_error') )
  2910 			}
  3441 			}
  2911 			break;
  3442 			break;
  2912 
  3443 
  2913 		case 'WPLANG':
  3444 		case 'WPLANG':
  2914 			$allowed = get_available_languages();
  3445 			$allowed = get_available_languages();
  2915 			if ( ! in_array( $value, $allowed ) && ! empty( $value ) )
  3446 			if ( ! is_multisite() && defined( 'WPLANG' ) && '' !== WPLANG && 'en_US' !== WPLANG ) {
       
  3447 				$allowed[] = WPLANG;
       
  3448 			}
       
  3449 			if ( ! in_array( $value, $allowed ) && ! empty( $value ) ) {
  2916 				$value = get_option( $option );
  3450 				$value = get_option( $option );
       
  3451 			}
  2917 			break;
  3452 			break;
  2918 
  3453 
  2919 		case 'illegal_names':
  3454 		case 'illegal_names':
       
  3455 			$value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  2920 			if ( ! is_array( $value ) )
  3456 			if ( ! is_array( $value ) )
  2921 				$value = explode( ' ', $value );
  3457 				$value = explode( ' ', $value );
  2922 
  3458 
  2923 			$value = array_values( array_filter( array_map( 'trim', $value ) ) );
  3459 			$value = array_values( array_filter( array_map( 'trim', $value ) ) );
  2924 
  3460 
  2926 				$value = '';
  3462 				$value = '';
  2927 			break;
  3463 			break;
  2928 
  3464 
  2929 		case 'limited_email_domains':
  3465 		case 'limited_email_domains':
  2930 		case 'banned_email_domains':
  3466 		case 'banned_email_domains':
       
  3467 			$value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  2931 			if ( ! is_array( $value ) )
  3468 			if ( ! is_array( $value ) )
  2932 				$value = explode( "\n", $value );
  3469 				$value = explode( "\n", $value );
  2933 
  3470 
  2934 			$domains = array_values( array_filter( array_map( 'trim', $value ) ) );
  3471 			$domains = array_values( array_filter( array_map( 'trim', $value ) ) );
  2935 			$value = array();
  3472 			$value = array();
  2952 			break;
  3489 			break;
  2953 
  3490 
  2954 		case 'permalink_structure':
  3491 		case 'permalink_structure':
  2955 		case 'category_base':
  3492 		case 'category_base':
  2956 		case 'tag_base':
  3493 		case 'tag_base':
       
  3494 			$value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  2957 			$value = esc_url_raw( $value );
  3495 			$value = esc_url_raw( $value );
  2958 			$value = str_replace( 'http://', '', $value );
  3496 			$value = str_replace( 'http://', '', $value );
  2959 			break;
  3497 			break;
  2960 
  3498 
  2961 		case 'default_role' :
  3499 		case 'default_role' :
  2962 			if ( ! get_role( $value ) && get_role( 'subscriber' ) )
  3500 			if ( ! get_role( $value ) && get_role( 'subscriber' ) )
  2963 				$value = 'subscriber';
  3501 				$value = 'subscriber';
  2964 			break;
  3502 			break;
  2965 	}
  3503 
  2966 
  3504 		case 'moderation_keys':
  2967 	$value = apply_filters("sanitize_option_{$option}", $value, $option);
  3505 		case 'blacklist_keys':
       
  3506 			$value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
       
  3507 			$value = explode( "\n", $value );
       
  3508 			$value = array_filter( array_map( 'trim', $value ) );
       
  3509 			$value = array_unique( $value );
       
  3510 			$value = implode( "\n", $value );
       
  3511 			break;
       
  3512 	}
       
  3513 
       
  3514 	/**
       
  3515 	 * Filter an option value following sanitization.
       
  3516 	 *
       
  3517 	 * @since 2.3.0
       
  3518 	 *
       
  3519 	 * @param string $value  The sanitized option value.
       
  3520 	 * @param string $option The option name.
       
  3521 	 */
       
  3522 	$value = apply_filters( "sanitize_option_{$option}", $value, $option );
  2968 
  3523 
  2969 	return $value;
  3524 	return $value;
  2970 }
  3525 }
  2971 
  3526 
  2972 /**
  3527 /**
  2974  *
  3529  *
  2975  * Uses {@link http://www.php.net/parse_str parse_str()} and stripslashes if
  3530  * 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.
  3531  * {@link http://www.php.net/magic_quotes magic_quotes_gpc} is on.
  2977  *
  3532  *
  2978  * @since 2.2.1
  3533  * @since 2.2.1
  2979  * @uses apply_filters() for the 'wp_parse_str' filter.
       
  2980  *
  3534  *
  2981  * @param string $string The string to be parsed.
  3535  * @param string $string The string to be parsed.
  2982  * @param array $array Variables will be stored in this array.
  3536  * @param array $array Variables will be stored in this array.
  2983  */
  3537  */
  2984 function wp_parse_str( $string, &$array ) {
  3538 function wp_parse_str( $string, &$array ) {
  2985 	parse_str( $string, $array );
  3539 	parse_str( $string, $array );
  2986 	if ( get_magic_quotes_gpc() )
  3540 	if ( get_magic_quotes_gpc() )
  2987 		$array = stripslashes_deep( $array );
  3541 		$array = stripslashes_deep( $array );
       
  3542 	/**
       
  3543 	 * Filter the array of variables derived from a parsed string.
       
  3544 	 *
       
  3545 	 * @since 2.3.0
       
  3546 	 *
       
  3547 	 * @param array $array The array populated with variables.
       
  3548 	 */
  2988 	$array = apply_filters( 'wp_parse_str', $array );
  3549 	$array = apply_filters( 'wp_parse_str', $array );
  2989 }
  3550 }
  2990 
  3551 
  2991 /**
  3552 /**
  2992  * Convert lone less than signs.
  3553  * Convert lone less than signs.
  2993  *
  3554  *
  2994  * KSES already converts lone greater than signs.
  3555  * KSES already converts lone greater than signs.
  2995  *
  3556  *
  2996  * @uses wp_pre_kses_less_than_callback in the callback function.
       
  2997  * @since 2.3.0
  3557  * @since 2.3.0
  2998  *
  3558  *
  2999  * @param string $text Text to be converted.
  3559  * @param string $text Text to be converted.
  3000  * @return string Converted text.
  3560  * @return string Converted text.
  3001  */
  3561  */
  3004 }
  3564 }
  3005 
  3565 
  3006 /**
  3566 /**
  3007  * Callback function used by preg_replace.
  3567  * Callback function used by preg_replace.
  3008  *
  3568  *
  3009  * @uses esc_html to format the $matches text.
       
  3010  * @since 2.3.0
  3569  * @since 2.3.0
  3011  *
  3570  *
  3012  * @param array $matches Populated by matches to preg_replace.
  3571  * @param array $matches Populated by matches to preg_replace.
  3013  * @return string The text returned after esc_html if needed.
  3572  * @return string The text returned after esc_html if needed.
  3014  */
  3573  */
  3023  *
  3582  *
  3024  * @since 2.5.0
  3583  * @since 2.5.0
  3025  * @link http://www.php.net/sprintf
  3584  * @link http://www.php.net/sprintf
  3026  *
  3585  *
  3027  * @param string $pattern The string which formatted args are inserted.
  3586  * @param string $pattern The string which formatted args are inserted.
  3028  * @param mixed $args,... Arguments to be formatted into the $pattern string.
  3587  * @param mixed  $args ,... Arguments to be formatted into the $pattern string.
  3029  * @return string The formatted string.
  3588  * @return string The formatted string.
  3030  */
  3589  */
  3031 function wp_sprintf( $pattern ) {
  3590 function wp_sprintf( $pattern ) {
  3032 	$args = func_get_args();
  3591 	$args = func_get_args();
  3033 	$len = strlen($pattern);
  3592 	$len = strlen($pattern);
  3063 			} else {
  3622 			} else {
  3064 				++$arg_index;
  3623 				++$arg_index;
  3065 				$arg = isset($args[$arg_index]) ? $args[$arg_index] : '';
  3624 				$arg = isset($args[$arg_index]) ? $args[$arg_index] : '';
  3066 			}
  3625 			}
  3067 
  3626 
  3068 			// Apply filters OR sprintf
  3627 			/**
       
  3628 			 * Filter a fragment from the pattern passed to wp_sprintf().
       
  3629 			 *
       
  3630 			 * If the fragment is unchanged, then sprintf() will be run on the fragment.
       
  3631 			 *
       
  3632 			 * @since 2.5.0
       
  3633 			 *
       
  3634 			 * @param string $fragment A fragment from the pattern.
       
  3635 			 * @param string $arg      The argument.
       
  3636 			 */
  3069 			$_fragment = apply_filters( 'wp_sprintf', $fragment, $arg );
  3637 			$_fragment = apply_filters( 'wp_sprintf', $fragment, $arg );
  3070 			if ( $_fragment != $fragment )
  3638 			if ( $_fragment != $fragment )
  3071 				$fragment = $_fragment;
  3639 				$fragment = $_fragment;
  3072 			else
  3640 			else
  3073 				$fragment = sprintf($fragment, strval($arg) );
  3641 				$fragment = sprintf($fragment, strval($arg) );
  3100 
  3668 
  3101 	// Nothing to work with
  3669 	// Nothing to work with
  3102 	if ( empty($args) )
  3670 	if ( empty($args) )
  3103 		return '';
  3671 		return '';
  3104 
  3672 
  3105 	// Translate and filter the delimiter set (avoid ampersands and entities here)
  3673 	/**
  3106 	$l = apply_filters('wp_sprintf_l', array(
  3674 	 * Filter the translated delimiters used by wp_sprintf_l().
  3107 		/* translators: used between list items, there is a space after the comma */
  3675 	 * Placeholders (%s) are included to assist translators and then
  3108 		'between'          => __(', '),
  3676 	 * removed before the array of strings reaches the filter.
  3109 		/* translators: used between list items, there is a space after the and */
  3677 	 *
  3110 		'between_last_two' => __(', and '),
  3678 	 * Please note: Ampersands and entities should be avoided here.
  3111 		/* translators: used between only two list items, there is a space after the and */
  3679 	 *
  3112 		'between_only_two' => __(' and '),
  3680 	 * @since 2.5.0
  3113 		));
  3681 	 *
       
  3682 	 * @param array $delimiters An array of translated delimiters.
       
  3683 	 */
       
  3684 	$l = apply_filters( 'wp_sprintf_l', array(
       
  3685 		/* translators: used to join items in a list with more than 2 items */
       
  3686 		'between'          => sprintf( __('%s, %s'), '', '' ),
       
  3687 		/* translators: used to join last two items in a list with more than 2 times */
       
  3688 		'between_last_two' => sprintf( __('%s, and %s'), '', '' ),
       
  3689 		/* translators: used to join items in a list with only 2 items */
       
  3690 		'between_only_two' => sprintf( __('%s and %s'), '', '' ),
       
  3691 	) );
  3114 
  3692 
  3115 	$args = (array) $args;
  3693 	$args = (array) $args;
  3116 	$result = array_shift($args);
  3694 	$result = array_shift($args);
  3117 	if ( count($args) == 1 )
  3695 	if ( count($args) == 1 )
  3118 		$result .= $l['between_only_two'] . array_shift($args);
  3696 		$result .= $l['between_only_two'] . array_shift($args);
  3188 	global $_links_add_base;
  3766 	global $_links_add_base;
  3189 	//1 = attribute name  2 = quotation mark  3 = URL
  3767 	//1 = attribute name  2 = quotation mark  3 = URL
  3190 	return $m[1] . '=' . $m[2] .
  3768 	return $m[1] . '=' . $m[2] .
  3191 		( preg_match( '#^(\w{1,20}):#', $m[3], $protocol ) && in_array( $protocol[1], wp_allowed_protocols() ) ?
  3769 		( preg_match( '#^(\w{1,20}):#', $m[3], $protocol ) && in_array( $protocol[1], wp_allowed_protocols() ) ?
  3192 			$m[3] :
  3770 			$m[3] :
  3193 			path_join( $_links_add_base, $m[3] ) )
  3771 			WP_HTTP::make_absolute_url( $m[3], $_links_add_base )
       
  3772 		)
  3194 		. $m[2];
  3773 		. $m[2];
  3195 }
  3774 }
  3196 
  3775 
  3197 /**
  3776 /**
  3198  * Adds a Target attribute to all links in passed content.
  3777  * Adds a Target attribute to all links in passed content.
  3199  *
  3778  *
  3200  * This function by default only applies to <a> tags, however this can be
  3779  * This function by default only applies to `<a>` tags, however this can be
  3201  * modified by the 3rd param.
  3780  * modified by the 3rd param.
  3202  *
  3781  *
  3203  * <b>NOTE:</b> Any current target attributed will be stripped and replaced.
  3782  * *NOTE:* Any current target attributed will be stripped and replaced.
  3204  *
  3783  *
  3205  * @since 2.7.0
  3784  * @since 2.7.0
  3206  *
  3785  *
  3207  * @param string $content String to search for links in.
  3786  * @param string $content String to search for links in.
  3208  * @param string $target The Target to add to the links.
  3787  * @param string $target The Target to add to the links.
  3211  */
  3790  */
  3212 function links_add_target( $content, $target = '_blank', $tags = array('a') ) {
  3791 function links_add_target( $content, $target = '_blank', $tags = array('a') ) {
  3213 	global $_links_add_target;
  3792 	global $_links_add_target;
  3214 	$_links_add_target = $target;
  3793 	$_links_add_target = $target;
  3215 	$tags = implode('|', (array)$tags);
  3794 	$tags = implode('|', (array)$tags);
  3216 	return preg_replace_callback( "!<($tags)(.+?)>!i", '_links_add_target', $content );
  3795 	return preg_replace_callback( "!<($tags)([^>]*)>!i", '_links_add_target', $content );
  3217 }
  3796 }
  3218 
  3797 
  3219 /**
  3798 /**
  3220  * Callback to add a target attribute to all links in passed content.
  3799  * Callback to add a target attribute to all links in passed content.
  3221  *
  3800  *
  3226  * @return string The processed link.
  3805  * @return string The processed link.
  3227  */
  3806  */
  3228 function _links_add_target( $m ) {
  3807 function _links_add_target( $m ) {
  3229 	global $_links_add_target;
  3808 	global $_links_add_target;
  3230 	$tag = $m[1];
  3809 	$tag = $m[1];
  3231 	$link = preg_replace('|(target=([\'"])(.*?)\2)|i', '', $m[2]);
  3810 	$link = preg_replace('|( target=([\'"])(.*?)\2)|i', '', $m[2]);
  3232 	return '<' . $tag . $link . ' target="' . esc_attr( $_links_add_target ) . '">';
  3811 	return '<' . $tag . $link . ' target="' . esc_attr( $_links_add_target ) . '">';
  3233 }
  3812 }
  3234 
  3813 
  3235 /**
  3814 /**
  3236  * Normalize EOL characters and strip duplicate whitespace.
  3815  * Normalize EOL characters and strip duplicate whitespace.
  3247 	return $str;
  3826 	return $str;
  3248 }
  3827 }
  3249 
  3828 
  3250 /**
  3829 /**
  3251  * Properly strip all HTML tags including script and style
  3830  * Properly strip all HTML tags including script and style
       
  3831  *
       
  3832  * This differs from strip_tags() because it removes the contents of
       
  3833  * the `<script>` and `<style>` tags. E.g. `strip_tags( '<script>something</script>' )`
       
  3834  * will return 'something'. wp_strip_all_tags will return ''
  3252  *
  3835  *
  3253  * @since 2.9.0
  3836  * @since 2.9.0
  3254  *
  3837  *
  3255  * @param string $string String containing HTML tags
  3838  * @param string $string String containing HTML tags
  3256  * @param bool $remove_breaks optional Whether to remove left over line breaks and white space chars
  3839  * @param bool $remove_breaks optional Whether to remove left over line breaks and white space chars
  3300 	if ( $found ) {
  3883 	if ( $found ) {
  3301 		// Strip out the whitespace that may now exist after removing the octets.
  3884 		// Strip out the whitespace that may now exist after removing the octets.
  3302 		$filtered = trim( preg_replace('/ +/', ' ', $filtered) );
  3885 		$filtered = trim( preg_replace('/ +/', ' ', $filtered) );
  3303 	}
  3886 	}
  3304 
  3887 
  3305 	return apply_filters('sanitize_text_field', $filtered, $str);
  3888 	/**
       
  3889 	 * Filter a sanitized text field string.
       
  3890 	 *
       
  3891 	 * @since 2.9.0
       
  3892 	 *
       
  3893 	 * @param string $filtered The sanitized string.
       
  3894 	 * @param string $str      The string prior to being sanitized.
       
  3895 	 */
       
  3896 	return apply_filters( 'sanitize_text_field', $filtered, $str );
  3306 }
  3897 }
  3307 
  3898 
  3308 /**
  3899 /**
  3309  * i18n friendly version of basename()
  3900  * i18n friendly version of basename()
  3310  *
  3901  *
  3325  *
  3916  *
  3326  * @since 3.0.0
  3917  * @since 3.0.0
  3327  */
  3918  */
  3328 function capital_P_dangit( $text ) {
  3919 function capital_P_dangit( $text ) {
  3329 	// Simple replacement for titles
  3920 	// Simple replacement for titles
  3330 	if ( 'the_title' === current_filter() )
  3921 	$current_filter = current_filter();
       
  3922 	if ( 'the_title' === $current_filter || 'wp_title' === $current_filter )
  3331 		return str_replace( 'Wordpress', 'WordPress', $text );
  3923 		return str_replace( 'Wordpress', 'WordPress', $text );
  3332 	// Still here? Use the more judicious replacement
  3924 	// Still here? Use the more judicious replacement
  3333 	static $dblq = false;
  3925 	static $dblq = false;
  3334 	if ( false === $dblq )
  3926 	if ( false === $dblq )
  3335 		$dblq = _x( '&#8220;', 'opening curly double quote' );
  3927 		$dblq = _x( '&#8220;', 'opening curly double quote' );
  3348  * @param string $mime_type Mime type
  3940  * @param string $mime_type Mime type
  3349  * @return string Sanitized mime type
  3941  * @return string Sanitized mime type
  3350  */
  3942  */
  3351 function sanitize_mime_type( $mime_type ) {
  3943 function sanitize_mime_type( $mime_type ) {
  3352 	$sani_mime_type = preg_replace( '/[^-+*.a-zA-Z0-9\/]/', '', $mime_type );
  3944 	$sani_mime_type = preg_replace( '/[^-+*.a-zA-Z0-9\/]/', '', $mime_type );
       
  3945 	/**
       
  3946 	 * Filter a mime type following sanitization.
       
  3947 	 *
       
  3948 	 * @since 3.1.3
       
  3949 	 *
       
  3950 	 * @param string $sani_mime_type The sanitized mime type.
       
  3951 	 * @param string $mime_type      The mime type prior to sanitization.
       
  3952 	 */
  3353 	return apply_filters( 'sanitize_mime_type', $sani_mime_type, $mime_type );
  3953 	return apply_filters( 'sanitize_mime_type', $sani_mime_type, $mime_type );
  3354 }
  3954 }
  3355 
  3955 
  3356 /**
  3956 /**
  3357  * Sanitize space or carriage return separated URLs that are used to send trackbacks.
  3957  * Sanitize space or carriage return separated URLs that are used to send trackbacks.
  3367 		if ( !preg_match( '#^https?://.#i', $url ) )
  3967 		if ( !preg_match( '#^https?://.#i', $url ) )
  3368 			unset( $urls_to_ping[$k] );
  3968 			unset( $urls_to_ping[$k] );
  3369 	}
  3969 	}
  3370 	$urls_to_ping = array_map( 'esc_url_raw', $urls_to_ping );
  3970 	$urls_to_ping = array_map( 'esc_url_raw', $urls_to_ping );
  3371 	$urls_to_ping = implode( "\n", $urls_to_ping );
  3971 	$urls_to_ping = implode( "\n", $urls_to_ping );
       
  3972 	/**
       
  3973 	 * Filter a list of trackback URLs following sanitization.
       
  3974 	 *
       
  3975 	 * The string returned here consists of a space or carriage return-delimited list
       
  3976 	 * of trackback URLs.
       
  3977 	 *
       
  3978 	 * @since 3.4.0
       
  3979 	 *
       
  3980 	 * @param string $urls_to_ping Sanitized space or carriage return separated URLs.
       
  3981 	 * @param string $to_ping      Space or carriage return separated URLs before sanitization.
       
  3982 	 */
  3372 	return apply_filters( 'sanitize_trackback_urls', $urls_to_ping, $to_ping );
  3983 	return apply_filters( 'sanitize_trackback_urls', $urls_to_ping, $to_ping );
  3373 }
  3984 }
  3374 
  3985 
  3375 /**
  3986 /**
  3376  * Add slashes to a string or array of strings.
  3987  * Add slashes to a string or array of strings.
  3421  *
  4032  *
  3422  * @param string $content A string which might contain a URL.
  4033  * @param string $content A string which might contain a URL.
  3423  * @return string The found URL.
  4034  * @return string The found URL.
  3424  */
  4035  */
  3425 function get_url_in_content( $content ) {
  4036 function get_url_in_content( $content ) {
  3426 	if ( empty( $content ) )
  4037 	if ( empty( $content ) ) {
  3427 		return '';
  4038 		return false;
  3428 
  4039 	}
  3429 	if ( preg_match( '/<a\s[^>]*?href=([\'"])(.+?)\1/is', $content, $matches ) )
  4040 
       
  4041 	if ( preg_match( '/<a\s[^>]*?href=([\'"])(.+?)\1/is', $content, $matches ) ) {
  3430 		return esc_url_raw( $matches[2] );
  4042 		return esc_url_raw( $matches[2] );
       
  4043 	}
  3431 
  4044 
  3432 	return false;
  4045 	return false;
  3433 }
  4046 }
       
  4047 
       
  4048 /**
       
  4049  * Returns the regexp for common whitespace characters.
       
  4050  *
       
  4051  * By default, spaces include new lines, tabs, nbsp entities, and the UTF-8 nbsp.
       
  4052  * This is designed to replace the PCRE \s sequence.  In ticket #22692, that
       
  4053  * sequence was found to be unreliable due to random inclusion of the A0 byte.
       
  4054  *
       
  4055  * @since 4.0.0
       
  4056  *
       
  4057  * @return string The spaces regexp.
       
  4058  */
       
  4059 function wp_spaces_regexp() {
       
  4060 	static $spaces;
       
  4061 
       
  4062 	if ( empty( $spaces ) ) {
       
  4063 		/**
       
  4064 		 * Filter the regexp for common whitespace characters.
       
  4065 		 *
       
  4066 		 * This string is substituted for the \s sequence as needed in regular
       
  4067 		 * expressions. For websites not written in English, different characters
       
  4068 		 * may represent whitespace. For websites not encoded in UTF-8, the 0xC2 0xA0
       
  4069 		 * sequence may not be in use.
       
  4070 		 *
       
  4071 		 * @since 4.0.0
       
  4072 		 *
       
  4073 		 * @param string $spaces Regexp pattern for matching common whitespace characters.
       
  4074 		 */
       
  4075 		$spaces = apply_filters( 'wp_spaces_regexp', '[\r\n\t ]|\xC2\xA0|&nbsp;' );
       
  4076 	}
       
  4077 
       
  4078 	return $spaces;
       
  4079 }
       
  4080 
       
  4081 /**
       
  4082  * Print the important emoji-related styles.
       
  4083  *
       
  4084  * @since 4.2.0
       
  4085  */
       
  4086 function print_emoji_styles() {
       
  4087 	static $printed = false;
       
  4088 
       
  4089 	if ( $printed ) {
       
  4090 		return;
       
  4091 	}
       
  4092 
       
  4093 	$printed = true;
       
  4094 ?>
       
  4095 <style type="text/css">
       
  4096 img.wp-smiley,
       
  4097 img.emoji {
       
  4098 	display: inline !important;
       
  4099 	border: none !important;
       
  4100 	box-shadow: none !important;
       
  4101 	height: 1em !important;
       
  4102 	width: 1em !important;
       
  4103 	margin: 0 .07em !important;
       
  4104 	vertical-align: -0.1em !important;
       
  4105 	background: none !important;
       
  4106 	padding: 0 !important;
       
  4107 }
       
  4108 </style>
       
  4109 <?php
       
  4110 }
       
  4111 
       
  4112 function print_emoji_detection_script() {
       
  4113 	global $wp_version;
       
  4114 	static $printed = false;
       
  4115 
       
  4116 	if ( $printed ) {
       
  4117 		return;
       
  4118 	}
       
  4119 
       
  4120 	$printed = true;
       
  4121 
       
  4122 	$settings = array(
       
  4123 		/**
       
  4124 		 * Filter the URL where emoji images are hosted.
       
  4125 		 *
       
  4126 		 * @since 4.2.0
       
  4127 		 *
       
  4128 		 * @param string The emoji base URL.
       
  4129 		 */
       
  4130 		'baseUrl' => apply_filters( 'emoji_url', set_url_scheme( '//s.w.org/images/core/emoji/72x72/' ) ),
       
  4131 
       
  4132 		/**
       
  4133 		 * Filter the extension of the emoji files.
       
  4134 		 *
       
  4135 		 * @since 4.2.0
       
  4136 		 *
       
  4137 		 * @param string The emoji extension. Default .png.
       
  4138 		 */
       
  4139 		'ext' => apply_filters( 'emoji_ext', '.png' ),
       
  4140 	);
       
  4141 
       
  4142 	$version = 'ver=' . $wp_version;
       
  4143 
       
  4144 	if ( SCRIPT_DEBUG ) {
       
  4145 		$settings['source'] = array(
       
  4146 			/** This filter is documented in wp-includes/class.wp-scripts.php */
       
  4147 			'wpemoji' => apply_filters( 'script_loader_src', includes_url( "js/wp-emoji.js?$version" ), 'wpemoji' ),
       
  4148 			/** This filter is documented in wp-includes/class.wp-scripts.php */
       
  4149 			'twemoji' => apply_filters( 'script_loader_src', includes_url( "js/twemoji.js?$version" ), 'twemoji' ),
       
  4150 		);
       
  4151 
       
  4152 		?>
       
  4153 		<script type="text/javascript">
       
  4154 			window._wpemojiSettings = <?php echo wp_json_encode( $settings ); ?>;
       
  4155 			<?php readfile( ABSPATH . WPINC . "/js/wp-emoji-loader.js" ); ?>
       
  4156 		</script>
       
  4157 		<?php
       
  4158 	} else {
       
  4159 		$settings['source'] = array(
       
  4160 			/** This filter is documented in wp-includes/class.wp-scripts.php */
       
  4161 			'concatemoji' => apply_filters( 'script_loader_src', includes_url( "js/wp-emoji-release.min.js?$version" ), 'concatemoji' ),
       
  4162 		);
       
  4163 
       
  4164 		/*
       
  4165 		 * If you're looking at a src version of this file, you'll see an "include"
       
  4166 		 * statement below. This is used by the `grunt build` process to directly
       
  4167 		 * include a minified version of wp-emoji-loader.js, instead of using the
       
  4168 		 * readfile() method from above.
       
  4169 		 *
       
  4170 		 * If you're looking at a build version of this file, you'll see a string of
       
  4171 		 * minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
       
  4172 		 * and edit wp-emoji-loader.js directly.
       
  4173 		 */
       
  4174 		?>
       
  4175 		<script type="text/javascript">
       
  4176 			window._wpemojiSettings = <?php echo wp_json_encode( $settings ); ?>;
       
  4177 			!function(a,b,c){function d(a){var c=b.createElement("canvas"),d=c.getContext&&c.getContext("2d");return d&&d.fillText?(d.textBaseline="top",d.font="600 32px Arial","flag"===a?(d.fillText(String.fromCharCode(55356,56812,55356,56807),0,0),c.toDataURL().length>3e3):(d.fillText(String.fromCharCode(55357,56835),0,0),0!==d.getImageData(16,16,1,1).data[0])):!1}function e(a){var c=b.createElement("script");c.src=a,c.type="text/javascript",b.getElementsByTagName("head")[0].appendChild(c)}var f,g;c.supports={simple:d("simple"),flag:d("flag")},c.DOMReady=!1,c.readyCallback=function(){c.DOMReady=!0},c.supports.simple&&c.supports.flag||(g=function(){c.readyCallback()},b.addEventListener?(b.addEventListener("DOMContentLoaded",g,!1),a.addEventListener("load",g,!1)):(a.attachEvent("onload",g),b.attachEvent("onreadystatechange",function(){"complete"===b.readyState&&c.readyCallback()})),f=c.source||{},f.concatemoji?e(f.concatemoji):f.wpemoji&&f.twemoji&&(e(f.twemoji),e(f.wpemoji)))}(window,document,window._wpemojiSettings);
       
  4178 		</script>
       
  4179 		<?php
       
  4180 	}
       
  4181 }
       
  4182 
       
  4183 /**
       
  4184  * Convert any 4 byte emoji in a string to their equivalent HTML entity.
       
  4185  *
       
  4186  * Currently, only Unicode 7 emoji are supported. Skin tone modifiers are allowed,
       
  4187  * all other Unicode 8 emoji will be added when the spec is finalised.
       
  4188  *
       
  4189  * This allows us to store emoji in a DB using the utf8 character set.
       
  4190  *
       
  4191  * @since 4.2.0
       
  4192  *
       
  4193  * @param string $content The content to encode.
       
  4194  * @return string The encoded content.
       
  4195  */
       
  4196 function wp_encode_emoji( $content ) {
       
  4197 	if ( function_exists( 'mb_convert_encoding' ) ) {
       
  4198 		$regex = '/(
       
  4199 		     \x23\xE2\x83\xA3               # Digits
       
  4200 		     [\x30-\x39]\xE2\x83\xA3
       
  4201 		   | \xF0\x9F[\x85-\x88][\xA6-\xBF] # Enclosed characters
       
  4202 		   | \xF0\x9F[\x8C-\x97][\x80-\xBF] # Misc
       
  4203 		   | \xF0\x9F\x98[\x80-\xBF]        # Smilies
       
  4204 		   | \xF0\x9F\x99[\x80-\x8F]
       
  4205 		   | \xF0\x9F\x9A[\x80-\xBF]        # Transport and map symbols
       
  4206 		)/x';
       
  4207 
       
  4208 		$matches = array();
       
  4209 		if ( preg_match_all( $regex, $content, $matches ) ) {
       
  4210 			if ( ! empty( $matches[1] ) ) {
       
  4211 				foreach( $matches[1] as $emoji ) {
       
  4212 					/*
       
  4213 					 * UTF-32's hex encoding is the same as HTML's hex encoding.
       
  4214 					 * So, by converting the emoji from UTF-8 to UTF-32, we magically
       
  4215 					 * get the correct hex encoding.
       
  4216 					 */
       
  4217 					$unpacked = unpack( 'H*', mb_convert_encoding( $emoji, 'UTF-32', 'UTF-8' ) );
       
  4218 					if ( isset( $unpacked[1] ) ) {
       
  4219 						$entity = '&#x' . ltrim( $unpacked[1], '0' ) . ';';
       
  4220 						$content = str_replace( $emoji, $entity, $content );
       
  4221 					}
       
  4222 				}
       
  4223 			}
       
  4224 		}
       
  4225 	}
       
  4226 
       
  4227 	return $content;
       
  4228 }
       
  4229 
       
  4230 /**
       
  4231  * Convert emoji to a static img element.
       
  4232  *
       
  4233  * @since 4.2.0
       
  4234  *
       
  4235  * @param string $text The content to encode.
       
  4236  * @return string The encoded content.
       
  4237  */
       
  4238 function wp_staticize_emoji( $text ) {
       
  4239 	$text = wp_encode_emoji( $text );
       
  4240 
       
  4241 	/** This filter is documented in wp-includes/formatting.php */
       
  4242 	$cdn_url = apply_filters( 'emoji_url', set_url_scheme( '//s.w.org/images/core/emoji/72x72/' ) );
       
  4243 
       
  4244 	/** This filter is documented in wp-includes/formatting.php */
       
  4245 	$ext = apply_filters( 'emoji_ext', '.png' );
       
  4246 
       
  4247 	$output = '';
       
  4248 	/*
       
  4249 	 * HTML loop taken from smiley function, which was taken from texturize function.
       
  4250 	 * It'll never be consolidated.
       
  4251 	 *
       
  4252 	 * First, capture the tags as well as in between.
       
  4253 	 */
       
  4254 	$textarr = preg_split( '/(<.*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE );
       
  4255 	$stop = count( $textarr );
       
  4256 
       
  4257 	// Ignore processing of specific tags.
       
  4258 	$tags_to_ignore = 'code|pre|style|script|textarea';
       
  4259 	$ignore_block_element = '';
       
  4260 
       
  4261 	for ( $i = 0; $i < $stop; $i++ ) {
       
  4262 		$content = $textarr[$i];
       
  4263 
       
  4264 		// If we're in an ignore block, wait until we find its closing tag.
       
  4265 		if ( '' == $ignore_block_element && preg_match( '/^<(' . $tags_to_ignore . ')>/', $content, $matches ) )  {
       
  4266 			$ignore_block_element = $matches[1];
       
  4267 		}
       
  4268 
       
  4269 		// If it's not a tag and not in ignore block.
       
  4270 		if ( '' ==  $ignore_block_element && strlen( $content ) > 0 && '<' != $content[0] ) {
       
  4271 			$matches = array();
       
  4272 			if ( preg_match_all( '/(&#x1f1(e[6-9a-f]|f[0-9a-f]);){2}/', $content, $matches ) ) {
       
  4273 				if ( ! empty( $matches[0] ) ) {
       
  4274 					foreach ( $matches[0] as $flag ) {
       
  4275 						$chars = str_replace( array( '&#x', ';'), '', $flag );
       
  4276 
       
  4277 						list( $char1, $char2 ) = str_split( $chars, 5 );
       
  4278 						$entity = sprintf( '<img src="%s" alt="%s" class="wp-smiley" style="height: 1em; max-height: 1em;" />', $cdn_url . $char1 . '-' . $char2 . $ext, html_entity_decode( $flag ) );
       
  4279 
       
  4280 						$content = str_replace( $flag, $entity, $content );
       
  4281 					}
       
  4282 				}
       
  4283 			}
       
  4284 
       
  4285 			// Loosely match the Emoji Unicode range.
       
  4286 			$regex = '/(&#x[2-3][0-9a-f]{3};|&#x1f[1-6][0-9a-f]{2};)/';
       
  4287 
       
  4288 			$matches = array();
       
  4289 			if ( preg_match_all( $regex, $content, $matches ) ) {
       
  4290 				if ( ! empty( $matches[1] ) ) {
       
  4291 					foreach ( $matches[1] as $emoji ) {
       
  4292 						$char = str_replace( array( '&#x', ';'), '', $emoji );
       
  4293 						$entity = sprintf( '<img src="%s" alt="%s" class="wp-smiley" style="height: 1em; max-height: 1em;" />', $cdn_url . $char . $ext, html_entity_decode( $emoji ) );
       
  4294 
       
  4295 						$content = str_replace( $emoji, $entity, $content );
       
  4296 					}
       
  4297 				}
       
  4298 			}
       
  4299 		}
       
  4300 
       
  4301 		// Did we exit ignore block.
       
  4302 		if ( '' != $ignore_block_element && '</' . $ignore_block_element . '>' == $content )  {
       
  4303 			$ignore_block_element = '';
       
  4304 		}
       
  4305 
       
  4306 		$output .= $content;
       
  4307 	}
       
  4308 
       
  4309 	return $output;
       
  4310 }
       
  4311 
       
  4312 /**
       
  4313  * Convert emoji in emails into static images.
       
  4314  *
       
  4315  * @since 4.2.0
       
  4316  *
       
  4317  * @param array $mail The email data array.
       
  4318  * @return array The email data array, with emoji in the message staticized.
       
  4319  */
       
  4320 function wp_staticize_emoji_for_email( $mail ) {
       
  4321 	if ( ! isset( $mail['message'] ) ) {
       
  4322 		return $mail;
       
  4323 	}
       
  4324 
       
  4325 	/*
       
  4326 	 * We can only transform the emoji into images if it's a text/html email.
       
  4327 	 * To do that, here's a cut down version of the same process that happens
       
  4328 	 * in wp_mail() - get the Content-Type from the headers, if there is one,
       
  4329 	 * then pass it through the wp_mail_content_type filter, in case a plugin
       
  4330 	 * is handling changing the Content-Type.
       
  4331 	 */
       
  4332 	$headers = array();
       
  4333 	if ( isset( $mail['headers'] ) ) {
       
  4334 		if ( is_array( $mail['headers'] ) ) {
       
  4335 			$headers = $mail['headers'];
       
  4336 		} else {
       
  4337 			$headers = explode( "\n", str_replace( "\r\n", "\n", $mail['headers'] ) );
       
  4338 		}
       
  4339 	}
       
  4340 
       
  4341 	foreach ( $headers as $header ) {
       
  4342 		if ( strpos($header, ':') === false ) {
       
  4343 			continue;
       
  4344 		}
       
  4345 
       
  4346 		// Explode them out.
       
  4347 		list( $name, $content ) = explode( ':', trim( $header ), 2 );
       
  4348 
       
  4349 		// Cleanup crew.
       
  4350 		$name    = trim( $name    );
       
  4351 		$content = trim( $content );
       
  4352 
       
  4353 		if ( 'content-type' === strtolower( $name ) ) {
       
  4354 			if ( strpos( $content, ';' ) !== false ) {
       
  4355 				list( $type, $charset ) = explode( ';', $content );
       
  4356 				$content_type = trim( $type );
       
  4357 			} else {
       
  4358 				$content_type = trim( $content );
       
  4359 			}
       
  4360 			break;
       
  4361 		}
       
  4362 	}
       
  4363 
       
  4364 	// Set Content-Type if we don't have a content-type from the input headers.
       
  4365 	if ( ! isset( $content_type ) ) {
       
  4366 		$content_type = 'text/plain';
       
  4367 	}
       
  4368 
       
  4369 	/** This filter is documented in wp-includes/pluggable.php */
       
  4370 	$content_type = apply_filters( 'wp_mail_content_type', $content_type );
       
  4371 
       
  4372 	if ( 'text/html' === $content_type ) {
       
  4373 		$mail['message'] = wp_staticize_emoji( $mail['message'] );
       
  4374 	}
       
  4375 
       
  4376 	return $mail;
       
  4377 }