1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26: 27: 28: 29:
30: if (!class_exists('HtmlHelper')) {
31: App::import('Helper', 'Html');
32: }
33: if (!class_exists('Multibyte')) {
34: App::import('Core', 'Multibyte');
35: }
36: 37: 38: 39: 40: 41: 42: 43:
44: class TextHelper extends AppHelper {
45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55:
56: function highlight($text, $phrase, $highlighter = '<span class="highlight">\1</span>', $considerHtml = false) {
57: if (empty($phrase)) {
58: return $text;
59: }
60:
61: if (is_array($phrase)) {
62: $replace = array();
63: $with = array();
64:
65: foreach ($phrase as $key => $value) {
66: $key = $value;
67: $value = $highlighter;
68: $key = '(' . preg_quote($key, '|') . ')';
69: if ($considerHtml) {
70: $key = '(?![^<]+>)' . $key . '(?![^<]+>)';
71: }
72: $replace[] = '|' . $key . '|iu';
73: $with[] = empty($value) ? $highlighter : $value;
74: }
75: return preg_replace($replace, $with, $text);
76: } else {
77: $phrase = '(' . preg_quote($phrase, '|') . ')';
78: if ($considerHtml) {
79: $phrase = '(?![^<]+>)' . $phrase . '(?![^<]+>)';
80: }
81: return preg_replace('|'.$phrase.'|iu', $highlighter, $text);
82: }
83: }
84: 85: 86: 87: 88: 89: 90:
91: function stripLinks($text) {
92: return preg_replace('|<a\s+[^>]+>|im', '', preg_replace('|<\/a>|im', '', $text));
93: }
94: 95: 96: 97: 98: 99: 100: 101: 102:
103: function autoLinkUrls($text, $htmlOptions = array()) {
104: $options = var_export($htmlOptions, true);
105: $text = preg_replace_callback('#(?<!href="|">)((?:https?|ftp|nntp)://[^\s<>()]+)#i', create_function('$matches',
106: '$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], $matches[0],' . $options . ');'), $text);
107:
108: return preg_replace_callback('#(?<!href="|">)(?<!http://|https://|ftp://|nntp://)(www\.[^\n\%\ <]+[^<\n\%\,\.\ <])(?<!\))#i',
109: create_function('$matches', '$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], "http://" . $matches[0],' . $options . ');'), $text);
110: }
111: 112: 113: 114: 115: 116: 117: 118:
119: function autoLinkEmails($text, $htmlOptions = array()) {
120: $options = 'array(';
121:
122: foreach ($htmlOptions as $option => $value) {
123: $options .= "'$option' => '$value', ";
124: }
125: $options .= ')';
126: $atom = '[a-z0-9!#$%&\'*+\/=?^_`{|}~-]';
127:
128: return preg_replace_callback('/(' . $atom . '+(?:\.' . $atom . '+)*@[a-z0-9-]+(?:\.[a-z0-9-]+)+)/i',
129: create_function('$matches', '$Html = new HtmlHelper(); $Html->tags = $Html->loadConfig(); return $Html->link($matches[0], "mailto:" . $matches[0],' . $options . ');'), $text);
130: }
131: 132: 133: 134: 135: 136: 137: 138:
139: function autoLink($text, $htmlOptions = array()) {
140: return $this->autoLinkEmails($this->autoLinkUrls($text, $htmlOptions), $htmlOptions);
141: }
142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154:
155: function truncate($text, $length = 100, $ending = '...', $exact = true, $considerHtml = false) {
156: if (is_array($ending)) {
157: extract($ending);
158: }
159: if ($considerHtml) {
160: if (mb_strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {
161: return $text;
162: }
163: $totalLength = mb_strlen(strip_tags($ending));
164: $openTags = array();
165: $truncate = '';
166: preg_match_all('/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER);
167: foreach ($tags as $tag) {
168: if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) {
169: if (preg_match('/<[\w]+[^>]*>/s', $tag[0])) {
170: array_unshift($openTags, $tag[2]);
171: } else if (preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag)) {
172: $pos = array_search($closeTag[1], $openTags);
173: if ($pos !== false) {
174: array_splice($openTags, $pos, 1);
175: }
176: }
177: }
178: $truncate .= $tag[1];
179:
180: $contentLength = mb_strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3]));
181: if ($contentLength + $totalLength > $length) {
182: $left = $length - $totalLength;
183: $entitiesLength = 0;
184: 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)) {
185: foreach ($entities[0] as $entity) {
186: if ($entity[1] + 1 - $entitiesLength <= $left) {
187: $left--;
188: $entitiesLength += mb_strlen($entity[0]);
189: } else {
190: break;
191: }
192: }
193: }
194:
195: $truncate .= mb_substr($tag[3], 0 , $left + $entitiesLength);
196: break;
197: } else {
198: $truncate .= $tag[3];
199: $totalLength += $contentLength;
200: }
201: if ($totalLength >= $length) {
202: break;
203: }
204: }
205: } else {
206: if (mb_strlen($text) <= $length) {
207: return $text;
208: } else {
209: $truncate = mb_substr($text, 0, $length - strlen($ending));
210: }
211: }
212: if (!$exact) {
213: $spacepos = mb_strrpos($truncate, ' ');
214: if (isset($spacepos)) {
215: if ($considerHtml) {
216: $bits = mb_substr($truncate, $spacepos);
217: preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER);
218: if (!empty($droppedTags)) {
219: foreach ($droppedTags as $closingTag) {
220: if (!in_array($closingTag[1], $openTags)) {
221: array_unshift($openTags, $closingTag[1]);
222: }
223: }
224: }
225: }
226: $truncate = mb_substr($truncate, 0, $spacepos);
227: }
228: }
229:
230: $truncate .= $ending;
231:
232: if ($considerHtml) {
233: foreach ($openTags as $tag) {
234: $truncate .= '</'.$tag.'>';
235: }
236: }
237:
238: return $truncate;
239: }
240: 241: 242: 243: 244: 245:
246: function trim() {
247: $args = func_get_args();
248: return call_user_func_array(array(&$this, 'truncate'), $args);
249: }
250: 251: 252: 253: 254: 255: 256: 257: 258: 259:
260: function excerpt($text, $phrase, $radius = 100, $ending = "...") {
261: if (empty($text) or empty($phrase)) {
262: return $this->truncate($text, $radius * 2, $ending);
263: }
264:
265: $phraseLen = strlen($phrase);
266: if ($radius < $phraseLen) {
267: $radius = $phraseLen;
268: }
269:
270: $pos = strpos(strtolower($text), strtolower($phrase));
271:
272: $startPos = 0;
273: if ($pos > $radius) {
274: $startPos = $pos - $radius;
275: }
276:
277: $textLen = strlen($text);
278:
279: $endPos = $pos + $phraseLen + $radius;
280: if ($endPos >= $textLen) {
281: $endPos = $textLen;
282: }
283:
284: $excerpt = substr($text, $startPos, $endPos - $startPos);
285: if ($startPos != 0) {
286: $excerpt = substr_replace($excerpt, $ending, 0, $phraseLen);
287: }
288:
289: if ($endPos != $textLen) {
290: $excerpt = substr_replace($excerpt, $ending, -$phraseLen);
291: }
292:
293: return $excerpt;
294: }
295: 296: 297: 298: 299: 300: 301:
302: function toList($list, $and = 'and') {
303: $return = '';
304: $count = count($list) - 1;
305: $counter = 0;
306: foreach ($list as $i => $item) {
307: $return .= $item;
308: if ($count > 0 && $counter < $count) {
309: $return .= ($counter < $count - 1 ? ', ' : " {$and} ");
310: }
311: $counter++;
312: }
313: return $return;
314: }
315: 316: 317: 318: 319: 320: 321: 322: 323: 324:
325: function flay($text, $allowHtml = false) {
326: trigger_error(__('(TextHelper::flay) Deprecated: the Flay library is no longer supported and will be removed in a future version.', true), E_USER_WARNING);
327: if (!class_exists('Flay')) {
328: uses('flay');
329: }
330: return Flay::toHtml($text, false, $allowHtml);
331: }
332: 333: 334:
335: }
336: ?>
337: