Mercurial > hg > Members > shoshi > webvirt
comparison cake/libs/view/helpers/text.php @ 0:261e66bd5a0c
hg init
author | Shoshi TAMAKI <shoshi@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 24 Jul 2011 21:08:31 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:261e66bd5a0c |
---|---|
1 <?php | |
2 /** | |
3 * Text Helper | |
4 * | |
5 * Text manipulations: Highlight, excerpt, truncate, strip of links, convert email addresses to mailto: links... | |
6 * | |
7 * PHP versions 4 and 5 | |
8 * | |
9 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) | |
10 * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) | |
11 * | |
12 * Licensed under The MIT License | |
13 * Redistributions of files must retain the above copyright notice. | |
14 * | |
15 * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) | |
16 * @link http://cakephp.org CakePHP(tm) Project | |
17 * @package cake | |
18 * @subpackage cake.cake.libs.view.helpers | |
19 * @since CakePHP(tm) v 0.10.0.1076 | |
20 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) | |
21 */ | |
22 | |
23 /** | |
24 * Included libraries. | |
25 * | |
26 */ | |
27 if (!class_exists('HtmlHelper')) { | |
28 App::import('Helper', 'Html'); | |
29 } | |
30 if (!class_exists('Multibyte')) { | |
31 App::import('Core', 'Multibyte'); | |
32 } | |
33 | |
34 /** | |
35 * Text helper library. | |
36 * | |
37 * Text manipulations: Highlight, excerpt, truncate, strip of links, convert email addresses to mailto: links... | |
38 * | |
39 * @package cake | |
40 * @subpackage cake.cake.libs.view.helpers | |
41 * @link http://book.cakephp.org/view/1469/Text | |
42 */ | |
43 class TextHelper extends AppHelper { | |
44 | |
45 /** | |
46 * Highlights a given phrase in a text. You can specify any expression in highlighter that | |
47 * may include the \1 expression to include the $phrase found. | |
48 * | |
49 * ### Options: | |
50 * | |
51 * - `format` The piece of html with that the phrase will be highlighted | |
52 * - `html` If true, will ignore any HTML tags, ensuring that only the correct text is highlighted | |
53 * | |
54 * @param string $text Text to search the phrase in | |
55 * @param string $phrase The phrase that will be searched | |
56 * @param array $options An array of html attributes and options. | |
57 * @return string The highlighted text | |
58 * @access public | |
59 * @link http://book.cakephp.org/view/1469/Text#highlight-1622 | |
60 */ | |
61 function highlight($text, $phrase, $options = array()) { | |
62 if (empty($phrase)) { | |
63 return $text; | |
64 } | |
65 | |
66 $default = array( | |
67 'format' => '<span class="highlight">\1</span>', | |
68 'html' => false | |
69 ); | |
70 $options = array_merge($default, $options); | |
71 extract($options); | |
72 | |
73 if (is_array($phrase)) { | |
74 $replace = array(); | |
75 $with = array(); | |
76 | |
77 foreach ($phrase as $key => $segment) { | |
78 $segment = "($segment)"; | |
79 if ($html) { | |
80 $segment = "(?![^<]+>)$segment(?![^<]+>)"; | |
81 } | |
82 | |
83 $with[] = (is_array($format)) ? $format[$key] : $format; | |
84 $replace[] = "|$segment|iu"; | |
85 } | |
86 | |
87 return preg_replace($replace, $with, $text); | |
88 } else { | |
89 $phrase = "($phrase)"; | |
90 if ($html) { | |
91 $phrase = "(?![^<]+>)$phrase(?![^<]+>)"; | |
92 } | |
93 | |
94 return preg_replace("|$phrase|iu", $format, $text); | |
95 } | |
96 } | |
97 | |
98 /** | |
99 * Strips given text of all links (<a href=....) | |
100 * | |
101 * @param string $text Text | |
102 * @return string The text without links | |
103 * @access public | |
104 * @link http://book.cakephp.org/view/1469/Text#stripLinks-1623 | |
105 */ | |
106 function stripLinks($text) { | |
107 return preg_replace('|<a\s+[^>]+>|im', '', preg_replace('|<\/a>|im', '', $text)); | |
108 } | |
109 | |
110 /** | |
111 * Adds links (<a href=....) to a given text, by finding text that begins with | |
112 * strings like http:// and ftp://. | |
113 * | |
114 * @param string $text Text to add links to | |
115 * @param array $options Array of HTML options. | |
116 * @return string The text with links | |
117 * @access public | |
118 * @link http://book.cakephp.org/view/1469/Text#autoLinkUrls-1619 | |
119 */ | |
120 function autoLinkUrls($text, $htmlOptions = array()) { | |
121 $options = var_export($htmlOptions, true); | |
122 $text = preg_replace_callback('#(?<!href="|">)((?:https?|ftp|nntp)://[^\s<>()]+)#i', create_function('$matches', | |
123 '$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], $matches[0],' . $options . ');'), $text); | |
124 | |
125 return preg_replace_callback('#(?<!href="|">)(?<!http://|https://|ftp://|nntp://)(www\.[^\n\%\ <]+[^<\n\%\,\.\ <])(?<!\))#i', | |
126 create_function('$matches', '$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], "http://" . $matches[0],' . $options . ');'), $text); | |
127 } | |
128 | |
129 /** | |
130 * Adds email links (<a href="mailto:....) to a given text. | |
131 * | |
132 * @param string $text Text | |
133 * @param array $options Array of HTML options. | |
134 * @return string The text with links | |
135 * @access public | |
136 * @link http://book.cakephp.org/view/1469/Text#autoLinkEmails-1618 | |
137 */ | |
138 function autoLinkEmails($text, $options = array()) { | |
139 $linkOptions = 'array('; | |
140 foreach ($options as $option => $value) { | |
141 $value = var_export($value, true); | |
142 $linkOptions .= "'$option' => $value, "; | |
143 } | |
144 $linkOptions .= ')'; | |
145 $atom = '[a-z0-9!#$%&\'*+\/=?^_`{|}~-]'; | |
146 | |
147 return preg_replace_callback( | |
148 '/(' . $atom . '+(?:\.' . $atom . '+)*@[a-z0-9-]+(?:\.[a-z0-9-]+)+)/i', | |
149 create_function('$matches', '$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], "mailto:" . $matches[0],' . $linkOptions . ');'), $text); | |
150 } | |
151 | |
152 /** | |
153 * Convert all links and email adresses to HTML links. | |
154 * | |
155 * @param string $text Text | |
156 * @param array $options Array of HTML options. | |
157 * @return string The text with links | |
158 * @access public | |
159 * @link http://book.cakephp.org/view/1469/Text#autoLink-1620 | |
160 */ | |
161 function autoLink($text, $options = array()) { | |
162 return $this->autoLinkEmails($this->autoLinkUrls($text, $options), $options); | |
163 } | |
164 | |
165 /** | |
166 * Truncates text. | |
167 * | |
168 * Cuts a string to the length of $length and replaces the last characters | |
169 * with the ending if the text is longer than length. | |
170 * | |
171 * ### Options: | |
172 * | |
173 * - `ending` Will be used as Ending and appended to the trimmed string | |
174 * - `exact` If false, $text will not be cut mid-word | |
175 * - `html` If true, HTML tags would be handled correctly | |
176 * | |
177 * @param string $text String to truncate. | |
178 * @param integer $length Length of returned string, including ellipsis. | |
179 * @param array $options An array of html attributes and options. | |
180 * @return string Trimmed string. | |
181 * @access public | |
182 * @link http://book.cakephp.org/view/1469/Text#truncate-1625 | |
183 */ | |
184 function truncate($text, $length = 100, $options = array()) { | |
185 $default = array( | |
186 'ending' => '...', 'exact' => true, 'html' => false | |
187 ); | |
188 $options = array_merge($default, $options); | |
189 extract($options); | |
190 | |
191 if ($html) { | |
192 if (mb_strlen(preg_replace('/<.*?>/', '', $text)) <= $length) { | |
193 return $text; | |
194 } | |
195 $totalLength = mb_strlen(strip_tags($ending)); | |
196 $openTags = array(); | |
197 $truncate = ''; | |
198 | |
199 preg_match_all('/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER); | |
200 foreach ($tags as $tag) { | |
201 if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) { | |
202 if (preg_match('/<[\w]+[^>]*>/s', $tag[0])) { | |
203 array_unshift($openTags, $tag[2]); | |
204 } else if (preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag)) { | |
205 $pos = array_search($closeTag[1], $openTags); | |
206 if ($pos !== false) { | |
207 array_splice($openTags, $pos, 1); | |
208 } | |
209 } | |
210 } | |
211 $truncate .= $tag[1]; | |
212 | |
213 $contentLength = mb_strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3])); | |
214 if ($contentLength + $totalLength > $length) { | |
215 $left = $length - $totalLength; | |
216 $entitiesLength = 0; | |
217 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)) { | |
218 foreach ($entities[0] as $entity) { | |
219 if ($entity[1] + 1 - $entitiesLength <= $left) { | |
220 $left--; | |
221 $entitiesLength += mb_strlen($entity[0]); | |
222 } else { | |
223 break; | |
224 } | |
225 } | |
226 } | |
227 | |
228 $truncate .= mb_substr($tag[3], 0 , $left + $entitiesLength); | |
229 break; | |
230 } else { | |
231 $truncate .= $tag[3]; | |
232 $totalLength += $contentLength; | |
233 } | |
234 if ($totalLength >= $length) { | |
235 break; | |
236 } | |
237 } | |
238 } else { | |
239 if (mb_strlen($text) <= $length) { | |
240 return $text; | |
241 } else { | |
242 $truncate = mb_substr($text, 0, $length - mb_strlen($ending)); | |
243 } | |
244 } | |
245 if (!$exact) { | |
246 $spacepos = mb_strrpos($truncate, ' '); | |
247 if (isset($spacepos)) { | |
248 if ($html) { | |
249 $bits = mb_substr($truncate, $spacepos); | |
250 preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER); | |
251 if (!empty($droppedTags)) { | |
252 foreach ($droppedTags as $closingTag) { | |
253 if (!in_array($closingTag[1], $openTags)) { | |
254 array_unshift($openTags, $closingTag[1]); | |
255 } | |
256 } | |
257 } | |
258 } | |
259 $truncate = mb_substr($truncate, 0, $spacepos); | |
260 } | |
261 } | |
262 $truncate .= $ending; | |
263 | |
264 if ($html) { | |
265 foreach ($openTags as $tag) { | |
266 $truncate .= '</'.$tag.'>'; | |
267 } | |
268 } | |
269 | |
270 return $truncate; | |
271 } | |
272 | |
273 /** | |
274 * Extracts an excerpt from the text surrounding the phrase with a number of characters on each side | |
275 * determined by radius. | |
276 * | |
277 * @param string $text String to search the phrase in | |
278 * @param string $phrase Phrase that will be searched for | |
279 * @param integer $radius The amount of characters that will be returned on each side of the founded phrase | |
280 * @param string $ending Ending that will be appended | |
281 * @return string Modified string | |
282 * @access public | |
283 * @link http://book.cakephp.org/view/1469/Text#excerpt-1621 | |
284 */ | |
285 function excerpt($text, $phrase, $radius = 100, $ending = '...') { | |
286 if (empty($text) or empty($phrase)) { | |
287 return $this->truncate($text, $radius * 2, array('ending' => $ending)); | |
288 } | |
289 | |
290 $phraseLen = mb_strlen($phrase); | |
291 if ($radius < $phraseLen) { | |
292 $radius = $phraseLen; | |
293 } | |
294 | |
295 $pos = mb_strpos(mb_strtolower($text), mb_strtolower($phrase)); | |
296 | |
297 $startPos = 0; | |
298 if ($pos > $radius) { | |
299 $startPos = $pos - $radius; | |
300 } | |
301 | |
302 $textLen = mb_strlen($text); | |
303 | |
304 $endPos = $pos + $phraseLen + $radius; | |
305 if ($endPos >= $textLen) { | |
306 $endPos = $textLen; | |
307 } | |
308 | |
309 $excerpt = mb_substr($text, $startPos, $endPos - $startPos); | |
310 if ($startPos != 0) { | |
311 $excerpt = substr_replace($excerpt, $ending, 0, $phraseLen); | |
312 } | |
313 | |
314 if ($endPos != $textLen) { | |
315 $excerpt = substr_replace($excerpt, $ending, -$phraseLen); | |
316 } | |
317 | |
318 return $excerpt; | |
319 } | |
320 | |
321 /** | |
322 * Creates a comma separated list where the last two items are joined with 'and', forming natural English | |
323 * | |
324 * @param array $list The list to be joined | |
325 * @param string $and The word used to join the last and second last items together with. Defaults to 'and' | |
326 * @param string $separator The separator used to join all othe other items together. Defaults to ', ' | |
327 * @return string The glued together string. | |
328 * @access public | |
329 * @link http://book.cakephp.org/view/1469/Text#toList-1624 | |
330 */ | |
331 function toList($list, $and = 'and', $separator = ', ') { | |
332 if (count($list) > 1) { | |
333 return implode($separator, array_slice($list, null, -1)) . ' ' . $and . ' ' . array_pop($list); | |
334 } else { | |
335 return array_pop($list); | |
336 } | |
337 } | |
338 } |