See More

= 240 && $ord <= 244) { $result .= '?'; $i += 3; } else { $result .= $str[$i]; } } return $result; } /** * A wrapper for PHP's number_format function * @param $number * @param int $decimals * @return string */ public static function forumNumberFormat($number, $decimals = 0) { return is_numeric($number) ? number_format($number, $decimals, __('lang_decimal_point'), __('lang_thousands_sep')) : $number; } /** * Format a time string according to $timeFormat and time zones * @param $timestamp * @param bool $dateOnly * @param null $dateFormat * @param null $timeFormat * @param bool $timeOnly * @param bool $noText * @return false|string */ public static function formatTime($timestamp, $dateOnly = false, $dateFormat = null, $timeFormat = null, $timeOnly = false, $noText = false) { if ($timestamp == '') { return __('Never'); } $diff = (User::getPref('timezone') + User::getPref('dst')) * 3600; $timestamp += $diff; $now = time(); if (is_null($dateFormat)) { $availableDateFormats = Container::get('forum_date_formats'); $userFormat = User::getPref('date_format'); $dateFormat = isset($availableDateFormats[$userFormat]) ? $availableDateFormats[$userFormat] : $userFormat; } if (is_null($timeFormat)) { $availableTimeFormats = Container::get('forum_time_formats'); $userFormat = User::getPref('time_format'); $timeFormat = isset($availableTimeFormats[$userFormat]) ? $availableTimeFormats[$userFormat] : $userFormat; } $date = gmdate($dateFormat, $timestamp); $today = gmdate($dateFormat, $now+$diff); $yesterday = gmdate($dateFormat, $now+$diff-86400); if (!$noText) { if ($date == $today) { $date = __('Today'); } elseif ($date == $yesterday) { $date = __('Yesterday'); } } if ($dateOnly) { return $date; } elseif ($timeOnly) { return gmdate($timeFormat, $timestamp); } else { return $date.' '.gmdate($timeFormat, $timestamp); } } /** * Calls htmlspecialchars with a few options already set * @param $str * @return string */ public static function escape($str) { return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); } /** * A wrapper for utf8_strlen for compatibility * @param $str * @return int */ public static function strlen($str) { return \utf8\len($str); } /** * Convert \r\n and \r to \n * @param $str * @return mixed */ public static function linebreaks($str) { return str_replace(["\r\n", "\r"], "\n", $str); } /** * A wrapper for utf8_trim for compatibility * @param $str * @param bool $charlist * @return string */ public static function trim($str, $charlist = false) { return is_string($str) ? \utf8\trim($str, $charlist) : ''; } /** * Checks if a string is in all uppercase * @param $string * @return bool */ public static function isAllUppercase($string) { return \utf8\to_upper($string) == $string && \utf8\to_lower($string) != $string; } /** * Replace string matching regular expression * * This function takes care of possibly disabled unicode properties in PCRE builds * @param $pattern * @param $replace * @param $subject * @param bool $callback * @return string|string[]|null */ public static function ucpPregReplace($pattern, $replace, $subject, $callback = false) { if ($callback) { $replaced = preg_replace_callback($pattern, $replace, $subject); } else { $replaced = preg_replace($pattern, $replace, $subject); } // If preg_replace() returns false, this probably means unicode support is not built-in, so we need to modify the pattern a little if ($replaced === false) { if (is_array($pattern)) { foreach ($pattern as $curKey => $curPattern) { $pattern[$curKey] = str_replace('\p{L}\p{N}', '\w', $curPattern); } $replaced = preg_replace($pattern, $replace, $subject); } else { $replaced = preg_replace(str_replace('\p{L}\p{N}', '\w', $pattern), $replace, $subject); } } return $replaced; } /** * Converts the file size in bytes to a human readable file size * @param $size * @return string */ public static function fileSize($size) { $units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']; for ($i = 0; $size > 1024; $i++) { $size /= 1024; } return sprintf(__('Size unit '.$units[$i]), round($size, 2)); } /** * Generate browser's title * @param $pageTitle * @param null $p * @return string */ public static function generatePageTitle($pageTitle, $p = null) { if (!is_array($pageTitle)) { $pageTitle = [$pageTitle]; } $pageTitle = array_reverse($pageTitle); if ($p > 1) { $pageTitle[0] .= ' ('.sprintf(__('Page'), self::forumNumberFormat($p)).')'; } $crumbs = implode(__('Title separator'), $pageTitle); return $crumbs; } /** * Generate breadcrumbs on top of page * @var $crumbs: array('optionnal/url' => 'Text displayed') * @var $rightCrumb: array('link' => 'url/of/action', 'text' => 'Text displayed') * * @return string */ public static function generateBreadcrumbs(array $crumbs = [], array $rightCrumb = []) { ViewInterface::setPageInfo([ 'rightCrumb' => $rightCrumb, 'crumbs' => $crumbs, ], 1 )->addTemplate('breadcrumbs.php'); } /** * Determines the correct title for $user * $user must contain the elements 'username', 'title', 'posts', 'g_id' and 'g_user_title' * @param $user * @return string */ public static function getTitle($user) { static $banList; // If not already built in a previous call, build an array of lowercase banned usernames if (empty($banList)) { $banList = []; foreach (Container::get('bans') as $curBan) { $banList[] = \utf8\to_lower($curBan['username']); } } // If the user has a custom title if ($user['title'] != '') { $userTitle = self::escape($user['title']); } // If the user is banned elseif (in_array(\utf8\to_lower($user['username']), $banList)) { $userTitle = __('Banned'); } // If the user group has a default user title elseif ($user['g_user_title'] != '') { $userTitle = self::escape($user['g_user_title']); } // If the user is a guest elseif ($user['g_id'] == ForumEnv::get('FEATHER_GUEST')) { $userTitle = __('Guest'); } // If nothing else helps, we assign the default else { $userTitle = __('Member'); } return $userTitle; } /** * Determines the correct user title * * @param string $title * @param string $name * @param string $groupTitle * @param int $gid * @return string */ public static function getTitleTwig($title = '', $name = '', $groupTitle = '', $gid = 0) { static $ban_list; // If not already built in a previous call, build an array of lowercase banned usernames if (empty($ban_list)) { $ban_list = []; foreach (Container::get('bans') as $cur_ban) { $ban_list[] = \utf8\to_lower($cur_ban['username']); } } // If the user has a custom title if ($title != '') { $user_title = self::escape($title); } // If the user is banned elseif (in_array(\utf8\to_lower($name), $ban_list)) { $user_title = __('Banned'); } // If the user group has a default user title elseif ($groupTitle != '') { $user_title = self::escape($groupTitle); } // If the user is a guest elseif ($gid == ForumEnv::get('FEATHER_GUEST')) { $user_title = __('Guest'); } // If nothing else helps, we assign the default else { $user_title = __('Member'); } return $user_title; } /** * Replace censored words in $text * @param $text * @return bool|string */ public static function censor($text) { if (!CacheInterface::isCached('search_for')) { CacheInterface::store('search_for', Cache::getCensoring('search_for')); } $searchFor = CacheInterface::retrieve('search_for'); if (!CacheInterface::isCached('replace_with')) { CacheInterface::store('replace_with', Cache::getCensoring('replace_with')); } $replaceWith = CacheInterface::retrieve('replace_with'); if (!empty($searchFor) && !empty($replaceWith)) { return substr(self::ucpPregReplace($searchFor, $replaceWith, ' '.$text.' '), 1, -1); } else { return $text; } } /** * Fetch admin IDs * @return string */ public static function getAdminIds() { // Get Slim current session if (!CacheInterface::isCached('admin_ids')) { CacheInterface::store('admin_ids', Cache::getAdminIds()); } return CacheInterface::retrieve('admin_ids'); } /** * Outputs markup to display a user's avatar * @param $userId * @return string */ public static function generateAvatarMarkup($userId) { $filetypes = ['jpg', 'gif', 'png']; $avatarMarkup = ''; foreach ($filetypes as $curType) { $path = ForumSettings::get('o_avatars_dir').'/'.$userId.'.'.$curType; if (file_exists(ForumEnv::get('FEATHER_ROOT').$path) && $imgSize = getimagesize(ForumEnv::get('FEATHER_ROOT').$path)) { $avatarMarkup = ''; break; } } return $avatarMarkup; } /** * Get IP Address * @return mixed\ */ public static function getIp() { if (isset(Request::getServerParams()['HTTP_CLIENT_IP'])) { $client = Request::getServerParams()['HTTP_CLIENT_IP']; } if (isset(Request::getServerParams()['HTTP_X_FORWARDED_FOR'])) { $forward = Request::getServerParams()['HTTP_X_FORWARDED_FOR']; } $remote = Request::getServerParams()['REMOTE_ADDR']; if (isset($client) && filter_var($client, FILTER_VALIDATE_IP)) { return $client; } elseif (isset($forward) && filter_var($forward, FILTER_VALIDATE_IP)) { return $forward; } return $remote; } /** * Timing attack safe string comparison * * Compares two strings using the same time whether they're equal or not. * * This function was added in PHP 5.6. * * Note: It can leak the length of a string when arguments of differing length are supplied. * * @param string $a Expected string. * @param string $b Actual, user supplied, string. * @return bool Whether strings are equal. * * Sourcecode from WordPress */ public static function hashEquals($a, $b) { if (function_exists('hash_equals')) { return hash_equals((string)$a, (string)$b); } $aLength = strlen($a); if ($aLength !== strlen($b)) { return false; } $result = 0; // Do not attempt to "optimize" this. for ($i = 0; $i < $aLength; $i++) { $result |= ord($a[ $i ]) ^ ord($b[ $i ]); } return $result === 0; } /** * Hash a user password using BCRYPT * Replaces old sha1 password hashing verification * Requires PHP >= 5.5 * * @param string $password User password * @return string Hashed password */ public static function passwordHash($password) { return password_hash($password, PASSWORD_DEFAULT); } /** * Compare an inputed password with the one in database for a user * Requires PHP >= 5.5 * * @param string $password Inputed password * @param string $hash Password stored in database * @return bool Do the passwords match ? */ public static function passwordVerify($password, $hash) { return password_verify($password, $hash); } /** * Check if the password needs rehash because PHP's default algorithm has changed * @param $hash * @return bool */ public static function passwordNeedsRehash($hash) { return password_needs_rehash($hash, PASSWORD_DEFAULT); } }