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