home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Blogs / wordpress2.6.exe / wordpress2.6 / wp-includes / formatting.php < prev    next >
Encoding:
PHP Script  |  2008-07-09  |  45.3 KB  |  1,424 lines

  1. <?php
  2.  
  3. function wptexturize($text) {
  4.     global $wp_cockneyreplace;
  5.     $next = true;
  6.     $has_pre_parent = false;
  7.     $output = '';
  8.     $curl = '';
  9.     $textarr = preg_split('/(<.*>|\[.*\])/Us', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
  10.     $stop = count($textarr);
  11.  
  12.     // if a plugin has provided an autocorrect array, use it
  13.     if ( isset($wp_cockneyreplace) ) {
  14.         $cockney = array_keys($wp_cockneyreplace);
  15.         $cockneyreplace = array_values($wp_cockneyreplace);
  16.     } else {
  17.         $cockney = array("'tain't","'twere","'twas","'tis","'twill","'til","'bout","'nuff","'round","'cause");
  18.         $cockneyreplace = array("’tain’t","’twere","’twas","’tis","’twill","’til","’bout","’nuff","’round","’cause");
  19.     }
  20.  
  21.     $static_characters = array_merge(array('---', ' -- ', '--', 'xn–', '...', '``', '\'s', '\'\'', ' (tm)'), $cockney);
  22.     $static_replacements = array_merge(array('—', ' — ', '–', 'xn--', '…', '“', '’s', '”', ' ™'), $cockneyreplace);
  23.  
  24.     $dynamic_characters = array('/\'(\d\d(?:’|\')?s)/', '/(\s|\A|")\'/', '/(\d+)"/', '/(\d+)\'/', '/(\S)\'([^\'\s])/', '/(\s|\A)"(?!\s)/', '/"(\s|\S|\Z)/', '/\'([\s.]|\Z)/', '/(\d+)x(\d+)/');
  25.     $dynamic_replacements = array('’$1','$1‘', '$1″', '$1′', '$1’$2', '$1“$2', '”$1', '’$1', '$1×$2');
  26.  
  27.     for ( $i = 0; $i < $stop; $i++ ) {
  28.          $curl = $textarr[$i];
  29.  
  30.         if (isset($curl{0}) && '<' != $curl{0} && '[' != $curl{0} && $next && !$has_pre_parent) { // If it's not a tag
  31.             // static strings
  32.             $curl = str_replace($static_characters, $static_replacements, $curl);
  33.             // regular expressions
  34.             $curl = preg_replace($dynamic_characters, $dynamic_replacements, $curl);
  35.         } elseif (strpos($curl, '<code') !== false || strpos($curl, '<kbd') !== false || strpos($curl, '<style') !== false || strpos($curl, '<script') !== false) {
  36.             $next = false;
  37.         } elseif (strpos($curl, '<pre') !== false) {
  38.             $has_pre_parent = true;
  39.         } elseif (strpos($curl, '</pre>') !== false) {
  40.             $has_pre_parent = false;
  41.         } else {
  42.             $next = true;
  43.         }
  44.  
  45.         $curl = preg_replace('/&([^#])(?![a-zA-Z1-4]{1,8};)/', '&$1', $curl);
  46.         $output .= $curl;
  47.     }
  48.  
  49.       return $output;
  50. }
  51.  
  52. // Accepts matches array from preg_replace_callback in wpautop()
  53. // or a string
  54. function clean_pre($matches) {
  55.     if ( is_array($matches) )
  56.         $text = $matches[1] . $matches[2] . "</pre>";
  57.     else
  58.         $text = $matches;
  59.  
  60.     $text = str_replace('<br />', '', $text);
  61.     $text = str_replace('<p>', "\n", $text);
  62.     $text = str_replace('</p>', '', $text);
  63.  
  64.     return $text;
  65. }
  66.  
  67. function wpautop($pee, $br = 1) {
  68.     $pee = $pee . "\n"; // just to make things a little easier, pad the end
  69.     $pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
  70.     // Space things out a little
  71.     $allblocks = '(?:table|thead|tfoot|caption|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|map|area|blockquote|address|math|style|input|p|h[1-6]|hr)';
  72.     $pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee);
  73.     $pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
  74.     $pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines
  75.     if ( strpos($pee, '<object') !== false ) {
  76.         $pee = preg_replace('|\s*<param([^>]*)>\s*|', "<param$1>", $pee); // no pee inside object/embed
  77.         $pee = preg_replace('|\s*</embed>\s*|', '</embed>', $pee);
  78.     }
  79.     $pee = preg_replace("/\n\n+/", "\n\n", $pee); // take care of duplicates
  80.     $pee = preg_replace('/\n?(.+?)(?:\n\s*\n|\z)/s', "<p>$1</p>\n", $pee); // make paragraphs, including one at the end
  81.     $pee = preg_replace('|<p>\s*?</p>|', '', $pee); // under certain strange conditions it could create a P of entirely whitespace
  82.     $pee = preg_replace('!<p>([^<]+)\s*?(</(?:div|address|form)[^>]*>)!', "<p>$1</p>$2", $pee);
  83.     $pee = preg_replace( '|<p>|', "$1<p>", $pee );
  84.     $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); // don't pee all over a tag
  85.     $pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists
  86.     $pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
  87.     $pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
  88.     $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
  89.     $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
  90.     if ($br) {
  91.         $pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', create_function('$matches', 'return str_replace("\n", "<WPPreserveNewline />", $matches[0]);'), $pee);
  92.         $pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); // optionally make line breaks
  93.         $pee = str_replace('<WPPreserveNewline />', "\n", $pee);
  94.     }
  95.     $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
  96.     $pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
  97.     if (strpos($pee, '<pre') !== false)
  98.         $pee = preg_replace_callback('!(<pre.*?>)(.*?)</pre>!is', 'clean_pre', $pee );
  99.     $pee = preg_replace( "|\n</p>$|", '</p>', $pee );
  100.     $pee = preg_replace('/<p>\s*?(' . get_shortcode_regex() . ')\s*<\/p>/s', '$1', $pee); // don't auto-p wrap shortcodes that stand alone
  101.  
  102.     return $pee;
  103. }
  104.  
  105.  
  106. function seems_utf8($Str) { # by bmorel at ssi dot fr
  107.     $length = strlen($Str);
  108.     for ($i=0; $i < $length; $i++) {
  109.         if (ord($Str[$i]) < 0x80) continue; # 0bbbbbbb
  110.         elseif ((ord($Str[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb
  111.         elseif ((ord($Str[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb
  112.         elseif ((ord($Str[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb
  113.         elseif ((ord($Str[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb
  114.         elseif ((ord($Str[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b
  115.         else return false; # Does not match any model
  116.         for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
  117.             if ((++$i == $length) || ((ord($Str[$i]) & 0xC0) != 0x80))
  118.             return false;
  119.         }
  120.     }
  121.     return true;
  122. }
  123.  
  124. function wp_specialchars( $text, $quotes = 0 ) {
  125.     // Like htmlspecialchars except don't double-encode HTML entities
  126.     $text = str_replace('&&', '&&', $text);
  127.     $text = str_replace('&&', '&&', $text);
  128.     $text = preg_replace('/&(?:$|([^#])(?![a-z1-4]{1,8};))/', '&$1', $text);
  129.     $text = str_replace('<', '<', $text);
  130.     $text = str_replace('>', '>', $text);
  131.     if ( 'double' === $quotes ) {
  132.         $text = str_replace('"', '"', $text);
  133.     } elseif ( 'single' === $quotes ) {
  134.         $text = str_replace("'", ''', $text);
  135.     } elseif ( $quotes ) {
  136.         $text = str_replace('"', '"', $text);
  137.         $text = str_replace("'", ''', $text);
  138.     }
  139.     return $text;
  140. }
  141.  
  142. function utf8_uri_encode( $utf8_string, $length = 0 ) {
  143.     $unicode = '';
  144.     $values = array();
  145.     $num_octets = 1;
  146.     $unicode_length = 0;
  147.  
  148.     $string_length = strlen( $utf8_string );
  149.     for ($i = 0; $i < $string_length; $i++ ) {
  150.  
  151.         $value = ord( $utf8_string[ $i ] );
  152.  
  153.         if ( $value < 128 ) {
  154.             if ( $length && ( $unicode_length >= $length ) )
  155.                 break;
  156.             $unicode .= chr($value);
  157.             $unicode_length++;
  158.         } else {
  159.             if ( count( $values ) == 0 ) $num_octets = ( $value < 224 ) ? 2 : 3;
  160.  
  161.             $values[] = $value;
  162.  
  163.             if ( $length && ( $unicode_length + ($num_octets * 3) ) > $length )
  164.                 break;
  165.             if ( count( $values ) == $num_octets ) {
  166.                 if ($num_octets == 3) {
  167.                     $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]) . '%' . dechex($values[2]);
  168.                     $unicode_length += 9;
  169.                 } else {
  170.                     $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]);
  171.                     $unicode_length += 6;
  172.                 }
  173.  
  174.                 $values = array();
  175.                 $num_octets = 1;
  176.             }
  177.         }
  178.     }
  179.  
  180.     return $unicode;
  181. }
  182.  
  183. function remove_accents($string) {
  184.     if ( !preg_match('/[\x80-\xff]/', $string) )
  185.         return $string;
  186.  
  187.     if (seems_utf8($string)) {
  188.         $chars = array(
  189.         // Decompositions for Latin-1 Supplement
  190.         chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
  191.         chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
  192.         chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
  193.         chr(195).chr(135) => 'C', chr(195).chr(136) => 'E',
  194.         chr(195).chr(137) => 'E', chr(195).chr(138) => 'E',
  195.         chr(195).chr(139) => 'E', chr(195).chr(140) => 'I',
  196.         chr(195).chr(141) => 'I', chr(195).chr(142) => 'I',
  197.         chr(195).chr(143) => 'I', chr(195).chr(145) => 'N',
  198.         chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
  199.         chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
  200.         chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
  201.         chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
  202.         chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
  203.         chr(195).chr(159) => 's', chr(195).chr(160) => 'a',
  204.         chr(195).chr(161) => 'a', chr(195).chr(162) => 'a',
  205.         chr(195).chr(163) => 'a', chr(195).chr(164) => 'a',
  206.         chr(195).chr(165) => 'a', chr(195).chr(167) => 'c',
  207.         chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
  208.         chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
  209.         chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
  210.         chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
  211.         chr(195).chr(177) => 'n', chr(195).chr(178) => 'o',
  212.         chr(195).chr(179) => 'o', chr(195).chr(180) => 'o',
  213.         chr(195).chr(181) => 'o', chr(195).chr(182) => 'o',
  214.         chr(195).chr(182) => 'o', chr(195).chr(185) => 'u',
  215.         chr(195).chr(186) => 'u', chr(195).chr(187) => 'u',
  216.         chr(195).chr(188) => 'u', chr(195).chr(189) => 'y',
  217.         chr(195).chr(191) => 'y',
  218.         // Decompositions for Latin Extended-A
  219.         chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
  220.         chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
  221.         chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
  222.         chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
  223.         chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
  224.         chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
  225.         chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
  226.         chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
  227.         chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
  228.         chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
  229.         chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
  230.         chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
  231.         chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
  232.         chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
  233.         chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
  234.         chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
  235.         chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
  236.         chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
  237.         chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
  238.         chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
  239.         chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
  240.         chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
  241.         chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
  242.         chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
  243.         chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
  244.         chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
  245.         chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
  246.         chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
  247.         chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
  248.         chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
  249.         chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
  250.         chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
  251.         chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
  252.         chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
  253.         chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
  254.         chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
  255.         chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
  256.         chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
  257.         chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
  258.         chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
  259.         chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
  260.         chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
  261.         chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
  262.         chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
  263.         chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
  264.         chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
  265.         chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
  266.         chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
  267.         chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
  268.         chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
  269.         chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
  270.         chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
  271.         chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
  272.         chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
  273.         chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
  274.         chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
  275.         chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
  276.         chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
  277.         chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
  278.         chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
  279.         chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
  280.         chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
  281.         chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
  282.         chr(197).chr(190) => 'z', chr(197).chr(191) => 's',
  283.         // Euro Sign
  284.         chr(226).chr(130).chr(172) => 'E',
  285.         // GBP (Pound) Sign
  286.         chr(194).chr(163) => '');
  287.  
  288.         $string = strtr($string, $chars);
  289.     } else {
  290.         // Assume ISO-8859-1 if not UTF-8
  291.         $chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158)
  292.             .chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194)
  293.             .chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202)
  294.             .chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210)
  295.             .chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218)
  296.             .chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227)
  297.             .chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235)
  298.             .chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243)
  299.             .chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251)
  300.             .chr(252).chr(253).chr(255);
  301.  
  302.         $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
  303.  
  304.         $string = strtr($string, $chars['in'], $chars['out']);
  305.         $double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
  306.         $double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
  307.         $string = str_replace($double_chars['in'], $double_chars['out'], $string);
  308.     }
  309.  
  310.     return $string;
  311. }
  312.  
  313. function sanitize_file_name( $name ) { // Like sanitize_title, but with periods
  314.     $name = strtolower( $name );
  315.     $name = preg_replace('/&.+?;/', '', $name); // kill entities
  316.     $name = str_replace( '_', '-', $name );
  317.     $name = preg_replace('/[^a-z0-9\s-.]/', '', $name);
  318.     $name = preg_replace('/\s+/', '-', $name);
  319.     $name = preg_replace('|-+|', '-', $name);
  320.     $name = trim($name, '-');
  321.     return $name;
  322. }
  323.  
  324. function sanitize_user( $username, $strict = false ) {
  325.     $raw_username = $username;
  326.     $username = strip_tags($username);
  327.     // Kill octets
  328.     $username = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '', $username);
  329.     $username = preg_replace('/&.+?;/', '', $username); // Kill entities
  330.  
  331.     // If strict, reduce to ASCII for max portability.
  332.     if ( $strict )
  333.         $username = preg_replace('|[^a-z0-9 _.\-@]|i', '', $username);
  334.  
  335.     return apply_filters('sanitize_user', $username, $raw_username, $strict);
  336. }
  337.  
  338. function sanitize_title($title, $fallback_title = '') {
  339.     $title = strip_tags($title);
  340.     $title = apply_filters('sanitize_title', $title);
  341.  
  342.     if ( '' === $title || false === $title )
  343.         $title = $fallback_title;
  344.  
  345.     return $title;
  346. }
  347.  
  348. function sanitize_title_with_dashes($title) {
  349.     $title = strip_tags($title);
  350.     // Preserve escaped octets.
  351.     $title = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '---$1---', $title);
  352.     // Remove percent signs that are not part of an octet.
  353.     $title = str_replace('%', '', $title);
  354.     // Restore octets.
  355.     $title = preg_replace('|---([a-fA-F0-9][a-fA-F0-9])---|', '%$1', $title);
  356.  
  357.     $title = remove_accents($title);
  358.     if (seems_utf8($title)) {
  359.         if (function_exists('mb_strtolower')) {
  360.             $title = mb_strtolower($title, 'UTF-8');
  361.         }
  362.         $title = utf8_uri_encode($title, 200);
  363.     }
  364.  
  365.     $title = strtolower($title);
  366.     $title = preg_replace('/&.+?;/', '', $title); // kill entities
  367.     $title = preg_replace('/[^%a-z0-9 _-]/', '', $title);
  368.     $title = preg_replace('/\s+/', '-', $title);
  369.     $title = preg_replace('|-+|', '-', $title);
  370.     $title = trim($title, '-');
  371.  
  372.     return $title;
  373. }
  374.  
  375. // ensures a string is a valid SQL order by clause like: post_name ASC, ID DESC
  376. // accepts one or more columns, with or without ASC/DESC, and also accepts RAND()
  377. function sanitize_sql_orderby( $orderby ){
  378.     preg_match('/^\s*([a-z0-9_]+(\s+(ASC|DESC))?(\s*,\s*|\s*$))+|^\s*RAND\(\s*\)\s*$/i', $orderby, $obmatches);
  379.     if ( !$obmatches )
  380.         return false;
  381.     return $orderby;
  382. }
  383.  
  384. function convert_chars($content, $deprecated = '') {
  385.     // Translation of invalid Unicode references range to valid range
  386.     $wp_htmltranswinuni = array(
  387.     '€' => '€', // the Euro sign
  388.     '' => '',
  389.     '‚' => '‚', // these are Windows CP1252 specific characters
  390.     'ƒ' => 'ƒ',  // they would look weird on non-Windows browsers
  391.     '„' => '„',
  392.     '…' => '…',
  393.     '†' => '†',
  394.     '‡' => '‡',
  395.     'ˆ' => 'ˆ',
  396.     '‰' => '‰',
  397.     'Š' => 'Š',
  398.     '‹' => '‹',
  399.     'Œ' => 'Œ',
  400.     '' => '',
  401.     'Ž' => 'ž',
  402.     '' => '',
  403.     '' => '',
  404.     '‘' => '‘',
  405.     '’' => '’',
  406.     '“' => '“',
  407.     '”' => '”',
  408.     '•' => '•',
  409.     '–' => '–',
  410.     '—' => '—',
  411.     '˜' => '˜',
  412.     '™' => '™',
  413.     'š' => 'š',
  414.     '›' => '›',
  415.     'œ' => 'œ',
  416.     '' => '',
  417.     'ž' => '',
  418.     'Ÿ' => 'Ÿ'
  419.     );
  420.  
  421.     // Remove metadata tags
  422.     $content = preg_replace('/<title>(.+?)<\/title>/','',$content);
  423.     $content = preg_replace('/<category>(.+?)<\/category>/','',$content);
  424.  
  425.     // Converts lone & characters into & (a.k.a. &)
  426.     $content = preg_replace('/&([^#])(?![a-z1-4]{1,8};)/i', '&$1', $content);
  427.  
  428.     // Fix Word pasting
  429.     $content = strtr($content, $wp_htmltranswinuni);
  430.  
  431.     // Just a little XHTML help
  432.     $content = str_replace('<br>', '<br />', $content);
  433.     $content = str_replace('<hr>', '<hr />', $content);
  434.  
  435.     return $content;
  436. }
  437.  
  438. function funky_javascript_fix($text) {
  439.     // Fixes for browsers' javascript bugs
  440.     global $is_macIE, $is_winIE;
  441.  
  442.     if ( $is_winIE || $is_macIE )
  443.         $text =  preg_replace("/\%u([0-9A-F]{4,4})/e",  "'&#'.base_convert('\\1',16,10).';'", $text);
  444.  
  445.     return $text;
  446. }
  447.  
  448. function balanceTags( $text, $force = false ) {
  449.     if ( !$force && get_option('use_balanceTags') == 0 )
  450.         return $text;
  451.     return force_balance_tags( $text );
  452. }
  453.  
  454. /*
  455.  force_balance_tags
  456.  
  457.  Balances Tags of string using a modified stack.
  458.  
  459.  @param text      Text to be balanced
  460.  @param force     Forces balancing, ignoring the value of the option
  461.  @return          Returns balanced text
  462.  @author          Leonard Lin (leonard@acm.org)
  463.  @version         v1.1
  464.  @date            November 4, 2001
  465.  @license         GPL v2.0
  466.  @notes
  467.  @changelog
  468.  ---  Modified by Scott Reilly (coffee2code) 02 Aug 2004
  469.     1.2  ***TODO*** Make better - change loop condition to $text
  470.     1.1  Fixed handling of append/stack pop order of end text
  471.          Added Cleaning Hooks
  472.     1.0  First Version
  473. */
  474. function force_balance_tags( $text ) {
  475.     $tagstack = array(); $stacksize = 0; $tagqueue = ''; $newtext = '';
  476.     $single_tags = array('br', 'hr', 'img', 'input'); //Known single-entity/self-closing tags
  477.     $nestable_tags = array('blockquote', 'div', 'span'); //Tags that can be immediately nested within themselves
  478.  
  479.     # WP bug fix for comments - in case you REALLY meant to type '< !--'
  480.     $text = str_replace('< !--', '<    !--', $text);
  481.     # WP bug fix for LOVE <3 (and other situations with '<' before a number)
  482.     $text = preg_replace('#<([0-9]{1})#', '<$1', $text);
  483.  
  484.     while (preg_match("/<(\/?\w*)\s*([^>]*)>/",$text,$regex)) {
  485.         $newtext .= $tagqueue;
  486.  
  487.         $i = strpos($text,$regex[0]);
  488.         $l = strlen($regex[0]);
  489.  
  490.         // clear the shifter
  491.         $tagqueue = '';
  492.         // Pop or Push
  493.         if ($regex[1][0] == "/") { // End Tag
  494.             $tag = strtolower(substr($regex[1],1));
  495.             // if too many closing tags
  496.             if($stacksize <= 0) {
  497.                 $tag = '';
  498.                 //or close to be safe $tag = '/' . $tag;
  499.             }
  500.             // if stacktop value = tag close value then pop
  501.             else if ($tagstack[$stacksize - 1] == $tag) { // found closing tag
  502.                 $tag = '</' . $tag . '>'; // Close Tag
  503.                 // Pop
  504.                 array_pop ($tagstack);
  505.                 $stacksize--;
  506.             } else { // closing tag not at top, search for it
  507.                 for ($j=$stacksize-1;$j>=0;$j--) {
  508.                     if ($tagstack[$j] == $tag) {
  509.                     // add tag to tagqueue
  510.                         for ($k=$stacksize-1;$k>=$j;$k--){
  511.                             $tagqueue .= '</' . array_pop ($tagstack) . '>';
  512.                             $stacksize--;
  513.                         }
  514.                         break;
  515.                     }
  516.                 }
  517.                 $tag = '';
  518.             }
  519.         } else { // Begin Tag
  520.             $tag = strtolower($regex[1]);
  521.  
  522.             // Tag Cleaning
  523.  
  524.             // If self-closing or '', don't do anything.
  525.             if((substr($regex[2],-1) == '/') || ($tag == '')) {
  526.             }
  527.             // ElseIf it's a known single-entity tag but it doesn't close itself, do so
  528.             elseif ( in_array($tag, $single_tags) ) {
  529.                 $regex[2] .= '/';
  530.             } else {    // Push the tag onto the stack
  531.                 // If the top of the stack is the same as the tag we want to push, close previous tag
  532.                 if (($stacksize > 0) && !in_array($tag, $nestable_tags) && ($tagstack[$stacksize - 1] == $tag)) {
  533.                     $tagqueue = '</' . array_pop ($tagstack) . '>';
  534.                     $stacksize--;
  535.                 }
  536.                 $stacksize = array_push ($tagstack, $tag);
  537.             }
  538.  
  539.             // Attributes
  540.             $attributes = $regex[2];
  541.             if($attributes) {
  542.                 $attributes = ' '.$attributes;
  543.             }
  544.             $tag = '<'.$tag.$attributes.'>';
  545.             //If already queuing a close tag, then put this tag on, too
  546.             if ($tagqueue) {
  547.                 $tagqueue .= $tag;
  548.                 $tag = '';
  549.             }
  550.         }
  551.         $newtext .= substr($text,0,$i) . $tag;
  552.         $text = substr($text,$i+$l);
  553.     }
  554.  
  555.     // Clear Tag Queue
  556.     $newtext .= $tagqueue;
  557.  
  558.     // Add Remaining text
  559.     $newtext .= $text;
  560.  
  561.     // Empty Stack
  562.     while($x = array_pop($tagstack)) {
  563.         $newtext .= '</' . $x . '>'; // Add remaining tags to close
  564.     }
  565.  
  566.     // WP fix for the bug with HTML comments
  567.     $newtext = str_replace("< !--","<!--",$newtext);
  568.     $newtext = str_replace("<    !--","< !--",$newtext);
  569.  
  570.     return $newtext;
  571. }
  572.  
  573. function format_to_edit($content, $richedit = false) {
  574.     $content = apply_filters('format_to_edit', $content);
  575.     if (! $richedit )
  576.         $content = htmlspecialchars($content);
  577.     return $content;
  578. }
  579.  
  580. function format_to_post($content) {
  581.     $content = apply_filters('format_to_post', $content);
  582.     return $content;
  583. }
  584.  
  585. function zeroise($number,$threshold) { // function to add leading zeros when necessary
  586.     return sprintf('%0'.$threshold.'s', $number);
  587. }
  588.  
  589.  
  590. function backslashit($string) {
  591.     $string = preg_replace('/^([0-9])/', '\\\\\\\\\1', $string);
  592.     $string = preg_replace('/([a-z])/i', '\\\\\1', $string);
  593.     return $string;
  594. }
  595.  
  596. function trailingslashit($string) {
  597.     return untrailingslashit($string) . '/';
  598. }
  599.  
  600. function untrailingslashit($string) {
  601.     return rtrim($string, '/');
  602. }
  603.  
  604. function addslashes_gpc($gpc) {
  605.     global $wpdb;
  606.  
  607.     if (get_magic_quotes_gpc()) {
  608.         $gpc = stripslashes($gpc);
  609.     }
  610.  
  611.     return $wpdb->escape($gpc);
  612. }
  613.  
  614.  
  615. function stripslashes_deep($value) {
  616.      $value = is_array($value) ?
  617.          array_map('stripslashes_deep', $value) :
  618.          stripslashes($value);
  619.  
  620.      return $value;
  621. }
  622.  
  623. function urlencode_deep($value) {
  624.      $value = is_array($value) ?
  625.          array_map('urlencode_deep', $value) :
  626.          urlencode($value);
  627.  
  628.      return $value;
  629. }
  630.  
  631. function antispambot($emailaddy, $mailto=0) {
  632.     $emailNOSPAMaddy = '';
  633.     srand ((float) microtime() * 1000000);
  634.     for ($i = 0; $i < strlen($emailaddy); $i = $i + 1) {
  635.         $j = floor(rand(0, 1+$mailto));
  636.         if ($j==0) {
  637.             $emailNOSPAMaddy .= '&#'.ord(substr($emailaddy,$i,1)).';';
  638.         } elseif ($j==1) {
  639.             $emailNOSPAMaddy .= substr($emailaddy,$i,1);
  640.         } elseif ($j==2) {
  641.             $emailNOSPAMaddy .= '%'.zeroise(dechex(ord(substr($emailaddy, $i, 1))), 2);
  642.         }
  643.     }
  644.     $emailNOSPAMaddy = str_replace('@','@',$emailNOSPAMaddy);
  645.     return $emailNOSPAMaddy;
  646. }
  647.  
  648. function _make_url_clickable_cb($matches) {
  649.     $ret = '';
  650.     $url = $matches[2];
  651.     $url = clean_url($url);
  652.     if ( empty($url) )
  653.         return $matches[0];
  654.     // removed trailing [.,;:] from URL
  655.     if ( in_array(substr($url, -1), array('.', ',', ';', ':')) === true ) {
  656.         $ret = substr($url, -1);
  657.         $url = substr($url, 0, strlen($url)-1);
  658.     }
  659.     return $matches[1] . "<a href=\"$url\" rel=\"nofollow\">$url</a>" . $ret;
  660. }
  661.  
  662. function _make_web_ftp_clickable_cb($matches) {
  663.     $ret = '';
  664.     $dest = $matches[2];
  665.     $dest = 'http://' . $dest;
  666.     $dest = clean_url($dest);
  667.     if ( empty($dest) )
  668.         return $matches[0];
  669.     // removed trailing [,;:] from URL
  670.     if ( in_array(substr($dest, -1), array('.', ',', ';', ':')) === true ) {
  671.         $ret = substr($dest, -1);
  672.         $dest = substr($dest, 0, strlen($dest)-1);
  673.     }
  674.     return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\">$dest</a>" . $ret;
  675. }
  676.  
  677. function _make_email_clickable_cb($matches) {
  678.     $email = $matches[2] . '@' . $matches[3];
  679.     return $matches[1] . "<a href=\"mailto:$email\">$email</a>";
  680. }
  681.  
  682. function make_clickable($ret) {
  683.     $ret = ' ' . $ret;
  684.     // in testing, using arrays here was found to be faster
  685.     $ret = preg_replace_callback('#([\s>])([\w]+?://[\w\#$%&~/.\-;:=,?@\[\]+]*)#is', '_make_url_clickable_cb', $ret);
  686.     $ret = preg_replace_callback('#([\s>])((www|ftp)\.[\w\#$%&~/.\-;:=,?@\[\]+]*)#is', '_make_web_ftp_clickable_cb', $ret);
  687.     $ret = preg_replace_callback('#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $ret);
  688.     // this one is not in an array because we need it to run last, for cleanup of accidental links within links
  689.     $ret = preg_replace("#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i", "$1$3</a>", $ret);
  690.     $ret = trim($ret);
  691.     return $ret;
  692. }
  693.  
  694. function wp_rel_nofollow( $text ) {
  695.     global $wpdb;
  696.     // This is a pre save filter, so text is already escaped.
  697.     $text = stripslashes($text);
  698.     $text = preg_replace_callback('|<a (.+?)>|i', 'wp_rel_nofollow_callback', $text);
  699.     $text = $wpdb->escape($text);
  700.     return $text;
  701. }
  702.  
  703. function wp_rel_nofollow_callback( $matches ) {
  704.     $text = $matches[1];
  705.     $text = str_replace(array(' rel="nofollow"', " rel='nofollow'"), '', $text);
  706.     return "<a $text rel=\"nofollow\">";
  707. }
  708.  
  709. function convert_smilies($text) {
  710.     global $wp_smiliessearch, $wp_smiliesreplace;
  711.     $output = '';
  712.     if ( get_option('use_smilies') && !empty($wp_smiliessearch) && !empty($wp_smiliesreplace) ) {
  713.         // HTML loop taken from texturize function, could possible be consolidated
  714.         $textarr = preg_split("/(<.*>)/U", $text, -1, PREG_SPLIT_DELIM_CAPTURE); // capture the tags as well as in between
  715.         $stop = count($textarr);// loop stuff
  716.         for ($i = 0; $i < $stop; $i++) {
  717.             $content = $textarr[$i];
  718.             if ((strlen($content) > 0) && ('<' != $content{0})) { // If it's not a tag
  719.                 $content = preg_replace($wp_smiliessearch, $wp_smiliesreplace, $content);
  720.             }
  721.             $output .= $content;
  722.         }
  723.     } else {
  724.         // return default text.
  725.         $output = $text;
  726.     }
  727.     return $output;
  728. }
  729.  
  730.  
  731. function is_email($user_email) {
  732.     $chars = "/^([a-z0-9+_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,6}\$/i";
  733.     if (strpos($user_email, '@') !== false && strpos($user_email, '.') !== false) {
  734.         if (preg_match($chars, $user_email)) {
  735.             return true;
  736.         } else {
  737.             return false;
  738.         }
  739.     } else {
  740.         return false;
  741.     }
  742. }
  743.  
  744. // used by wp-mail to handle charsets in email subjects
  745. function wp_iso_descrambler($string) {
  746.   /* this may only work with iso-8859-1, I'm afraid */
  747.   if (!preg_match('#\=\?(.+)\?Q\?(.+)\?\=#i', $string, $matches)) {
  748.     return $string;
  749.   } else {
  750.     $subject = str_replace('_', ' ', $matches[2]);
  751.     $subject = preg_replace('#\=([0-9a-f]{2})#ei', "chr(hexdec(strtolower('$1')))", $subject);
  752.     return $subject;
  753.   }
  754. }
  755.  
  756.  
  757. // give it a date, it will give you the same date as GMT
  758. function get_gmt_from_date($string) {
  759.   // note: this only substracts $time_difference from the given date
  760.   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);
  761.   $string_time = gmmktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
  762.   $string_gmt = gmdate('Y-m-d H:i:s', $string_time - get_option('gmt_offset') * 3600);
  763.   return $string_gmt;
  764. }
  765.  
  766. // give it a GMT date, it will give you the same date with $time_difference added
  767. function get_date_from_gmt($string) {
  768.   // note: this only adds $time_difference to the given date
  769.   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);
  770.   $string_time = gmmktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
  771.   $string_localtime = gmdate('Y-m-d H:i:s', $string_time + get_option('gmt_offset')*3600);
  772.   return $string_localtime;
  773. }
  774.  
  775. // computes an offset in seconds from an iso8601 timezone
  776. function iso8601_timezone_to_offset($timezone) {
  777.   // $timezone is either 'Z' or '[+|-]hhmm'
  778.   if ($timezone == 'Z') {
  779.     $offset = 0;
  780.   } else {
  781.     $sign    = (substr($timezone, 0, 1) == '+') ? 1 : -1;
  782.     $hours   = intval(substr($timezone, 1, 2));
  783.     $minutes = intval(substr($timezone, 3, 4)) / 60;
  784.     $offset  = $sign * 3600 * ($hours + $minutes);
  785.   }
  786.   return $offset;
  787. }
  788.  
  789. // converts an iso8601 date to MySQL DateTime format used by post_date[_gmt]
  790. function iso8601_to_datetime($date_string, $timezone = USER) {
  791.   if ($timezone == GMT) {
  792.     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);
  793.     if (!empty($date_bits[7])) { // we have a timezone, so let's compute an offset
  794.       $offset = iso8601_timezone_to_offset($date_bits[7]);
  795.     } else { // we don't have a timezone, so we assume user local timezone (not server's!)
  796.       $offset = 3600 * get_option('gmt_offset');
  797.     }
  798.     $timestamp = gmmktime($date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1]);
  799.     $timestamp -= $offset;
  800.     return gmdate('Y-m-d H:i:s', $timestamp);
  801.   } elseif ($timezone == USER) {
  802.     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);
  803.   }
  804. }
  805.  
  806. function popuplinks($text) {
  807.     // Comment text in popup windows should be filtered through this.
  808.     // Right now it's a moderately dumb function, ideally it would detect whether
  809.     // a target or rel attribute was already there and adjust its actions accordingly.
  810.     $text = preg_replace('/<a (.+?)>/i', "<a $1 target='_blank' rel='external'>", $text);
  811.     return $text;
  812. }
  813.  
  814. function sanitize_email($email) {
  815.     return preg_replace('/[^a-z0-9+_.@-]/i', '', $email);
  816. }
  817.  
  818. function human_time_diff( $from, $to = '' ) {
  819.     if ( empty($to) )
  820.         $to = time();
  821.     $diff = (int) abs($to - $from);
  822.     if ($diff <= 3600) {
  823.         $mins = round($diff / 60);
  824.         if ($mins <= 1) {
  825.             $mins = 1;
  826.         }
  827.         $since = sprintf(__ngettext('%s min', '%s mins', $mins), $mins);
  828.     } else if (($diff <= 86400) && ($diff > 3600)) {
  829.         $hours = round($diff / 3600);
  830.         if ($hours <= 1) {
  831.             $hours = 1;
  832.         }
  833.         $since = sprintf(__ngettext('%s hour', '%s hours', $hours), $hours);
  834.     } elseif ($diff >= 86400) {
  835.         $days = round($diff / 86400);
  836.         if ($days <= 1) {
  837.             $days = 1;
  838.         }
  839.         $since = sprintf(__ngettext('%s day', '%s days', $days), $days);
  840.     }
  841.     return $since;
  842. }
  843.  
  844. function wp_trim_excerpt($text) { // Fakes an excerpt if needed
  845.     if ( '' == $text ) {
  846.         $text = get_the_content('');
  847.         
  848.         $text = strip_shortcodes( $text ); 
  849.         
  850.         $text = apply_filters('the_content', $text);
  851.         $text = str_replace(']]>', ']]>', $text);
  852.         $text = strip_tags($text);
  853.         $excerpt_length = 55;
  854.         $words = explode(' ', $text, $excerpt_length + 1);
  855.         if (count($words) > $excerpt_length) {
  856.             array_pop($words);
  857.             array_push($words, '[...]');
  858.             $text = implode(' ', $words);
  859.         }
  860.     }
  861.     return $text;
  862. }
  863.  
  864. function ent2ncr($text) {
  865.     $to_ncr = array(
  866.         '"' => '"',
  867.         '&' => '&',
  868.         '⁄' => '/',
  869.         '<' => '<',
  870.         '>' => '>',
  871.         '|' => '|',
  872.         ' ' => ' ',
  873.         '¡' => '¡',
  874.         '¢' => '¢',
  875.         '£' => '£',
  876.         '¤' => '¤',
  877.         '¥' => '¥',
  878.         '¦' => '¦',
  879.         '&brkbar;' => '¦',
  880.         '§' => '§',
  881.         '¨' => '¨',
  882.         '¨' => '¨',
  883.         '©' => '©',
  884.         'ª' => 'ª',
  885.         '«' => '«',
  886.         '¬' => '¬',
  887.         '­' => '­',
  888.         '®' => '®',
  889.         '¯' => '¯',
  890.         '&hibar;' => '¯',
  891.         '°' => '°',
  892.         '±' => '±',
  893.         '²' => '²',
  894.         '³' => '³',
  895.         '´' => '´',
  896.         'µ' => 'µ',
  897.         '¶' => '¶',
  898.         '·' => '·',
  899.         '¸' => '¸',
  900.         '¹' => '¹',
  901.         'º' => 'º',
  902.         '»' => '»',
  903.         '¼' => '¼',
  904.         '½' => '½',
  905.         '¾' => '¾',
  906.         '¿' => '¿',
  907.         'À' => 'À',
  908.         'Á' => 'Á',
  909.         'Â' => 'Â',
  910.         'Ã' => 'Ã',
  911.         'Ä' => 'Ä',
  912.         'Å' => 'Å',
  913.         'Æ' => 'Æ',
  914.         'Ç' => 'Ç',
  915.         'È' => 'È',
  916.         'É' => 'É',
  917.         'Ê' => 'Ê',
  918.         'Ë' => 'Ë',
  919.         'Ì' => 'Ì',
  920.         'Í' => 'Í',
  921.         'Î' => 'Î',
  922.         'Ï' => 'Ï',
  923.         'Ð' => 'Ð',
  924.         'Ñ' => 'Ñ',
  925.         'Ò' => 'Ò',
  926.         'Ó' => 'Ó',
  927.         'Ô' => 'Ô',
  928.         'Õ' => 'Õ',
  929.         'Ö' => 'Ö',
  930.         '×' => '×',
  931.         'Ø' => 'Ø',
  932.         'Ù' => 'Ù',
  933.         'Ú' => 'Ú',
  934.         'Û' => 'Û',
  935.         'Ü' => 'Ü',
  936.         'Ý' => 'Ý',
  937.         'Þ' => 'Þ',
  938.         'ß' => 'ß',
  939.         'à' => 'à',
  940.         'á' => 'á',
  941.         'â' => 'â',
  942.         'ã' => 'ã',
  943.         'ä' => 'ä',
  944.         'å' => 'å',
  945.         'æ' => 'æ',
  946.         'ç' => 'ç',
  947.         'è' => 'è',
  948.         'é' => 'é',
  949.         'ê' => 'ê',
  950.         'ë' => 'ë',
  951.         'ì' => 'ì',
  952.         'í' => 'í',
  953.         'î' => 'î',
  954.         'ï' => 'ï',
  955.         'ð' => 'ð',
  956.         'ñ' => 'ñ',
  957.         'ò' => 'ò',
  958.         'ó' => 'ó',
  959.         'ô' => 'ô',
  960.         'õ' => 'õ',
  961.         'ö' => 'ö',
  962.         '÷' => '÷',
  963.         'ø' => 'ø',
  964.         'ù' => 'ù',
  965.         'ú' => 'ú',
  966.         'û' => 'û',
  967.         'ü' => 'ü',
  968.         'ý' => 'ý',
  969.         'þ' => 'þ',
  970.         'ÿ' => 'ÿ',
  971.         'Œ' => 'Œ',
  972.         'œ' => 'œ',
  973.         'Š' => 'Š',
  974.         'š' => 'š',
  975.         'Ÿ' => 'Ÿ',
  976.         'ƒ' => 'ƒ',
  977.         'ˆ' => 'ˆ',
  978.         '˜' => '˜',
  979.         'Α' => 'Α',
  980.         'Β' => 'Β',
  981.         'Γ' => 'Γ',
  982.         'Δ' => 'Δ',
  983.         'Ε' => 'Ε',
  984.         'Ζ' => 'Ζ',
  985.         'Η' => 'Η',
  986.         'Θ' => 'Θ',
  987.         'Ι' => 'Ι',
  988.         'Κ' => 'Κ',
  989.         'Λ' => 'Λ',
  990.         'Μ' => 'Μ',
  991.         'Ν' => 'Ν',
  992.         'Ξ' => 'Ξ',
  993.         'Ο' => 'Ο',
  994.         'Π' => 'Π',
  995.         'Ρ' => 'Ρ',
  996.         'Σ' => 'Σ',
  997.         'Τ' => 'Τ',
  998.         'Υ' => 'Υ',
  999.         'Φ' => 'Φ',
  1000.         'Χ' => 'Χ',
  1001.         'Ψ' => 'Ψ',
  1002.         'Ω' => 'Ω',
  1003.         'α' => 'α',
  1004.         'β' => 'β',
  1005.         'γ' => 'γ',
  1006.         'δ' => 'δ',
  1007.         'ε' => 'ε',
  1008.         'ζ' => 'ζ',
  1009.         'η' => 'η',
  1010.         'θ' => 'θ',
  1011.         'ι' => 'ι',
  1012.         'κ' => 'κ',
  1013.         'λ' => 'λ',
  1014.         'μ' => 'μ',
  1015.         'ν' => 'ν',
  1016.         'ξ' => 'ξ',
  1017.         'ο' => 'ο',
  1018.         'π' => 'π',
  1019.         'ρ' => 'ρ',
  1020.         'ς' => 'ς',
  1021.         'σ' => 'σ',
  1022.         'τ' => 'τ',
  1023.         'υ' => 'υ',
  1024.         'φ' => 'φ',
  1025.         'χ' => 'χ',
  1026.         'ψ' => 'ψ',
  1027.         'ω' => 'ω',
  1028.         'ϑ' => 'ϑ',
  1029.         'ϒ' => 'ϒ',
  1030.         'ϖ' => 'ϖ',
  1031.         ' ' => ' ',
  1032.         ' ' => ' ',
  1033.         ' ' => ' ',
  1034.         '‌' => '‌',
  1035.         '‍' => '‍',
  1036.         '‎' => '‎',
  1037.         '‏' => '‏',
  1038.         '–' => '–',
  1039.         '—' => '—',
  1040.         '‘' => '‘',
  1041.         '’' => '’',
  1042.         '‚' => '‚',
  1043.         '“' => '“',
  1044.         '”' => '”',
  1045.         '„' => '„',
  1046.         '†' => '†',
  1047.         '‡' => '‡',
  1048.         '•' => '•',
  1049.         '…' => '…',
  1050.         '‰' => '‰',
  1051.         '′' => '′',
  1052.         '″' => '″',
  1053.         '‹' => '‹',
  1054.         '›' => '›',
  1055.         '‾' => '‾',
  1056.         '⁄' => '⁄',
  1057.         '€' => '€',
  1058.         'ℑ' => 'ℑ',
  1059.         '℘' => '℘',
  1060.         'ℜ' => 'ℜ',
  1061.         '™' => '™',
  1062.         'ℵ' => 'ℵ',
  1063.         '↵' => '↵',
  1064.         '⇐' => '⇐',
  1065.         '⇑' => '⇑',
  1066.         '⇒' => '⇒',
  1067.         '⇓' => '⇓',
  1068.         '⇔' => '⇔',
  1069.         '∀' => '∀',
  1070.         '∂' => '∂',
  1071.         '∃' => '∃',
  1072.         '∅' => '∅',
  1073.         '∇' => '∇',
  1074.         '∈' => '∈',
  1075.         '∉' => '∉',
  1076.         '∋' => '∋',
  1077.         '∏' => '∏',
  1078.         '∑' => '∑',
  1079.         '−' => '−',
  1080.         '∗' => '∗',
  1081.         '√' => '√',
  1082.         '∝' => '∝',
  1083.         '∞' => '∞',
  1084.         '∠' => '∠',
  1085.         '∧' => '∧',
  1086.         '∨' => '∨',
  1087.         '∩' => '∩',
  1088.         '∪' => '∪',
  1089.         '∫' => '∫',
  1090.         '∴' => '∴',
  1091.         '∼' => '∼',
  1092.         '≅' => '≅',
  1093.         '≈' => '≈',
  1094.         '≠' => '≠',
  1095.         '≡' => '≡',
  1096.         '≤' => '≤',
  1097.         '≥' => '≥',
  1098.         '⊂' => '⊂',
  1099.         '⊃' => '⊃',
  1100.         '⊄' => '⊄',
  1101.         '⊆' => '⊆',
  1102.         '⊇' => '⊇',
  1103.         '⊕' => '⊕',
  1104.         '⊗' => '⊗',
  1105.         '⊥' => '⊥',
  1106.         '⋅' => '⋅',
  1107.         '⌈' => '⌈',
  1108.         '⌉' => '⌉',
  1109.         '⌊' => '⌊',
  1110.         '⌋' => '⌋',
  1111.         '⟨' => '〈',
  1112.         '⟩' => '〉',
  1113.         '←' => '←',
  1114.         '↑' => '↑',
  1115.         '→' => '→',
  1116.         '↓' => '↓',
  1117.         '↔' => '↔',
  1118.         '◊' => '◊',
  1119.         '♠' => '♠',
  1120.         '♣' => '♣',
  1121.         '♥' => '♥',
  1122.         '♦' => '♦'
  1123.     );
  1124.  
  1125.     return str_replace( array_keys($to_ncr), array_values($to_ncr), $text );
  1126. }
  1127.  
  1128. function wp_richedit_pre($text) {
  1129.     // Filtering a blank results in an annoying <br />\n
  1130.     if ( empty($text) ) return apply_filters('richedit_pre', '');
  1131.  
  1132.     $output = convert_chars($text);
  1133.     $output = wpautop($output);
  1134.     $output = htmlspecialchars($output, ENT_NOQUOTES);
  1135.  
  1136.     return apply_filters('richedit_pre', $output);
  1137. }
  1138.  
  1139. function wp_htmledit_pre($output) {
  1140.     if ( !empty($output) )
  1141.         $output = htmlspecialchars($output, ENT_NOQUOTES); // convert only < > &
  1142.  
  1143.     return apply_filters('htmledit_pre', $output);
  1144. }
  1145.  
  1146. function clean_url( $url, $protocols = null, $context = 'display' ) {
  1147.     $original_url = $url;
  1148.  
  1149.     if ('' == $url) return $url;
  1150.     $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@()]|i', '', $url);
  1151.     $strip = array('%0d', '%0a');
  1152.     $url = str_replace($strip, '', $url);
  1153.     $url = str_replace(';//', '://', $url);
  1154.     /* If the URL doesn't appear to contain a scheme, we
  1155.      * presume it needs http:// appended (unless a relative
  1156.      * link starting with / or a php file).
  1157.     */
  1158.     if ( strpos($url, ':') === false &&
  1159.         substr( $url, 0, 1 ) != '/' && !preg_match('/^[a-z0-9-]+?\.php/i', $url) )
  1160.         $url = 'http://' . $url;
  1161.  
  1162.     // Replace ampersands ony when displaying.
  1163.     if ( 'display' == $context )
  1164.         $url = preg_replace('/&([^#])(?![a-z]{2,8};)/', '&$1', $url);
  1165.  
  1166.     if ( !is_array($protocols) )
  1167.         $protocols = array('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet');
  1168.     if ( wp_kses_bad_protocol( $url, $protocols ) != $url )
  1169.         return '';
  1170.  
  1171.     return apply_filters('clean_url', $url, $original_url, $context);
  1172. }
  1173.  
  1174. function sanitize_url( $url, $protocols = null ) {
  1175.     return clean_url( $url, $protocols, 'db');
  1176. }
  1177.  
  1178. // Borrowed from the PHP Manual user notes. Convert entities, while
  1179. // preserving already-encoded entities:
  1180. function htmlentities2($myHTML) {
  1181.     $translation_table=get_html_translation_table (HTML_ENTITIES,ENT_QUOTES);
  1182.     $translation_table[chr(38)] = '&';
  1183.     return preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/","&" , strtr($myHTML, $translation_table));
  1184. }
  1185.  
  1186. // Escape single quotes, specialchar double quotes, and fix line endings.
  1187. function js_escape($text) {
  1188.     $safe_text = wp_specialchars($text, 'double');
  1189.     $safe_text = preg_replace('/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes($safe_text));
  1190.     $safe_text = preg_replace("/\r?\n/", "\\n", addslashes($safe_text));
  1191.     return apply_filters('js_escape', $safe_text, $text);
  1192. }
  1193.  
  1194. // Escaping for HTML attributes
  1195. function attribute_escape($text) {
  1196.     $safe_text = wp_specialchars($text, true);
  1197.     return apply_filters('attribute_escape', $safe_text, $text);
  1198. }
  1199.  
  1200. // Escape a HTML tag name
  1201. function tag_escape($tag_name) {
  1202.     $safe_tag = strtolower( preg_replace('[^a-zA-Z_:]', '', $tag_name) );
  1203.     return apply_filters('tag_escape', $safe_tag, $tag_name);
  1204. }
  1205.  
  1206. /**
  1207.  * Escapes text for SQL LIKE special characters % and _
  1208.  *
  1209.  * @param string text the text to be escaped
  1210.  * @return string text, safe for inclusion in LIKE query
  1211.  */
  1212. function like_escape($text) {
  1213.     return str_replace(array("%", "_"), array("\\%", "\\_"), $text);
  1214. }
  1215.  
  1216. function wp_make_link_relative( $link ) {
  1217.     return preg_replace('|https?://[^/]+(/.*)|i', '$1', $link );
  1218. }
  1219.  
  1220. function sanitize_option($option, $value) { // Remember to call stripslashes!
  1221.  
  1222.     switch ($option) {
  1223.         case 'admin_email':
  1224.             $value = sanitize_email($value);
  1225.             break;
  1226.  
  1227.         case 'default_post_edit_rows':
  1228.         case 'mailserver_port':
  1229.         case 'comment_max_links':
  1230.         case 'page_on_front':
  1231.         case 'rss_excerpt_length':
  1232.         case 'default_category':
  1233.         case 'default_email_category':
  1234.         case 'default_link_category':
  1235.             $value = abs((int) $value);
  1236.             break;
  1237.  
  1238.         case 'posts_per_page':
  1239.         case 'posts_per_rss':
  1240.             $value = (int) $value;
  1241.             if ( empty($value) ) $value = 1;
  1242.             if ( $value < -1 ) $value = abs($value);
  1243.             break;
  1244.  
  1245.         case 'default_ping_status':
  1246.         case 'default_comment_status':
  1247.             // Options that if not there have 0 value but need to be something like "closed"
  1248.             if ( $value == '0' || $value == '')
  1249.                 $value = 'closed';
  1250.             break;
  1251.  
  1252.         case 'blogdescription':
  1253.         case 'blogname':
  1254.             $value = addslashes($value);
  1255.             $value = wp_filter_post_kses( $value ); // calls stripslashes then addslashes
  1256.             $value = stripslashes($value);
  1257.             $value = wp_specialchars( $value );
  1258.             break;
  1259.  
  1260.         case 'blog_charset':
  1261.             $value = preg_replace('/[^a-zA-Z0-9_-]/', '', $value); // strips slashes
  1262.             break;
  1263.  
  1264.         case 'date_format':
  1265.         case 'time_format':
  1266.         case 'mailserver_url':
  1267.         case 'mailserver_login':
  1268.         case 'mailserver_pass':
  1269.         case 'ping_sites':
  1270.         case 'upload_path':
  1271.             $value = strip_tags($value);
  1272.             $value = addslashes($value);
  1273.             $value = wp_filter_kses($value); // calls stripslashes then addslashes
  1274.             $value = stripslashes($value);
  1275.             break;
  1276.  
  1277.         case 'gmt_offset':
  1278.             $value = preg_replace('/[^0-9:.-]/', '', $value); // strips slashes
  1279.             break;
  1280.  
  1281.         case 'siteurl':
  1282.         case 'home':
  1283.             $value = stripslashes($value);
  1284.             $value = clean_url($value);
  1285.             break;
  1286.         default :
  1287.             $value = apply_filters("sanitize_option_{$option}", $value, $option);
  1288.             break;
  1289.     }
  1290.  
  1291.     return $value;
  1292. }
  1293.  
  1294. function wp_parse_str( $string, &$array ) {
  1295.     parse_str( $string, $array );
  1296.     if ( get_magic_quotes_gpc() )
  1297.         $array = stripslashes_deep( $array ); // parse_str() adds slashes if magicquotes is on.  See: http://php.net/parse_str
  1298.     $array = apply_filters( 'wp_parse_str', $array );
  1299. }
  1300.  
  1301. // Convert lone less than signs.  KSES already converts lone greater than signs.
  1302. function wp_pre_kses_less_than( $text ) {
  1303.     return preg_replace_callback('%<[^>]*?((?=<)|>|$)%', 'wp_pre_kses_less_than_callback', $text);
  1304. }
  1305.  
  1306. function wp_pre_kses_less_than_callback( $matches ) {
  1307.     if ( false === strpos($matches[0], '>') )
  1308.         return wp_specialchars($matches[0]);
  1309.     return $matches[0];
  1310. }
  1311.  
  1312. /**
  1313.  * wp_sprintf() - sprintf() with filters
  1314.  */
  1315. function wp_sprintf( $pattern ) {
  1316.     $args = func_get_args( );
  1317.     $len = strlen($pattern);
  1318.     $start = 0;
  1319.     $result = '';
  1320.     $arg_index = 0;
  1321.     while ( $len > $start ) {
  1322.         // Last character: append and break
  1323.         if ( strlen($pattern) - 1 == $start ) {
  1324.             $result .= substr($pattern, -1);
  1325.             break;
  1326.         }
  1327.  
  1328.         // Literal %: append and continue
  1329.         if ( substr($pattern, $start, 2) == '%%' ) {
  1330.             $start += 2;
  1331.             $result .= '%';
  1332.             continue;
  1333.         }
  1334.  
  1335.         // Get fragment before next %
  1336.         $end = strpos($pattern, '%', $start + 1);
  1337.         if ( false === $end )
  1338.             $end = $len;
  1339.         $fragment = substr($pattern, $start, $end - $start);
  1340.  
  1341.         // Fragment has a specifier
  1342.         if ( $pattern{$start} == '%' ) {
  1343.             // Find numbered arguments or take the next one in order
  1344.             if ( preg_match('/^%(\d+)\$/', $fragment, $matches) ) {
  1345.                 $arg = isset($args[$matches[1]]) ? $args[$matches[1]] : '';
  1346.                 $fragment = str_replace("%{$matches[1]}$", '%', $fragment);
  1347.             } else {
  1348.                 ++$arg_index;
  1349.                 $arg = isset($args[$arg_index]) ? $args[$arg_index] : '';
  1350.             }
  1351.  
  1352.             // Apply filters OR sprintf
  1353.             $_fragment = apply_filters( 'wp_sprintf', $fragment, $arg );
  1354.             if ( $_fragment != $fragment )
  1355.                 $fragment = $_fragment;
  1356.             else
  1357.                 $fragment = sprintf($fragment, strval($arg) );
  1358.         }
  1359.  
  1360.         // Append to result and move to next fragment
  1361.         $result .= $fragment;
  1362.         $start = $end;
  1363.     }
  1364.     return $result;
  1365. }
  1366.  
  1367. /**
  1368.  * wp_sprintf_l - List specifier %l for wp_sprintf
  1369.  *
  1370.  * @param unknown_type $pattern
  1371.  * @param unknown_type $args
  1372.  * @return unknown
  1373.  */
  1374. function wp_sprintf_l($pattern, $args) {
  1375.     // Not a match
  1376.     if ( substr($pattern, 0, 2) != '%l' )
  1377.         return $pattern;
  1378.  
  1379.     // Nothing to work with
  1380.     if ( empty($args) )
  1381.         return '';
  1382.  
  1383.     // Translate and filter the delimiter set (avoid ampersands and entities here)
  1384.     $l = apply_filters('wp_sprintf_l', array(
  1385.         'between'          => _c(', |between list items'),
  1386.         'between_last_two' => _c(', and |between last two list items'),
  1387.         'between_only_two' => _c(' and |between only two list items'),
  1388.         ));
  1389.  
  1390.     $args = (array) $args;
  1391.     $result = array_shift($args);
  1392.     if ( count($args) == 1 )
  1393.         $result .= $l['between_only_two'] . array_shift($args);
  1394.     // Loop when more than two args
  1395.     while ( count($args) ) {
  1396.         $arg = array_shift($args);
  1397.         if ( $i == 1 )
  1398.             $result .= $l['between_last_two'] . $arg;
  1399.         else
  1400.             $result .= $l['between'] . $arg;
  1401.     }
  1402.     return $result . substr($pattern, 2);
  1403. }
  1404.  
  1405. /**
  1406.  * Safely extracts not more than the first $count characters from html string
  1407.  *
  1408.  * UTF-8, tags and entities safe prefix extraction. Entities inside will *NOT* be
  1409.  * counted as one character. For example & will be counted as 4, < as 3, etc.
  1410.  *
  1411.  * @param integer $str String to get the excerpt from
  1412.  * @param integer $count Maximum number of characters to take
  1413.  * @eaturn string the excerpt
  1414.  */
  1415. function wp_html_excerpt( $str, $count ) {
  1416.     $str = strip_tags( $str );
  1417.     $str = mb_strcut( $str, 0, $count );
  1418.     // remove part of an entity at the end
  1419.     $str = preg_replace( '/&[^;\s]{0,6}$/', '', $str );
  1420.     return $str;
  1421. }
  1422.  
  1423. ?>
  1424.