2008-05-30 11:40:08 +00:00
< ? php
/* SVN FILE: $Id$ */
/**
* Text Helper
*
* Text manipulations : Highlight , excerpt , truncate , strip of links , convert email addresses to mailto : links ...
*
* PHP versions 4 and 5
*
2010-01-26 22:15:15 +00:00
* CakePHP ( tm ) : Rapid Development Framework ( http :// cakephp . org )
2010-01-26 19:18:20 +00:00
* Copyright 2005 - 2010 , Cake Software Foundation , Inc . ( http :// cakefoundation . org )
2008-05-30 11:40:08 +00:00
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice .
*
2010-01-26 19:18:20 +00:00
* @ copyright Copyright 2005 - 2010 , Cake Software Foundation , Inc . ( http :// cakefoundation . org )
* @ link http :// cakephp . org CakePHP ( tm ) Project
2008-10-30 17:30:26 +00:00
* @ package cake
* @ subpackage cake . cake . libs . view . helpers
* @ since CakePHP ( tm ) v 0.10 . 0.1076
* @ version $Revision $
* @ modifiedby $LastChangedBy $
* @ lastmodified $Date $
* @ license http :// www . opensource . org / licenses / mit - license . php The MIT License
2008-05-30 11:40:08 +00:00
*/
/**
* Included libraries .
*
*/
if ( ! class_exists ( 'HtmlHelper' )) {
2008-06-11 15:46:31 +00:00
App :: import ( 'Helper' , 'Html' );
2008-05-30 11:40:08 +00:00
}
2008-11-08 00:07:17 +00:00
if ( ! class_exists ( 'Multibyte' )) {
App :: import ( 'Core' , 'Multibyte' );
}
2008-05-30 11:40:08 +00:00
/**
* Text helper library .
*
* Text manipulations : Highlight , excerpt , truncate , strip of links , convert email addresses to mailto : links ...
*
2008-10-30 17:30:26 +00:00
* @ package cake
* @ subpackage cake . cake . libs . view . helpers
2008-05-30 11:40:08 +00:00
*/
class TextHelper extends AppHelper {
/**
* Highlights a given phrase in a text . You can specify any expression in highlighter that
* may include the \1 expression to include the $phrase found .
*
* @ param string $text Text to search the phrase in
* @ param string $phrase The phrase that will be searched
* @ param string $highlighter The piece of html with that the phrase will be highlighted
* @ param boolean $considerHtml If true , will ignore any HTML tags , ensuring that only the correct text is highlighted
* @ return string The highlighted text
* @ access public
*/
function highlight ( $text , $phrase , $highlighter = '<span class="highlight">\1</span>' , $considerHtml = false ) {
if ( empty ( $phrase )) {
return $text ;
}
if ( is_array ( $phrase )) {
$replace = array ();
$with = array ();
foreach ( $phrase as $key => $value ) {
$key = $value ;
$value = $highlighter ;
$key = '(' . $key . ')' ;
if ( $considerHtml ) {
$key = '(?![^<]+>)' . $key . '(?![^<]+>)' ;
}
$replace [] = '|' . $key . '|iu' ;
$with [] = empty ( $value ) ? $highlighter : $value ;
}
2008-07-30 20:34:01 +00:00
2008-05-30 11:40:08 +00:00
return preg_replace ( $replace , $with , $text );
} else {
$phrase = '(' . $phrase . ')' ;
if ( $considerHtml ) {
$phrase = '(?![^<]+>)' . $phrase . '(?![^<]+>)' ;
}
2008-07-30 20:34:01 +00:00
2008-05-30 11:40:08 +00:00
return preg_replace ( '|' . $phrase . '|iu' , $highlighter , $text );
}
}
/**
* Strips given text of all links ( < a href =.... )
*
* @ param string $text Text
* @ return string The text without links
* @ access public
*/
function stripLinks ( $text ) {
return preg_replace ( '|<a\s+[^>]+>|im' , '' , preg_replace ( '|<\/a>|im' , '' , $text ));
}
/**
* Adds links ( < a href =.... ) to a given text , by finding text that begins with
* strings like http :// and ftp ://.
*
* @ param string $text Text to add links to
* @ param array $htmlOptions Array of HTML options .
* @ return string The text with links
* @ access public
*/
function autoLinkUrls ( $text , $htmlOptions = array ()) {
$options = 'array(' ;
foreach ( $htmlOptions as $option => $value ) {
$value = var_export ( $value , true );
$options .= " ' $option ' => $value , " ;
}
$options .= ')' ;
$text = preg_replace_callback ( '#(?<!href="|">)((?:http|https|ftp|nntp)://[^ <]+)#i' , create_function ( '$matches' ,
'$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], $matches[0],' . $options . ');' ), $text );
return preg_replace_callback ( '#(?<!href="|">)(?<!http://|https://|ftp://|nntp://)(www\.[^\n\%\ <]+[^<\n\%\,\.\ <])(?<!\))#i' ,
create_function ( '$matches' , '$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], "http://" . strtolower($matches[0]),' . $options . ');' ), $text );
}
/**
* Adds email links ( < a href = " mailto:....) to a given text.
*
* @ param string $text Text
* @ param array $htmlOptions Array of HTML options .
* @ return string The text with links
* @ access public
*/
function autoLinkEmails ( $text , $htmlOptions = array ()) {
$options = 'array(' ;
foreach ( $htmlOptions as $option => $value ) {
$options .= " ' $option ' => ' $value ', " ;
}
$options .= ')' ;
return preg_replace_callback ( '#([_A-Za-z0-9+-]+(?:\.[_A-Za-z0-9+-]+)*@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*)#' ,
create_function ( '$matches' , '$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], "mailto:" . $matches[0],' . $options . ');' ), $text );
}
/**
* Convert all links and email adresses to HTML links .
*
* @ param string $text Text
* @ param array $htmlOptions Array of HTML options .
* @ return string The text with links
* @ access public
*/
function autoLink ( $text , $htmlOptions = array ()) {
return $this -> autoLinkEmails ( $this -> autoLinkUrls ( $text , $htmlOptions ), $htmlOptions );
}
/**
* Truncates text .
*
* Cuts a string to the length of $length and replaces the last characters
* with the ending if the text is longer than length .
*
* @ param string $text String to truncate .
* @ param integer $length Length of returned string , including ellipsis .
* @ param mixed $ending If string , will be used as Ending and appended to the trimmed string . Can also be an associative array that can contain the last three params of this method .
* @ param boolean $exact If false , $text will not be cut mid - word
* @ param boolean $considerHtml If true , HTML tags would be handled correctly
* @ return string Trimmed string .
*/
function truncate ( $text , $length = 100 , $ending = '...' , $exact = true , $considerHtml = false ) {
if ( is_array ( $ending )) {
extract ( $ending );
}
if ( $considerHtml ) {
2008-11-08 00:07:17 +00:00
if ( mb_strlen ( preg_replace ( '/<.*?>/' , '' , $text )) <= $length ) {
2008-05-30 11:40:08 +00:00
return $text ;
}
2010-02-01 22:13:52 +00:00
$totalLength = mb_strlen ( strip_tags ( $ending ));
2008-07-16 12:40:49 +00:00
$openTags = array ();
2008-05-30 11:40:08 +00:00
$truncate = '' ;
2008-07-16 12:40:49 +00:00
preg_match_all ( '/(<\/?([\w+]+)[^>]*>)?([^<>]*)/' , $text , $tags , PREG_SET_ORDER );
foreach ( $tags as $tag ) {
2008-11-08 00:07:17 +00:00
if ( ! preg_match ( '/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s' , $tag [ 2 ])) {
if ( preg_match ( '/<[\w]+[^>]*>/s' , $tag [ 0 ])) {
array_unshift ( $openTags , $tag [ 2 ]);
} else if ( preg_match ( '/<\/([\w]+)[^>]*>/s' , $tag [ 0 ], $closeTag )) {
$pos = array_search ( $closeTag [ 1 ], $openTags );
if ( $pos !== false ) {
array_splice ( $openTags , $pos , 1 );
}
2008-05-30 11:40:08 +00:00
}
}
2008-07-16 12:40:49 +00:00
$truncate .= $tag [ 1 ];
2008-05-30 11:40:08 +00:00
2008-11-08 00:07:17 +00:00
$contentLength = mb_strlen ( preg_replace ( '/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i' , ' ' , $tag [ 3 ]));
2008-07-16 12:40:49 +00:00
if ( $contentLength + $totalLength > $length ) {
$left = $length - $totalLength ;
$entitiesLength = 0 ;
if ( preg_match_all ( '/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i' , $tag [ 3 ], $entities , PREG_OFFSET_CAPTURE )) {
2008-05-30 11:40:08 +00:00
foreach ( $entities [ 0 ] as $entity ) {
2008-07-16 12:40:49 +00:00
if ( $entity [ 1 ] + 1 - $entitiesLength <= $left ) {
2008-05-30 11:40:08 +00:00
$left -- ;
2008-11-08 00:07:17 +00:00
$entitiesLength += mb_strlen ( $entity [ 0 ]);
2008-05-30 11:40:08 +00:00
} else {
break ;
}
}
2008-07-30 20:34:01 +00:00
}
2008-07-16 12:40:49 +00:00
2008-11-08 00:07:17 +00:00
$truncate .= mb_substr ( $tag [ 3 ], 0 , $left + $entitiesLength );
2008-05-30 11:40:08 +00:00
break ;
} else {
2008-07-16 12:40:49 +00:00
$truncate .= $tag [ 3 ];
$totalLength += $contentLength ;
2008-05-30 11:40:08 +00:00
}
2008-07-16 12:40:49 +00:00
if ( $totalLength >= $length ) {
2008-05-30 11:40:08 +00:00
break ;
}
}
} else {
2008-11-08 00:07:17 +00:00
if ( mb_strlen ( $text ) <= $length ) {
2008-05-30 11:40:08 +00:00
return $text ;
} else {
2008-11-08 00:07:17 +00:00
$truncate = mb_substr ( $text , 0 , $length - strlen ( $ending ));
2008-05-30 11:40:08 +00:00
}
}
if ( ! $exact ) {
2008-11-08 00:07:17 +00:00
$spacepos = mb_strrpos ( $truncate , ' ' );
2008-05-30 11:40:08 +00:00
if ( isset ( $spacepos )) {
2008-07-16 12:40:49 +00:00
if ( $considerHtml ) {
2008-11-08 00:07:17 +00:00
$bits = mb_substr ( $truncate , $spacepos );
2008-07-16 12:40:49 +00:00
preg_match_all ( '/<\/([a-z]+)>/' , $bits , $droppedTags , PREG_SET_ORDER );
if ( ! empty ( $droppedTags )) {
foreach ( $droppedTags as $closingTag ) {
if ( ! in_array ( $closingTag [ 1 ], $openTags )) {
array_unshift ( $openTags , $closingTag [ 1 ]);
}
}
}
}
2008-11-08 00:07:17 +00:00
$truncate = mb_substr ( $truncate , 0 , $spacepos );
2008-05-30 11:40:08 +00:00
}
}
$truncate .= $ending ;
2008-07-30 20:34:01 +00:00
if ( $considerHtml ) {
2008-07-16 12:40:49 +00:00
foreach ( $openTags as $tag ) {
$truncate .= '</' . $tag . '>' ;
2008-05-30 11:40:08 +00:00
}
}
return $truncate ;
}
/**
* Alias for truncate () .
*
* @ see TextHelper :: truncate ()
* @ access public
*/
function trim () {
$args = func_get_args ();
return call_user_func_array ( array ( & $this , 'truncate' ), $args );
}
/**
* Extracts an excerpt from the text surrounding the phrase with a number of characters on each side determined by radius .
*
* @ param string $text String to search the phrase in
* @ param string $phrase Phrase that will be searched for
* @ param integer $radius The amount of characters that will be returned on each side of the founded phrase
* @ param string $ending Ending that will be appended
* @ return string Modified string
* @ access public
*/
function excerpt ( $text , $phrase , $radius = 100 , $ending = " ... " ) {
if ( empty ( $text ) or empty ( $phrase )) {
return $this -> truncate ( $text , $radius * 2 , $ending );
}
2008-07-30 20:34:01 +00:00
$phraseLen = strlen ( $phrase );
if ( $radius < $phraseLen ) {
$radius = $phraseLen ;
2008-05-30 11:40:08 +00:00
}
$pos = strpos ( strtolower ( $text ), strtolower ( $phrase ));
2009-07-21 20:57:39 +00:00
2008-07-30 20:34:01 +00:00
$startPos = 0 ;
if ( $pos > $radius ) {
$startPos = $pos - $radius ;
}
2009-07-21 20:57:39 +00:00
2008-07-30 20:34:01 +00:00
$textLen = strlen ( $text );
2009-07-21 20:57:39 +00:00
2008-07-30 20:34:01 +00:00
$endPos = $pos + $phraseLen + $radius ;
if ( $endPos >= $textLen ) {
$endPos = $textLen ;
}
2008-05-30 11:40:08 +00:00
2009-07-21 20:57:39 +00:00
$excerpt = substr ( $text , $startPos , $endPos - $startPos );
2008-05-30 11:40:08 +00:00
if ( $startPos != 0 ) {
2008-07-30 20:34:01 +00:00
$excerpt = substr_replace ( $excerpt , $ending , 0 , $phraseLen );
2008-05-30 11:40:08 +00:00
}
2008-07-30 20:34:01 +00:00
if ( $endPos != $textLen ) {
$excerpt = substr_replace ( $excerpt , $ending , - $phraseLen );
2008-05-30 11:40:08 +00:00
}
return $excerpt ;
}
/**
* Creates a comma separated list where the last two items are joined with 'and' , forming natural English
*
* @ param array $list The list to be joined
* @ return string
* @ access public
*/
function toList ( $list , $and = 'and' ) {
2009-11-24 19:11:22 +00:00
$return = '' ;
$count = count ( $list ) - 1 ;
$counter = 0 ;
2008-05-30 11:40:08 +00:00
foreach ( $list as $i => $item ) {
2009-11-24 19:11:22 +00:00
$return .= $item ;
if ( $count > 0 && $counter < $count ) {
$return .= ( $counter < $count - 1 ? ', ' : " { $and } " );
2008-05-30 11:40:08 +00:00
}
2009-11-24 19:11:22 +00:00
$counter ++ ;
2008-05-30 11:40:08 +00:00
}
2009-11-24 19:11:22 +00:00
return $return ;
2008-05-30 11:40:08 +00:00
}
/**
* Text - to - html parser , similar to Textile or RedCloth , only with a little different syntax .
*
* @ param string $text String to " flay "
* @ param boolean $allowHtml Set to true if if html is allowed
* @ return string " Flayed " text
* @ access public
* @ todo Change this . We need a real Textile parser .
* @ codeCoverageIgnoreStart
*/
function flay ( $text , $allowHtml = false ) {
trigger_error ( __ ( '(TextHelper::flay) Deprecated: the Flay library is no longer supported and will be removed in a future version.' , true ), E_USER_WARNING );
if ( ! class_exists ( 'Flay' )) {
uses ( 'flay' );
}
return Flay :: toHtml ( $text , false , $allowHtml );
}
/**
* @ codeCoverageIgnoreEnd
*/
}
?>