3 * @copyright Copyright (C) 2020, Friendica
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 namespace Friendica\Util;
24 use Friendica\Content\ContactSelector;
25 use Friendica\Core\Logger;
28 * This class handles string functions
33 * Generates a pseudo-random string of hexadecimal characters
39 public static function getRandomHex($size = 64)
41 $byte_size = ceil($size / 2);
43 $bytes = random_bytes($byte_size);
45 $return = substr(bin2hex($bytes), 0, $size);
51 * Checks, if the given string is a valid hexadecimal code
53 * @param string $hexCode
57 public static function isHex($hexCode)
59 return !empty($hexCode) ? @preg_match("/^[a-f0-9]{2,}$/i", $hexCode) && !(strlen($hexCode) & 1) : false;
63 * This is our primary input filter.
65 * Use this on any text input where angle chars are not valid or permitted
66 * They will be replaced with safer brackets. This may be filtered further
67 * if these are not allowed either.
69 * @param string $string Input string
70 * @return string Filtered string
72 public static function escapeTags($string)
74 return str_replace(["<", ">"], ['[', ']'], $string);
78 * Use this on "body" or "content" input where angle chars shouldn't be removed,
79 * and allow them to be safely displayed.
80 * @param string $string
84 public static function escapeHtml($string)
86 return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false);
90 * Generate a string that's random, but usually pronounceable. Used to generate initial passwords
92 * @param int $len length
96 public static function getRandomName($len)
102 $vowels = ['a', 'a', 'ai', 'au', 'e', 'e', 'e', 'ee', 'ea', 'i', 'ie', 'o', 'ou', 'u'];
104 if (mt_rand(0, 5) == 4) {
110 'c', 'ch', 'cl', 'cr',
113 'g', 'gh', 'gl', 'gr',
116 'k', 'kh', 'kl', 'kr',
120 'p', 'ph', 'pl', 'pr',
123 's', 'sc', 'sh', 'sm', 'sp', 'st',
132 'ck', 'ct', 'gn', 'ld', 'lf', 'lm', 'lt', 'mb', 'mm', 'mn', 'mp',
133 'nd', 'ng', 'nk', 'nt', 'rn', 'rp', 'rt'
137 'bl', 'br', 'cl', 'cr', 'dr', 'fl', 'fr', 'gl', 'gr',
138 'kh', 'kl', 'kr', 'mn', 'pl', 'pr', 'rh', 'tr', 'qu', 'wh', 'q'
141 $start = mt_rand(0, 2);
150 for ($x = 0; $x < $len; $x++) {
151 $r = mt_rand(0, count($table) - 1);
154 if ($table == $vowels) {
155 $table = array_merge($cons, $midcons);
161 $word = substr($word, 0, $len);
163 foreach ($noend as $noe) {
164 $noelen = strlen($noe);
165 if ((strlen($word) > $noelen) && (substr($word, -$noelen) == $noe)) {
166 $word = self::getRandomName($len);
175 * Translate and format the network name of a contact
177 * @param string $network Network name of the contact (e.g. dfrn, rss and so on)
178 * @param string $url The contact url
180 * @return string Formatted network name
181 * @throws \Friendica\Network\HTTPException\InternalServerErrorException
183 public static function formatNetworkName($network, $url = '')
185 if ($network != '') {
187 $network_name = '<a href="' . $url . '">' . ContactSelector::networkToName($network, $url) . '</a>';
189 $network_name = ContactSelector::networkToName($network);
192 return $network_name;
197 * Remove indentation from a text
199 * @param string $text String to be transformed.
200 * @param string $chr Optional. Indentation tag. Default tab (\t).
201 * @param int $count Optional. Default null.
203 * @return string Transformed string.
205 public static function deindent($text, $chr = "[\t ]", $count = NULL)
207 $lines = explode("\n", $text);
209 if (is_null($count)) {
212 while ($k < count($lines) && strlen($lines[$k]) == 0) {
215 preg_match("|^" . $chr . "*|", $lines[$k], $m);
216 $count = strlen($m[0]);
219 for ($k = 0; $k < count($lines); $k++) {
220 $lines[$k] = preg_replace("|^" . $chr . "{" . $count . "}|", "", $lines[$k]);
223 return implode("\n", $lines);
227 * Get byte size returned in a Data Measurement (KB, MB, GB)
229 * @param int $bytes The number of bytes to be measured
230 * @param int $precision Optional. Default 2.
232 * @return string Size with measured units.
234 public static function formatBytes($bytes, $precision = 2)
236 $units = ['B', 'KB', 'MB', 'GB', 'TB'];
237 $bytes = max($bytes, 0);
238 $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
239 $pow = min($pow, count($units) - 1);
240 $bytes /= pow(1024, $pow);
242 return round($bytes, $precision) . ' ' . $units[$pow];
246 * Protect percent characters in sprintf calls
248 * @param string $s String to transform.
250 * @return string Transformed string.
252 public static function protectSprintf($s)
254 return str_replace('%', '%%', $s);
258 * Base64 Encode URL and translate +/ to -_ Optionally strip padding.
260 * @param string $s URL to encode
261 * @param boolean $strip_padding Optional. Default false
263 * @return string Encoded URL
265 public static function base64UrlEncode($s, $strip_padding = false)
267 $s = strtr(base64_encode($s), '+/', '-_');
269 if ($strip_padding) {
270 $s = str_replace('=', '', $s);
277 * Decode Base64 Encoded URL and translate -_ to +/
278 * @param string $s URL to decode
280 * @return string Decoded URL
283 public static function base64UrlDecode($s)
286 Logger::log('base64url_decode: illegal input: ' . print_r(debug_backtrace(), true));
291 * // Placeholder for new rev of salmon which strips base64 padding.
292 * // PHP base64_decode handles the un-padded input without requiring this step
293 * // Uncomment if you find you need it.
296 * if (!strpos($s,'=')) {
306 return base64_decode(strtr($s, '-_', '+/'));
312 * @param string $url URL to be normalized.
314 * @return string Normalized URL.
316 public static function normaliseLink($url)
318 $ret = str_replace(['https:', '//www.'], ['http:', '//'], $url);
319 return rtrim($ret, '/');
323 * Normalize OpenID identity
325 * @param string $s OpenID Identity
327 * @return string normalized OpenId Identity
329 public static function normaliseOpenID($s)
331 return trim(str_replace(['http://', 'https://'], ['', ''], $s), '/');
335 * Compare two URLs to see if they are the same, but ignore
336 * slight but hopefully insignificant differences such as if one
337 * is https and the other isn't, or if one is www.something and
338 * the other isn't - and also ignore case differences.
340 * @param string $a first url
341 * @param string $b second url
342 * @return boolean True if the URLs match, otherwise False
345 public static function compareLink($a, $b)
347 return (strcasecmp(self::normaliseLink($a), self::normaliseLink($b)) === 0);
351 * Ensures the provided URI has its query string punctuation in order.
356 public static function ensureQueryParameter($uri)
358 if (strpos($uri, '?') === false && ($pos = strpos($uri, '&')) !== false) {
359 $uri = substr($uri, 0, $pos) . '?' . substr($uri, $pos + 1);
366 * Check if the trimmed provided string is starting with one of the provided characters
368 * @param string $string
369 * @param array $chars
372 public static function startsWith($string, array $chars)
374 $return = in_array(substr(trim($string), 0, 1), $chars);
380 * Returns the regular expression string to match URLs in a given text
383 * @see https://daringfireball.net/2010/07/improved_regex_for_matching_urls
385 public static function autoLinkRegEx()
388 (?<![=\'\]"/]) # Not preceded by [, =, \', ], ", /
390 ( # Capture 1: entire matched URL
391 https?:// # http or https protocol
393 [^/\s\xA0`!()\[\]{};:\'",<>?«»“”‘’.] # Domain can\'t start with a .
394 [^/\s\xA0`!()\[\]{};:\'",<>?«»“”‘’]+ # Domain can\'t end with a .
396 [^/\s\xA0`!()\[\]{};:\'".,<>?«»“”‘’]+/? # Followed by a slash
399 [^\s\xA0()<>]+ # Run of non-space, non-()<>
401 \(([^\s\xA0()<>]+|(\([^\s()<>]+\)))*\) # balanced parens, up to 2 levels
403 [^\s\xA0`!()\[\]{};:\'".,<>?«»“”‘’] # not a space or one of these punct chars
409 * Ensures a single path item doesn't contain any path-traversing characters
411 * @see https://stackoverflow.com/a/46097713
412 * @param string $pathItem
415 public static function sanitizeFilePathItem($pathItem)
417 $pathItem = str_replace('/', '_', $pathItem);
418 $pathItem = str_replace('\\', '_', $pathItem);
419 $pathItem = str_replace(DIRECTORY_SEPARATOR, '_', $pathItem); // In case it does not equal the standard values