[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 namespace Joomla\CMS\HTML\Helpers; 11 12 use Joomla\CMS\HTML\HTMLHelper; 13 use Joomla\String\StringHelper as FrameworkStringHelper; 14 15 // phpcs:disable PSR1.Files.SideEffects 16 \defined('JPATH_PLATFORM') or die; 17 // phpcs:enable PSR1.Files.SideEffects 18 19 /** 20 * HTML helper class for rendering manipulated strings. 21 * 22 * @since 1.6 23 */ 24 abstract class StringHelper 25 { 26 /** 27 * Truncates text blocks over the specified character limit and closes 28 * all open HTML tags. The method will optionally not truncate an individual 29 * word, it will find the first space that is within the limit and 30 * truncate at that point. This method is UTF-8 safe. 31 * 32 * @param string $text The text to truncate. 33 * @param integer $length The maximum length of the text. 34 * @param boolean $noSplit Don't split a word if that is where the cutoff occurs (default: true). 35 * @param boolean $allowHtml Allow HTML tags in the output, and close any open tags (default: true). 36 * 37 * @return string The truncated text. 38 * 39 * @since 1.6 40 */ 41 public static function truncate($text, $length = 0, $noSplit = true, $allowHtml = true) 42 { 43 // Assume a lone open tag is invalid HTML. 44 if ($length === 1 && $text[0] === '<') { 45 return '...'; 46 } 47 48 // Check if HTML tags are allowed. 49 if (!$allowHtml) { 50 // Deal with spacing issues in the input. 51 $text = str_replace('>', '> ', $text); 52 $text = str_replace(array(' ', ' '), ' ', $text); 53 $text = FrameworkStringHelper::trim(preg_replace('#\s+#mui', ' ', $text)); 54 55 // Strip the tags from the input and decode entities. 56 $text = strip_tags($text); 57 $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8'); 58 59 // Remove remaining extra spaces. 60 $text = str_replace(' ', ' ', $text); 61 $text = FrameworkStringHelper::trim(preg_replace('#\s+#mui', ' ', $text)); 62 } 63 64 // Whether or not allowing HTML, truncate the item text if it is too long. 65 if ($length > 0 && FrameworkStringHelper::strlen($text) > $length) { 66 $tmp = trim(FrameworkStringHelper::substr($text, 0, $length)); 67 68 if ($tmp[0] === '<' && strpos($tmp, '>') === false) { 69 return '...'; 70 } 71 72 // $noSplit true means that we do not allow splitting of words. 73 if ($noSplit) { 74 // Find the position of the last space within the allowed length. 75 $offset = FrameworkStringHelper::strrpos($tmp, ' '); 76 $tmp = FrameworkStringHelper::substr($tmp, 0, $offset + 1); 77 78 // If there are no spaces and the string is longer than the maximum 79 // we need to just use the ellipsis. In that case we are done. 80 if ($offset === false && strlen($text) > $length) { 81 return '...'; 82 } 83 84 if (FrameworkStringHelper::strlen($tmp) > $length - 3) { 85 $tmp = trim(FrameworkStringHelper::substr($tmp, 0, FrameworkStringHelper::strrpos($tmp, ' '))); 86 } 87 } 88 89 if ($allowHtml) { 90 // Put all opened tags into an array 91 preg_match_all("#<([a-z][a-z0-9]*)\b.*?(?!/)>#i", $tmp, $result); 92 $openedTags = $result[1]; 93 94 // Some tags self close so they do not need a separate close tag. 95 $openedTags = array_diff($openedTags, array('img', 'hr', 'br')); 96 $openedTags = array_values($openedTags); 97 98 // Put all closed tags into an array 99 preg_match_all("#</([a-z][a-z0-9]*)\b(?:[^>]*?)>#iU", $tmp, $result); 100 $closedTags = $result[1]; 101 102 $numOpened = count($openedTags); 103 104 // Not all tags are closed so trim the text and finish. 105 if (count($closedTags) !== $numOpened) { 106 // Closing tags need to be in the reverse order of opening tags. 107 $openedTags = array_reverse($openedTags); 108 109 // Close tags 110 for ($i = 0; $i < $numOpened; $i++) { 111 if (!in_array($openedTags[$i], $closedTags)) { 112 $tmp .= '</' . $openedTags[$i] . '>'; 113 } else { 114 unset($closedTags[array_search($openedTags[$i], $closedTags)]); 115 } 116 } 117 } 118 119 // Check if we are within a tag 120 if (FrameworkStringHelper::strrpos($tmp, '<') > FrameworkStringHelper::strrpos($tmp, '>')) { 121 $offset = FrameworkStringHelper::strrpos($tmp, '<'); 122 $tmp = FrameworkStringHelper::trim(FrameworkStringHelper::substr($tmp, 0, $offset)); 123 } 124 } 125 126 if ($tmp === false || strlen($text) > strlen($tmp)) { 127 $text = trim($tmp) . '...'; 128 } 129 } 130 131 // Clean up any internal spaces created by the processing. 132 $text = str_replace(' </', '</', $text); 133 $text = str_replace(' ...', '...', $text); 134 135 return $text; 136 } 137 138 /** 139 * Method to extend the truncate method to more complex situations 140 * 141 * The goal is to get the proper length plain text string with as much of 142 * the html intact as possible with all tags properly closed. 143 * 144 * @param string $html The content of the introtext to be truncated 145 * @param integer $maxLength The maximum number of characters to render 146 * @param boolean $noSplit Don't split a word if that is where the cutoff occurs (default: true). 147 * 148 * @return string The truncated string. If the string is truncated an ellipsis 149 * (...) will be appended. 150 * 151 * @note If a maximum length of 3 or less is selected and the text has more than 152 * that number of characters an ellipsis will be displayed. 153 * This method will not create valid HTML from malformed HTML. 154 * 155 * @since 3.1 156 */ 157 public static function truncateComplex($html, $maxLength = 0, $noSplit = true) 158 { 159 // Start with some basic rules. 160 $baseLength = strlen($html); 161 162 // If the original HTML string is shorter than the $maxLength do nothing and return that. 163 if ($baseLength <= $maxLength || $maxLength === 0) { 164 return $html; 165 } 166 167 // Take care of short simple cases. 168 if ($maxLength <= 3 && $html[0] !== '<' && strpos(substr($html, 0, $maxLength - 1), '<') === false && $baseLength > $maxLength) { 169 return '...'; 170 } 171 172 // Deal with maximum length of 1 where the string starts with a tag. 173 if ($maxLength === 1 && $html[0] === '<') { 174 $endTagPos = strlen(strstr($html, '>', true)); 175 $tag = substr($html, 1, $endTagPos); 176 177 $l = $endTagPos + 1; 178 179 if ($noSplit) { 180 return substr($html, 0, $l) . '</' . $tag . '...'; 181 } 182 183 // @todo: $character doesn't seem to be used... 184 $character = substr(strip_tags($html), 0, 1); 185 186 return substr($html, 0, $l) . '</' . $tag . '...'; 187 } 188 189 // First get the truncated plain text string. This is the rendered text we want to end up with. 190 $ptString = HTMLHelper::_('string.truncate', $html, $maxLength, $noSplit, $allowHtml = false); 191 192 // It's all HTML, just return it. 193 if ($ptString === '') { 194 return $html; 195 } 196 197 // If the plain text is shorter than the max length the variable will not end in ... 198 // In that case we use the whole string. 199 if (substr($ptString, -3) !== '...') { 200 return $html; 201 } 202 203 // Regular truncate gives us the ellipsis but we want to go back for text and tags. 204 if ($ptString === '...') { 205 $stripped = substr(strip_tags($html), 0, $maxLength); 206 $ptString = HTMLHelper::_('string.truncate', $stripped, $maxLength, $noSplit, $allowHtml = false); 207 } 208 209 // We need to trim the ellipsis that truncate adds. 210 $ptString = rtrim($ptString, '.'); 211 212 // Now deal with more complex truncation. 213 while ($maxLength <= $baseLength) { 214 // Get the truncated string assuming HTML is allowed. 215 $htmlString = HTMLHelper::_('string.truncate', $html, $maxLength, $noSplit, $allowHtml = true); 216 217 if ($htmlString === '...' && strlen($ptString) + 3 > $maxLength) { 218 return $htmlString; 219 } 220 221 $htmlString = rtrim($htmlString, '.'); 222 223 // Now get the plain text from the HTML string and trim it. 224 $htmlStringToPtString = HTMLHelper::_('string.truncate', $htmlString, $maxLength, $noSplit, $allowHtml = false); 225 $htmlStringToPtString = rtrim($htmlStringToPtString, '.'); 226 227 // If the new plain text string matches the original plain text string we are done. 228 if ($ptString === $htmlStringToPtString) { 229 return $htmlString . '...'; 230 } 231 232 // Get the number of HTML tag characters in the first $maxLength characters 233 $diffLength = strlen($ptString) - strlen($htmlStringToPtString); 234 235 if ($diffLength <= 0) { 236 return $htmlString . '...'; 237 } 238 239 // Set new $maxlength that adjusts for the HTML tags 240 $maxLength += $diffLength; 241 } 242 } 243 244 /** 245 * Abridges text strings over the specified character limit. The 246 * behavior will insert an ellipsis into the text replacing a section 247 * of variable size to ensure the string does not exceed the defined 248 * maximum length. This method is UTF-8 safe. 249 * 250 * For example, it transforms "Really long title" to "Really...title". 251 * 252 * Note that this method does not scan for HTML tags so will potentially break them. 253 * 254 * @param string $text The text to abridge. 255 * @param integer $length The maximum length of the text (default is 50). 256 * @param integer $intro The maximum length of the intro text (default is 30). 257 * 258 * @return string The abridged text. 259 * 260 * @since 1.6 261 */ 262 public static function abridge($text, $length = 50, $intro = 30) 263 { 264 // Abridge the item text if it is too long. 265 if (FrameworkStringHelper::strlen($text) > $length) { 266 // Determine the remaining text length. 267 $remainder = $length - ($intro + 3); 268 269 // Extract the beginning and ending text sections. 270 $beg = FrameworkStringHelper::substr($text, 0, $intro); 271 $end = FrameworkStringHelper::substr($text, FrameworkStringHelper::strlen($text) - $remainder); 272 273 // Build the resulting string. 274 $text = $beg . '...' . $end; 275 } 276 277 return $text; 278 } 279 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |