/system/helpers/text_helper.php
PHP | 535 lines | 326 code | 66 blank | 143 comment | 52 complexity | 9ab6750d12b52c162fca7caf377c25f9 MD5 | raw file
1<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 2/** 3 * CodeIgniter 4 * 5 * An open source application development framework for PHP 5.1.6 or newer 6 * 7 * @package CodeIgniter 8 * @author ExpressionEngine Dev Team 9 * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. 10 * @license http://codeigniter.com/user_guide/license.html 11 * @link http://codeigniter.com 12 * @since Version 1.0 13 * @filesource 14 */ 15 16// ------------------------------------------------------------------------ 17 18/** 19 * CodeIgniter Text Helpers 20 * 21 * @package CodeIgniter 22 * @subpackage Helpers 23 * @category Helpers 24 * @author ExpressionEngine Dev Team 25 * @link http://codeigniter.com/user_guide/helpers/text_helper.html 26 */ 27 28// ------------------------------------------------------------------------ 29 30/** 31 * Word Limiter 32 * 33 * Limits a string to X number of words. 34 * 35 * @access public 36 * @param string 37 * @param integer 38 * @param string the end character. Usually an ellipsis 39 * @return string 40 */ 41if ( ! function_exists('word_limiter')) 42{ 43 function word_limiter($str, $limit = 100, $end_char = '…') 44 { 45 if (trim($str) == '') 46 { 47 return $str; 48 } 49 50 preg_match('/^\s*+(?:\S++\s*+){1,'.(int) $limit.'}/', $str, $matches); 51 52 if (strlen($str) == strlen($matches[0])) 53 { 54 $end_char = ''; 55 } 56 57 return rtrim($matches[0]).$end_char; 58 } 59} 60 61// ------------------------------------------------------------------------ 62 63/** 64 * Character Limiter 65 * 66 * Limits the string based on the character count. Preserves complete words 67 * so the character count may not be exactly as specified. 68 * 69 * @access public 70 * @param string 71 * @param integer 72 * @param string the end character. Usually an ellipsis 73 * @return string 74 */ 75if ( ! function_exists('character_limiter')) 76{ 77 function character_limiter($str, $n = 500, $end_char = '…') 78 { 79 if (strlen($str) < $n) 80 { 81 return $str; 82 } 83 84 $str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str)); 85 86 if (strlen($str) <= $n) 87 { 88 return $str; 89 } 90 91 $out = ""; 92 foreach (explode(' ', trim($str)) as $val) 93 { 94 $out .= $val.' '; 95 96 if (strlen($out) >= $n) 97 { 98 $out = trim($out); 99 return (strlen($out) == strlen($str)) ? $out : $out.$end_char; 100 } 101 } 102 } 103} 104 105// ------------------------------------------------------------------------ 106 107/** 108 * High ASCII to Entities 109 * 110 * Converts High ascii text and MS Word special characters to character entities 111 * 112 * @access public 113 * @param string 114 * @return string 115 */ 116if ( ! function_exists('ascii_to_entities')) 117{ 118 function ascii_to_entities($str) 119 { 120 $count = 1; 121 $out = ''; 122 $temp = array(); 123 124 for ($i = 0, $s = strlen($str); $i < $s; $i++) 125 { 126 $ordinal = ord($str[$i]); 127 128 if ($ordinal < 128) 129 { 130 /* 131 If the $temp array has a value but we have moved on, then it seems only 132 fair that we output that entity and restart $temp before continuing. -Paul 133 */ 134 if (count($temp) == 1) 135 { 136 $out .= '&#'.array_shift($temp).';'; 137 $count = 1; 138 } 139 140 $out .= $str[$i]; 141 } 142 else 143 { 144 if (count($temp) == 0) 145 { 146 $count = ($ordinal < 224) ? 2 : 3; 147 } 148 149 $temp[] = $ordinal; 150 151 if (count($temp) == $count) 152 { 153 $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64); 154 155 $out .= '&#'.$number.';'; 156 $count = 1; 157 $temp = array(); 158 } 159 } 160 } 161 162 return $out; 163 } 164} 165 166// ------------------------------------------------------------------------ 167 168/** 169 * Entities to ASCII 170 * 171 * Converts character entities back to ASCII 172 * 173 * @access public 174 * @param string 175 * @param bool 176 * @return string 177 */ 178if ( ! function_exists('entities_to_ascii')) 179{ 180 function entities_to_ascii($str, $all = TRUE) 181 { 182 if (preg_match_all('/\&#(\d+)\;/', $str, $matches)) 183 { 184 for ($i = 0, $s = count($matches['0']); $i < $s; $i++) 185 { 186 $digits = $matches['1'][$i]; 187 188 $out = ''; 189 190 if ($digits < 128) 191 { 192 $out .= chr($digits); 193 194 } 195 elseif ($digits < 2048) 196 { 197 $out .= chr(192 + (($digits - ($digits % 64)) / 64)); 198 $out .= chr(128 + ($digits % 64)); 199 } 200 else 201 { 202 $out .= chr(224 + (($digits - ($digits % 4096)) / 4096)); 203 $out .= chr(128 + ((($digits % 4096) - ($digits % 64)) / 64)); 204 $out .= chr(128 + ($digits % 64)); 205 } 206 207 $str = str_replace($matches['0'][$i], $out, $str); 208 } 209 } 210 211 if ($all) 212 { 213 $str = str_replace(array("&", "<", ">", """, "'", "-"), 214 array("&","<",">","\"", "'", "-"), 215 $str); 216 } 217 218 return $str; 219 } 220} 221 222// ------------------------------------------------------------------------ 223 224/** 225 * Word Censoring Function 226 * 227 * Supply a string and an array of disallowed words and any 228 * matched words will be converted to #### or to the replacement 229 * word you've submitted. 230 * 231 * @access public 232 * @param string the text string 233 * @param string the array of censoered words 234 * @param string the optional replacement value 235 * @return string 236 */ 237if ( ! function_exists('word_censor')) 238{ 239 function word_censor($str, $censored, $replacement = '') 240 { 241 if ( ! is_array($censored)) 242 { 243 return $str; 244 } 245 246 $str = ' '.$str.' '; 247 248 // \w, \b and a few others do not match on a unicode character 249 // set for performance reasons. As a result words like über 250 // will not match on a word boundary. Instead, we'll assume that 251 // a bad word will be bookeneded by any of these characters. 252 $delim = '[-_\'\"`(){}<>\[\]|!?@#%&,.:;^~*+=\/ 0-9\n\r\t]'; 253 254 foreach ($censored as $badword) 255 { 256 if ($replacement != '') 257 { 258 $str = preg_replace("/({$delim})(".str_replace('\*', '\w*?', preg_quote($badword, '/')).")({$delim})/i", "\\1{$replacement}\\3", $str); 259 } 260 else 261 { 262 $str = preg_replace("/({$delim})(".str_replace('\*', '\w*?', preg_quote($badword, '/')).")({$delim})/ie", "'\\1'.str_repeat('#', strlen('\\2')).'\\3'", $str); 263 } 264 } 265 266 return trim($str); 267 } 268} 269 270// ------------------------------------------------------------------------ 271 272/** 273 * Code Highlighter 274 * 275 * Colorizes code strings 276 * 277 * @access public 278 * @param string the text string 279 * @return string 280 */ 281if ( ! function_exists('highlight_code')) 282{ 283 function highlight_code($str) 284 { 285 // The highlight string function encodes and highlights 286 // brackets so we need them to start raw 287 $str = str_replace(array('<', '>'), array('<', '>'), $str); 288 289 // Replace any existing PHP tags to temporary markers so they don't accidentally 290 // break the string out of PHP, and thus, thwart the highlighting. 291 292 $str = str_replace(array('<?', '?>', '<%', '%>', '\\', '</script>'), 293 array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), $str); 294 295 // The highlight_string function requires that the text be surrounded 296 // by PHP tags, which we will remove later 297 $str = '<?php '.$str.' ?>'; // <? 298 299 // All the magic happens here, baby! 300 $str = highlight_string($str, TRUE); 301 302 // Prior to PHP 5, the highligh function used icky <font> tags 303 // so we'll replace them with <span> tags. 304 305 if (abs(PHP_VERSION) < 5) 306 { 307 $str = str_replace(array('<font ', '</font>'), array('<span ', '</span>'), $str); 308 $str = preg_replace('#color="(.*?)"#', 'style="color: \\1"', $str); 309 } 310 311 // Remove our artificially added PHP, and the syntax highlighting that came with it 312 $str = preg_replace('/<span style="color: #([A-Z0-9]+)"><\?php( | )/i', '<span style="color: #$1">', $str); 313 $str = preg_replace('/(<span style="color: #[A-Z0-9]+">.*?)\?><\/span>\n<\/span>\n<\/code>/is', "$1</span>\n</span>\n</code>", $str); 314 $str = preg_replace('/<span style="color: #[A-Z0-9]+"\><\/span>/i', '', $str); 315 316 // Replace our markers back to PHP tags. 317 $str = str_replace(array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), 318 array('<?', '?>', '<%', '%>', '\\', '</script>'), $str); 319 320 return $str; 321 } 322} 323 324// ------------------------------------------------------------------------ 325 326/** 327 * Phrase Highlighter 328 * 329 * Highlights a phrase within a text string 330 * 331 * @access public 332 * @param string the text string 333 * @param string the phrase you'd like to highlight 334 * @param string the openging tag to precede the phrase with 335 * @param string the closing tag to end the phrase with 336 * @return string 337 */ 338if ( ! function_exists('highlight_phrase')) 339{ 340 function highlight_phrase($str, $phrase, $tag_open = '<strong>', $tag_close = '</strong>') 341 { 342 if ($str == '') 343 { 344 return ''; 345 } 346 347 if ($phrase != '') 348 { 349 return preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open."\\1".$tag_close, $str); 350 } 351 352 return $str; 353 } 354} 355 356// ------------------------------------------------------------------------ 357 358/** 359 * Convert Accented Foreign Characters to ASCII 360 * 361 * @access public 362 * @param string the text string 363 * @return string 364 */ 365if ( ! function_exists('convert_accented_characters')) 366{ 367 function convert_accented_characters($str) 368 { 369 if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars'.EXT)) 370 { 371 include(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars'.EXT); 372 } 373 elseif (is_file(APPPATH.'config/foreign_chars'.EXT)) 374 { 375 include(APPPATH.'config/foreign_chars'.EXT); 376 } 377 378 if ( ! isset($foreign_characters)) 379 { 380 return $str; 381 } 382 383 return preg_replace(array_keys($foreign_characters), array_values($foreign_characters), $str); 384 } 385} 386 387// ------------------------------------------------------------------------ 388 389/** 390 * Word Wrap 391 * 392 * Wraps text at the specified character. Maintains the integrity of words. 393 * Anything placed between {unwrap}{/unwrap} will not be word wrapped, nor 394 * will URLs. 395 * 396 * @access public 397 * @param string the text string 398 * @param integer the number of characters to wrap at 399 * @return string 400 */ 401if ( ! function_exists('word_wrap')) 402{ 403 function word_wrap($str, $charlim = '76') 404 { 405 // Se the character limit 406 if ( ! is_numeric($charlim)) 407 $charlim = 76; 408 409 // Reduce multiple spaces 410 $str = preg_replace("| +|", " ", $str); 411 412 // Standardize newlines 413 if (strpos($str, "\r") !== FALSE) 414 { 415 $str = str_replace(array("\r\n", "\r"), "\n", $str); 416 } 417 418 // If the current word is surrounded by {unwrap} tags we'll 419 // strip the entire chunk and replace it with a marker. 420 $unwrap = array(); 421 if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches)) 422 { 423 for ($i = 0; $i < count($matches['0']); $i++) 424 { 425 $unwrap[] = $matches['1'][$i]; 426 $str = str_replace($matches['1'][$i], "{{unwrapped".$i."}}", $str); 427 } 428 } 429 430 // Use PHP's native function to do the initial wordwrap. 431 // We set the cut flag to FALSE so that any individual words that are 432 // too long get left alone. In the next step we'll deal with them. 433 $str = wordwrap($str, $charlim, "\n", FALSE); 434 435 // Split the string into individual lines of text and cycle through them 436 $output = ""; 437 foreach (explode("\n", $str) as $line) 438 { 439 // Is the line within the allowed character count? 440 // If so we'll join it to the output and continue 441 if (strlen($line) <= $charlim) 442 { 443 $output .= $line."\n"; 444 continue; 445 } 446 447 $temp = ''; 448 while ((strlen($line)) > $charlim) 449 { 450 // If the over-length word is a URL we won't wrap it 451 if (preg_match("!\[url.+\]|://|wwww.!", $line)) 452 { 453 break; 454 } 455 456 // Trim the word down 457 $temp .= substr($line, 0, $charlim-1); 458 $line = substr($line, $charlim-1); 459 } 460 461 // If $temp contains data it means we had to split up an over-length 462 // word into smaller chunks so we'll add it back to our current line 463 if ($temp != '') 464 { 465 $output .= $temp."\n".$line; 466 } 467 else 468 { 469 $output .= $line; 470 } 471 472 $output .= "\n"; 473 } 474 475 // Put our markers back 476 if (count($unwrap) > 0) 477 { 478 foreach ($unwrap as $key => $val) 479 { 480 $output = str_replace("{{unwrapped".$key."}}", $val, $output); 481 } 482 } 483 484 // Remove the unwrap tags 485 $output = str_replace(array('{unwrap}', '{/unwrap}'), '', $output); 486 487 return $output; 488 } 489} 490 491// ------------------------------------------------------------------------ 492 493/** 494 * Ellipsize String 495 * 496 * This function will strip tags from a string, split it at its max_length and ellipsize 497 * 498 * @param string string to ellipsize 499 * @param integer max length of string 500 * @param mixed int (1|0) or float, .5, .2, etc for position to split 501 * @param string ellipsis ; Default '...' 502 * @return string ellipsized string 503 */ 504if ( ! function_exists('ellipsize')) 505{ 506 function ellipsize($str, $max_length, $position = 1, $ellipsis = '…') 507 { 508 // Strip tags 509 $str = trim(strip_tags($str)); 510 511 // Is the string long enough to ellipsize? 512 if (strlen($str) <= $max_length) 513 { 514 return $str; 515 } 516 517 $beg = substr($str, 0, floor($max_length * $position)); 518 519 $position = ($position > 1) ? 1 : $position; 520 521 if ($position === 1) 522 { 523 $end = substr($str, 0, -($max_length - strlen($beg))); 524 } 525 else 526 { 527 $end = substr($str, -($max_length - strlen($beg))); 528 } 529 530 return $beg.$ellipsis.$end; 531 } 532} 533 534/* End of file text_helper.php */ 535/* Location: ./system/helpers/text_helper.php */