1<?php 2 3/* 4 * This file is part of the TYPO3 CMS project. 5 * 6 * It is free software; you can redistribute it and/or modify it under 7 * the terms of the GNU General Public License, either version 2 8 * of the License, or any later version. 9 * 10 * For the full copyright and license information, please read the 11 * LICENSE.txt file that was distributed with this source code. 12 * 13 * The TYPO3 project - inspiring people to share! 14 */ 15 16namespace TYPO3\CMS\Core\Utility; 17 18/** 19 * Class with helper functions for string handling 20 */ 21class StringUtility 22{ 23 /** 24 * Returns TRUE if $haystack begins with $needle. 25 * The input string is not trimmed before and search is done case sensitive. 26 * 27 * @param string $haystack Full string to check 28 * @param string $needle Reference string which must be found as the "first part" of the full string 29 * @throws \InvalidArgumentException 30 * @return bool TRUE if $needle was found to be equal to the first part of $haystack 31 */ 32 public static function beginsWith($haystack, $needle) 33 { 34 // Sanitize $haystack and $needle 35 if (is_array($haystack) || is_object($haystack) || $haystack === null || (string)$haystack != $haystack) { 36 throw new \InvalidArgumentException( 37 '$haystack can not be interpreted as string', 38 1347135546 39 ); 40 } 41 if (is_array($needle) || is_object($needle) || (string)$needle != $needle || strlen($needle) < 1) { 42 throw new \InvalidArgumentException( 43 '$needle can not be interpreted as string or has zero length', 44 1347135547 45 ); 46 } 47 $haystack = (string)$haystack; 48 $needle = (string)$needle; 49 return $needle !== '' && strpos($haystack, $needle) === 0; 50 } 51 52 /** 53 * Returns TRUE if $haystack ends with $needle. 54 * The input string is not trimmed before and search is done case sensitive. 55 * 56 * @param string $haystack Full string to check 57 * @param string $needle Reference string which must be found as the "last part" of the full string 58 * @throws \InvalidArgumentException 59 * @return bool TRUE if $needle was found to be equal to the last part of $haystack 60 */ 61 public static function endsWith($haystack, $needle) 62 { 63 // Sanitize $haystack and $needle 64 if (is_array($haystack) || is_object($haystack) || $haystack === null || (string)$haystack != $haystack) { 65 throw new \InvalidArgumentException( 66 '$haystack can not be interpreted as string', 67 1347135544 68 ); 69 } 70 if (is_array($needle) || is_object($needle) || (string)$needle != $needle || strlen($needle) < 1) { 71 throw new \InvalidArgumentException( 72 '$needle can not be interpreted as string or has no length', 73 1347135545 74 ); 75 } 76 $haystackLength = strlen($haystack); 77 $needleLength = strlen($needle); 78 if (!$haystackLength || $needleLength > $haystackLength) { 79 return false; 80 } 81 $position = strrpos((string)$haystack, (string)$needle); 82 return $position !== false && $position === $haystackLength - $needleLength; 83 } 84 85 /** 86 * This function generates a unique id by using the more entropy parameter. 87 * Furthermore the dots are removed so the id can be used inside HTML attributes e.g. id. 88 * 89 * @param string $prefix 90 * @return string 91 */ 92 public static function getUniqueId($prefix = '') 93 { 94 $uniqueId = uniqid($prefix, true); 95 return str_replace('.', '', $uniqueId); 96 } 97 98 /** 99 * Escape a CSS selector to be used for DOM queries 100 * 101 * This method takes care to escape any CSS selector meta character. 102 * The result may be used to query the DOM like $('#' + escapedSelector) 103 * 104 * @param string $selector 105 * @return string 106 */ 107 public static function escapeCssSelector(string $selector): string 108 { 109 return preg_replace('/([#:.\\[\\],=@])/', '\\\\$1', $selector); 110 } 111 112 /** 113 * Removes the Byte Order Mark (BOM) from the input string. This method supports UTF-8 encoded strings only! 114 * 115 * @param string $input 116 * @return string 117 */ 118 public static function removeByteOrderMark(string $input): string 119 { 120 if (strpos($input, "\xef\xbb\xbf") === 0) { 121 $input = substr($input, 3); 122 } 123 124 return $input; 125 } 126 127 /** 128 * Matching two strings against each other, supporting a "*" wildcard (match many) or a "?" wildcard (match one= or (if wrapped in "/") PCRE regular expressions 129 * 130 * @param string $haystack The string in which to find $needle. 131 * @param string $needle The string to find in $haystack 132 * @return bool Returns TRUE if $needle matches or is found in (according to wildcards) $haystack. E.g. if $haystack is "Netscape 6.5" and $needle is "Net*" or "Net*ape" then it returns TRUE. 133 */ 134 public static function searchStringWildcard($haystack, $needle): bool 135 { 136 $result = false; 137 if ($haystack === $needle) { 138 $result = true; 139 } elseif ($needle) { 140 if (preg_match('/^\\/.+\\/$/', $needle)) { 141 // Regular expression, only "//" is allowed as delimiter 142 $regex = $needle; 143 } else { 144 $needle = str_replace(['*', '?'], ['%%%MANY%%%', '%%%ONE%%%'], $needle); 145 $regex = '/^' . preg_quote($needle, '/') . '$/'; 146 // Replace the marker with .* to match anything (wildcard) 147 $regex = str_replace(['%%%MANY%%%', '%%%ONE%%%'], ['.*', '.'], $regex); 148 } 149 $result = (bool)preg_match($regex, $haystack); 150 } 151 return $result; 152 } 153 154 /** 155 * Works the same as str_pad() except that it correctly handles strings with multibyte characters 156 * and takes an additional optional argument $encoding. 157 * 158 * @param string $string 159 * @param int $length 160 * @param string $pad_string 161 * @param int $pad_type 162 * @param string $encoding 163 * @return string 164 */ 165 public static function multibyteStringPad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, string $encoding = 'UTF-8'): string 166 { 167 $len = mb_strlen($string, $encoding); 168 $pad_string_len = mb_strlen($pad_string, $encoding); 169 if ($len >= $length || $pad_string_len === 0) { 170 return $string; 171 } 172 173 switch ($pad_type) { 174 case STR_PAD_RIGHT: 175 $string .= str_repeat($pad_string, (int)(($length - $len)/$pad_string_len)); 176 $string .= mb_substr($pad_string, 0, ($length - $len) % $pad_string_len); 177 return $string; 178 179 case STR_PAD_LEFT: 180 $leftPad = str_repeat($pad_string, (int)(($length - $len)/$pad_string_len)); 181 $leftPad .= mb_substr($pad_string, 0, ($length - $len) % $pad_string_len); 182 return $leftPad . $string; 183 184 case STR_PAD_BOTH: 185 $leftPadCount = (int)(($length - $len)/2); 186 $len += $leftPadCount; 187 $padded = ((int)($leftPadCount / $pad_string_len)) * $pad_string_len; 188 $leftPad = str_repeat($pad_string, (int)($leftPadCount / $pad_string_len)); 189 $leftPad .= mb_substr($pad_string, 0, $leftPadCount - $padded); 190 $string = $leftPad . $string . str_repeat($pad_string, ($length - $len)/$pad_string_len); 191 $string .= mb_substr($pad_string, 0, ($length - $len) % $pad_string_len); 192 return $string; 193 } 194 return $string; 195 } 196} 197