Make WordPress Core

source: trunk/wp-includes/functions-formatting.php @ 1404

Last change on this file since 1404 was 1404, checked in by saxmatt, 21 years ago

Gzip cleanup, debugged wacky options problem, some cleanup and reorg. We need to split up functions.php more logically, and kill some of the useless functions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.9 KB
Line 
1<?php
2
3add_action('sanitize_title', 'sanitize_title_with_dashes');
4
5function wptexturize($text) {
6        $output = '';
7        // Capture tags and everything inside them
8        $textarr = preg_split("/(<.*>)/Us", $text, -1, PREG_SPLIT_DELIM_CAPTURE);
9        $stop = count($textarr); $next = true; // loop stuff
10        for ($i = 0; $i < $stop; $i++) {
11                $curl = $textarr[$i];
12
13                if (isset($curl{0}) && '<' != $curl{0} && $next) { // If it's not a tag
14                        $curl = str_replace('---', '&#8212;', $curl);
15                        $curl = str_replace('--', '&#8211;', $curl);
16                        $curl = str_replace("...", '&#8230;', $curl);
17                        $curl = str_replace('``', '&#8220;', $curl);
18
19                        // This is a hack, look at this more later. It works pretty well though.
20                        $cockney = array("'tain't","'twere","'twas","'tis","'twill","'til","'bout","'nuff","'round");
21                        $cockneyreplace = array("&#8217;tain&#8217;t","&#8217;twere","&#8217;twas","&#8217;tis","&#8217;twill","&#8217;til","&#8217;bout","&#8217;nuff","&#8217;round");
22                        $curl = str_replace($cockney, $cockneyreplace, $curl);
23
24                        $curl = preg_replace("/'s/", '&#8217;s', $curl);
25                        $curl = preg_replace("/'(\d\d(?:&#8217;|')?s)/", "&#8217;$1", $curl);
26                        $curl = preg_replace('/(\s|\A|")\'/', '$1&#8216;', $curl);
27                        $curl = preg_replace('/(\d+)"/', '$1&Prime;', $curl);
28                        $curl = preg_replace("/(\d+)'/", '$1&prime;', $curl);
29                        $curl = preg_replace("/(\S)'([^'\s])/", "$1&#8217;$2", $curl);
30                        $curl = preg_replace('/(\s|\A)"(?!\s)/', '$1&#8220;$2', $curl);
31                        $curl = preg_replace('/"(\s|\Z)/', '&#8221;$1', $curl);
32                        $curl = preg_replace("/'([\s.]|\Z)/", '&#8217;$1', $curl);
33                        $curl = preg_replace("/\(tm\)/i", '&#8482;', $curl);
34                        $curl = preg_replace("/\(c\)/i", '&#169;', $curl);
35                        $curl = preg_replace("/\(r\)/i", '&#174;', $curl);
36                        $curl = str_replace("''", '&#8221;', $curl);
37                       
38                        $curl = preg_replace('/(d+)x(\d+)/', "$1&#215;$2", $curl);
39
40                } elseif (strstr($curl, '<code') || strstr($curl, '<pre') || strstr($curl, '<kbd' || strstr($curl, '<style') || strstr($curl, '<script'))) {
41                        // strstr is fast
42                        $next = false;
43                } else {
44                        $next = true;
45                }
46                $curl = preg_replace('/&([^#])(?![a-z]{1,8};)/', '&#038;$1', $curl);
47                $output .= $curl;
48        }
49        return $output;
50}
51
52function clean_pre($text) {
53        $text = stripslashes($text);
54        $text = str_replace('<br />', '', $text);
55        return $text;
56}
57
58function wpautop($pee, $br = 1) {
59        $pee = $pee . "\n"; // just to make things a little easier, pad the end
60        $pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
61        // Space things out a little
62        $pee = preg_replace('!(<(?:table|thead|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|blockquote|math|p|h[1-6])[^>]*>)!', "\n$1", $pee); 
63        $pee = preg_replace('!(</(?:table|thead|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|blockquote|math|p|h[1-6])>)!', "$1\n", $pee);
64        $pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines
65        $pee = preg_replace("/\n\n+/", "\n\n", $pee); // take care of duplicates
66        $pee = preg_replace('/\n?(.+?)(?:\n\s*\n|\z)/s', "\t<p>$1</p>\n", $pee); // make paragraphs, including one at the end
67        $pee = preg_replace('|<p>\s*?</p>|', '', $pee); // under certain strange conditions it could create a P of entirely whitespace
68    $pee = preg_replace('!<p>\s*(</?(?:table|thead|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|blockquote|math|p|h[1-6])[^>]*>)\s*</p>!', "$1", $pee); // don't pee all over a tag
69        $pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists
70        $pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
71        $pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
72        $pee = preg_replace('!<p>\s*(</?(?:table|thead|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|blockquote|math|p|h[1-6])[^>]*>)!', "$1", $pee);
73        $pee = preg_replace('!(</?(?:table|thead|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|blockquote|math|p|h[1-6])[^>]*>)\s*</p>!', "$1", $pee); 
74        if ($br) $pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); // optionally make line breaks
75        $pee = preg_replace('!(</?(?:table|thead|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|blockquote|math|p|h[1-6])[^>]*>)\s*<br />!', "$1", $pee);
76        $pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)>)!', '$1', $pee);
77        $pee = preg_replace('!(<pre.*?>)(.*?)</pre>!ise', " stripslashes('$1') .  clean_pre('$2')  . '</pre>' ", $pee);
78       
79        return $pee; 
80}
81
82
83function seems_utf8($Str) { # by bmorel at ssi dot fr
84        for ($i=0; $i<strlen($Str); $i++) {
85                if (ord($Str[$i]) < 0x80) continue; # 0bbbbbbb
86                elseif ((ord($Str[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb
87                elseif ((ord($Str[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb
88                elseif ((ord($Str[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb
89                elseif ((ord($Str[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb
90                elseif ((ord($Str[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b
91                else return false; # Does not match any model
92                for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
93                        if ((++$i == strlen($Str)) || ((ord($Str[$i]) & 0xC0) != 0x80))
94                        return false;
95                }
96        }
97        return true;
98}
99
100function remove_accents($string) {
101        $chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158)
102          .chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194)
103          .chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202)
104          .chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210)
105          .chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218)
106          .chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227)
107          .chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235)
108          .chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243)
109          .chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251)
110          .chr(252).chr(253).chr(255);
111        $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
112        if (seems_utf8($string)) {
113                $invalid_latin_chars = array(chr(197).chr(146) => 'OE', chr(197).chr(147) => 'oe', chr(197).chr(160) => 'S', chr(197).chr(189) => 'Z', chr(197).chr(161) => 's', chr(197).chr(190) => 'z', chr(226).chr(130).chr(172) => 'E');
114                $string = utf8_decode(strtr($string, $invalid_latin_chars));
115        }
116        $string = strtr($string, $chars['in'], $chars['out']);
117        $double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
118        $double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
119        $string = str_replace($double_chars['in'], $double_chars['out'], $string);
120        return $string;
121}
122
123function sanitize_title($title) {
124    $title = do_action('sanitize_title', $title);
125
126    return $title;
127}
128
129function sanitize_title_with_dashes($title) {
130    $title = remove_accents($title);
131    $title = strtolower($title);
132    $title = preg_replace('/&.+?;/', '', $title); // kill entities
133    $title = preg_replace('/[^a-z0-9 _-]/', '', $title);
134    $title = preg_replace('/\s+/', ' ', $title);
135    $title = str_replace(' ', '-', $title);
136    $title = preg_replace('|-+|', '-', $title);
137    $title = trim($title, '-');
138
139    return $title;
140}
141
142function convert_chars($content, $flag = 'obsolete') { 
143        global $wp_htmltranswinuni;
144
145        // Remove metadata tags
146        $content = preg_replace('/<title>(.+?)<\/title>/','',$content);
147        $content = preg_replace('/<category>(.+?)<\/category>/','',$content);
148
149        // Converts lone & characters into &#38; (a.k.a. &amp;)
150        $content = preg_replace('/&([^#])(?![a-z]{1,8};)/i', '&#038;$1', $content);
151
152        // Fix Word pasting
153        $content = strtr($content, $wp_htmltranswinuni);
154
155        // Just a little XHTML help
156        $content = str_replace('<br>', '<br />', $content);
157        $content = str_replace('<hr>', '<hr />', $content);
158
159        return $content;
160}
161
162/*
163 balanceTags
164 
165 Balances Tags of string using a modified stack.
166 
167 @param text      Text to be balanced
168 @return          Returns balanced text
169 @author          Leonard Lin ([email protected])
170 @version         v1.1
171 @date            November 4, 2001
172 @license         GPL v2.0
173 @notes           
174 @changelog       
175             1.2  ***TODO*** Make better - change loop condition to $text
176             1.1  Fixed handling of append/stack pop order of end text
177                  Added Cleaning Hooks
178             1.0  First Version
179*/
180function balanceTags($text, $is_comment = 0) {
181       
182        if (get_settings('use_balanceTags') == 0) {
183                return $text;
184        }
185
186        $tagstack = array(); $stacksize = 0; $tagqueue = ''; $newtext = '';
187
188        # WP bug fix for comments - in case you REALLY meant to type '< !--'
189        $text = str_replace('< !--', '<    !--', $text);
190        # WP bug fix for LOVE <3 (and other situations with '<' before a number)
191        $text = preg_replace('#<([0-9]{1})#', '&lt;$1', $text);
192
193        while (preg_match("/<(\/?\w*)\s*([^>]*)>/",$text,$regex)) {
194                $newtext = $newtext . $tagqueue;
195
196                $i = strpos($text,$regex[0]);
197                $l = strlen($tagqueue) + strlen($regex[0]);
198
199                // clear the shifter
200                $tagqueue = '';
201                // Pop or Push
202                if ($regex[1][0] == "/") { // End Tag
203                        $tag = strtolower(substr($regex[1],1));
204                        // if too many closing tags
205                        if($stacksize <= 0) { 
206                                $tag = '';
207                                //or close to be safe $tag = '/' . $tag;
208                        }
209                        // if stacktop value = tag close value then pop
210                        else if ($tagstack[$stacksize - 1] == $tag) { // found closing tag
211                                $tag = '</' . $tag . '>'; // Close Tag
212                                // Pop
213                                array_pop ($tagstack);
214                                $stacksize--;
215                        } else { // closing tag not at top, search for it
216                                for ($j=$stacksize-1;$j>=0;$j--) {
217                                        if ($tagstack[$j] == $tag) {
218                                        // add tag to tagqueue
219                                                for ($k=$stacksize-1;$k>=$j;$k--){
220                                                        $tagqueue .= '</' . array_pop ($tagstack) . '>';
221                                                        $stacksize--;
222                                                }
223                                                break;
224                                        }
225                                }
226                                $tag = '';
227                        }
228                } else { // Begin Tag
229                        $tag = strtolower($regex[1]);
230
231                        // Tag Cleaning
232
233                        // Push if not img or br or hr
234                        if($tag != 'br' && $tag != 'img' && $tag != 'hr') {
235                                $stacksize = array_push ($tagstack, $tag);
236                        }
237
238                        // Attributes
239                        // $attributes = $regex[2];
240                        $attributes = $regex[2];
241                        if($attributes) {
242                                $attributes = ' '.$attributes;
243                        }
244                        $tag = '<'.$tag.$attributes.'>';
245                }
246                $newtext .= substr($text,0,$i) . $tag;
247                $text = substr($text,$i+$l);
248        } 
249
250        // Clear Tag Queue
251        $newtext = $newtext . $tagqueue;
252
253        // Add Remaining text
254        $newtext .= $text;
255
256        // Empty Stack
257        while($x = array_pop($tagstack)) {
258                $newtext = $newtext . '</' . $x . '>'; // Add remaining tags to close     
259        }
260
261        // WP fix for the bug with HTML comments
262        $newtext = str_replace("< !--","<!--",$newtext);
263        $newtext = str_replace("<    !--","< !--",$newtext);
264
265        return $newtext;
266}
267
268
269function format_to_edit($content) {
270        $content = stripslashes($content);
271        $content = apply_filters('format_to_edit', $content);
272        $content = htmlspecialchars($content);
273        return $content;
274}
275
276function format_to_post($content) {
277        global $wpdb;
278        $content = apply_filters('format_to_post', $content);
279        return $content;
280}
281
282function zeroise($number,$threshold) { // function to add leading zeros when necessary
283        $l=strlen($number);
284        if ($l<$threshold)
285                for ($i=0; $i<($threshold-$l); $i=$i+1) { $number='0'.$number;  }
286        return $number;
287        }
288
289
290function backslashit($string) {
291        $string = preg_replace('/([a-z])/i', '\\\\\1', $string);
292        return $string;
293}
294
295function trailingslashit($string) {
296    if ( '/' != substr($string, -1)) {
297        $string .= '/';
298    }
299    return $string;
300}
301
302function addslashes_gpc($gpc) {
303        if (!get_magic_quotes_gpc()) {
304                $gpc = addslashes($gpc);
305        }
306        return $gpc;
307}
308
309function antispambot($emailaddy, $mailto=0) {
310        $emailNOSPAMaddy = '';
311        srand ((float) microtime() * 1000000);
312        for ($i = 0; $i < strlen($emailaddy); $i = $i + 1) {
313                $j = floor(rand(0, 1+$mailto));
314                if ($j==0) {
315                        $emailNOSPAMaddy .= '&#'.ord(substr($emailaddy,$i,1)).';';
316                } elseif ($j==1) {
317                        $emailNOSPAMaddy .= substr($emailaddy,$i,1);
318                } elseif ($j==2) {
319                        $emailNOSPAMaddy .= '%'.zeroise(dechex(ord(substr($emailaddy, $i, 1))), 2);
320                }
321        }
322        $emailNOSPAMaddy = str_replace('@','&#64;',$emailNOSPAMaddy);
323        return $emailNOSPAMaddy;
324}
325
326function make_clickable($text) { // original function: phpBB, extended here for AIM & ICQ
327    $ret = " " . $text;
328    $ret = preg_replace("#([\n ])([a-z]+?)://([^, <>{}\n\r]+)#i", "\\1<a href=\"\\2://\\3\" target=\"_blank\">\\2://\\3</a>", $ret);
329    $ret = preg_replace("#([\n ])aim:([^,< \n\r]+)#i", "\\1<a href=\"aim:goim?screenname=\\2\\3&message=Hello\">\\2\\3</a>", $ret);
330    $ret = preg_replace("#([\n ])icq:([^,< \n\r]+)#i", "\\1<a href=\"http://wwp.icq.com/scripts/search.dll?to=\\2\\3\">\\2\\3</a>", $ret);
331    $ret = preg_replace("#([\n ])www\.([a-z0-9\-]+)\.([a-z0-9\-.\~]+)((?:/[^,< \n\r]*)?)#i", "\\1<a href=\"http://www.\\2.\\3\\4\" target=\"_blank\">www.\\2.\\3\\4</a>", $ret);
332    $ret = preg_replace("#([\n ])([a-z0-9\-_.]+?)@([^,< \n\r]+)#i", "\\1<a href=\"mailto:\\2@\\3\">\\2@\\3</a>", $ret);
333    $ret = substr($ret, 1);
334    return $ret;
335}
336
337function convert_smilies($text) {
338        global $wp_smiliessearch, $wp_smiliesreplace;
339    $output = '';
340        if (get_settings('use_smilies')) {
341                // HTML loop taken from texturize function, could possible be consolidated
342                $textarr = preg_split("/(<.*>)/U", $text, -1, PREG_SPLIT_DELIM_CAPTURE); // capture the tags as well as in between
343                $stop = count($textarr);// loop stuff
344                for ($i = 0; $i < $stop; $i++) {
345                        $content = $textarr[$i];
346                        if ((strlen($content) > 0) && ('<' != $content{0})) { // If it's not a tag
347                                $content = str_replace($wp_smiliessearch, $wp_smiliesreplace, $content);
348                        }
349                        $output .= $content;
350                }
351        } else {
352                // return default text.
353                $output = $text;
354        }
355        return $output;
356}
357
358
359function is_email($user_email) {
360        $chars = "/^([a-z0-9+_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,6}\$/i";
361        if(strstr($user_email, '@') && strstr($user_email, '.')) {
362                if (preg_match($chars, $user_email)) {
363                        return true;
364                } else {
365                        return false;
366                }
367        } else {
368                return false;
369        }
370}
371
372
373function strip_all_but_one_link($text, $mylink) {
374        $match_link = '#(<a.+?href.+?'.'>)(.+?)(</a>)#';
375        preg_match_all($match_link, $text, $matches);
376        $count = count($matches[0]);
377        for ($i=0; $i<$count; $i++) {
378                if (!strstr($matches[0][$i], $mylink)) {
379                        $text = str_replace($matches[0][$i], $matches[2][$i], $text);
380                }
381        }
382        return $text;
383}
384
385
386// used by wp-mail to handle charsets in email subjects
387function wp_iso_descrambler($string) {
388  /* this may only work with iso-8859-1, I'm afraid */
389  if (!preg_match('#\=\?(.+)\?Q\?(.+)\?\=#i', $string, $matches)) {
390    return $string;
391  } else {
392    $subject = str_replace('_', ' ', $matches[2]);
393    $subject = preg_replace('#\=([0-9a-f]{2})#ei', "chr(hexdec(strtolower('$1')))", $subject);
394    return $subject;
395  }
396}
397
398
399// give it a date, it will give you the same date as GMT
400function get_gmt_from_date($string) {
401  // note: this only substracts $time_difference from the given date
402  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);
403  $string_time = gmmktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
404  $string_gmt = gmdate('Y-m-d H:i:s', $string_time - get_settings('gmt_offset') * 3600);
405  return $string_gmt;
406}
407
408// give it a GMT date, it will give you the same date with $time_difference added
409function get_date_from_gmt($string) {
410  // note: this only adds $time_difference to the given date
411  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);
412  $string_time = gmmktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
413  $string_localtime = gmdate('Y-m-d H:i:s', $string_time + get_settings('gmt_offset')*3600);
414  return $string_localtime;
415}
416
417// computes an offset in seconds from an iso8601 timezone
418function iso8601_timezone_to_offset($timezone) {
419  // $timezone is either 'Z' or '[+|-]hhmm'
420  if ($timezone == 'Z') {
421    $offset = 0;
422  } else {
423    $sign    = (substr($timezone, 0, 1) == '+') ? 1 : -1;
424    $hours   = intval(substr($timezone, 1, 2));
425    $minutes = intval(substr($timezone, 3, 4)) / 60;
426    $offset  = $sign * 3600 * ($hours + $minutes);
427  }
428  return $offset;
429}
430
431// converts an iso8601 date to MySQL DateTime format used by post_date[_gmt]
432function iso8601_to_datetime($date_string, $timezone = USER) {
433  if ($timezone == GMT) {
434    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);
435    if (!empty($date_bits[7])) { // we have a timezone, so let's compute an offset
436      $offset = iso8601_timezone_to_offset($date_bits[7]);
437    } else { // we don't have a timezone, so we assume user local timezone (not server's!)
438      $offset = 3600 * get_settings('gmt_offset');
439    }
440    $timestamp = gmmktime($date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1]);
441    $timestamp -= $offset;
442    return gmdate('Y-m-d H:i:s', $timestamp);
443  } elseif ($timezone == USER) {
444    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);
445  }
446}
447
448function popuplinks($text) {
449        // Comment text in popup windows should be filtered through this.
450        // Right now it's a moderately dumb function, ideally it would detect whether
451        // a target or rel attribute was already there and adjust its actions accordingly.
452        $text = preg_replace('/<a (.+?)>/i', "<a $1 target='_blank' rel='external'>", $text);
453        return $text;
454}
455
456?>
Note: See TracBrowser for help on using the repository browser.