- <?php
-
- use App\Models\AdminAdvert;
- use App\Models\PaidAdvert;
- use App\Classes\{BBCode, Calendar, Metrika, CloudFlare};
- use App\Models\Antimat;
- use App\Models\Ban;
- use App\Models\Banhist;
- use App\Models\BlackList;
- use App\Models\Article;
- use App\Models\Item;
- use App\Models\Load;
- use App\Models\Chat;
- use App\Models\Counter;
- use App\Models\Down;
- use App\Models\Guestbook;
- use App\Models\Invite;
- use App\Models\Error;
- use App\Models\News;
- use App\Models\Notice;
- use App\Models\Offer;
- use App\Models\Online;
- use App\Models\Photo;
- use App\Models\Post;
- use App\Models\Advert;
- use App\Models\Setting;
- use App\Models\Sticker;
- use App\Models\Spam;
- use App\Models\Topic;
- use App\Models\User;
- use App\Models\Vote;
- use GuzzleHttp\Client;
- use Illuminate\Mail\Message;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Database\Eloquent\Builder;
- use Illuminate\Database\Eloquent\Model;
- use Illuminate\Pagination\LengthAwarePaginator;
- use Illuminate\Support\Arr;
- use Illuminate\Support\Facades\Cache;
- use Illuminate\Support\Facades\Mail;
- use Illuminate\Support\HtmlString;
- use Illuminate\Support\Str;
- use Illuminate\Support\ViewErrorBag;
- use Intervention\Image\Constraint;
- use Intervention\Image\ImageManagerStatic as Image;
- use ReCaptcha\ReCaptcha;
-
- const ROTOR_VERSION = '10.1';
- define('SITETIME', time());
-
- /**
- * Форматирует вывод времени из секунд
- *
- * @param int $time секунды
- *
- * @return string форматированный вывод
- */
- function makeTime(int $time): string
- {
- $format = $time < 3600 ? 'i:s' : 'H:i:s';
-
- return gmdate($format, $time);
- }
-
- /**
- * Форматирует время с учетом часовых поясов
- *
- * @param int|null $timestamp Секунды
- * @param string $format Формат времени
- * @param bool $original Формат без изменения
- *
- * @return string Форматированный вывод
- */
- function dateFixed(?int $timestamp, string $format = 'd.m.Y / H:i', bool $original = false): string
- {
- if (! is_numeric($timestamp)) {
- $timestamp = SITETIME;
- }
-
- $shift = getUser('timezone') * 3600;
- $dateStamp = date($format, $timestamp + $shift);
-
- if ($original) {
- return $dateStamp;
- }
-
- $today = date('d.m.Y', SITETIME + $shift);
- $yesterday = date('d.m.Y', strtotime('-1 day', SITETIME + $shift));
-
- $replaces = [
- $today => __('main.today'),
- $yesterday => __('main.yesterday'),
- 'January' => __('main.january'),
- 'February' => __('main.february'),
- 'March' => __('main.march'),
- 'April' => __('main.april'),
- 'May' => __('main.may'),
- 'June' => __('main.june'),
- 'July' => __('main.july'),
- 'August' => __('main.august'),
- 'September' => __('main.september'),
- 'October' => __('main.october'),
- 'November' => __('main.november'),
- 'December' => __('main.december'),
- ];
-
- return strtr($dateStamp, $replaces);
- }
-
- /**
- * Конвертирует строку в кодировку utf-8
- *
- * @param string $str строка
- *
- * @return string Конвертированная строка
- */
- function winToUtf(string $str): string
- {
- return mb_convert_encoding($str, 'utf-8', 'windows-1251');
- }
-
- /**
- * Преобразует строку в нижний регистр
- *
- * @param string $str строка
- *
- * @return string Преобразованная строка
- */
- function utfLower(string $str): string
- {
- return mb_strtolower($str, 'utf-8');
- }
-
- /**
- * Обрезает строку
- *
- * @param mixed $str Строка
- * @param int $start Начало позиции
- * @param int|null $length Конец позиции
- *
- * @return string Обрезанная строка
- */
- function utfSubstr($str, int $start, ?int $length = null): string
- {
- if (! $length) {
- $length = utfStrlen($str);
- }
-
- return mb_substr($str, $start, $length, 'utf-8');
- }
-
- /**
- * Возвращает длину строки
- *
- * @param mixed $str строка
- *
- * @return int Длина строка
- */
- function utfStrlen($str): int
- {
- return mb_strlen($str, 'utf-8');
- }
-
- /**
- * Является ли кодировка utf-8
- *
- * @param string $str строка
- *
- * @return bool
- */
- function isUtf(string $str): bool
- {
- return mb_check_encoding($str, 'utf-8');
- }
-
- /**
- * Преобразует специальные символы в HTML-сущности
- *
- * @param mixed $string Строка или массив строк
- * @param bool $doubleEncode Преобразовывать существующие html-сущности
- *
- * @return array|string Обработанные данные
- */
- function check($string, bool $doubleEncode = true)
- {
- if (is_array($string)) {
- foreach ($string as $key => $val) {
- $string[$key] = check($val, $doubleEncode);
- }
- } else {
- $string = htmlspecialchars($string, ENT_QUOTES, 'UTF-8', $doubleEncode);
- $search = [chr(0), "\x00", "\x1A", chr(226) . chr(128) . chr(174)];
- $string = str_replace($search, [], $string);
- }
-
- return $string;
- }
-
- /**
- * Преобразует в положительное число
- *
- * @param int|string $num число
- *
- * @return int Обработанные данные
- */
- function int($num): int
- {
- return abs((int) $num);
- }
-
- /**
- * Преобразует все элементы массива в int
- *
- * @param array|int|string $numbers массив или число
- *
- * @return array|null Обработанные данные
- */
- function intar($numbers): ?array
- {
- if ($numbers) {
- if (is_array($numbers)) {
- $numbers = array_map('intval', $numbers);
- } else {
- $numbers = [(int) $numbers];
- }
- }
-
- return $numbers;
- }
-
- /**
- * Возвращает размер в человеко читаемом формате
- *
- * @param int $bytes размер в байтах
- * @param int $precision кол. символов после запятой
- *
- * @return string Форматированный вывод размера
- */
- function formatSize(int $bytes, int $precision = 2): string
- {
- $units = ['B', 'Kb', 'Mb', 'Gb', 'Tb'];
- $pow = floor(($bytes ? log($bytes) : 0) / log(1000));
- $pow = min($pow, count($units) - 1);
-
- $bytes /= (1 << (10 * $pow));
-
- return round($bytes, $precision) . $units[$pow];
- }
-
- /**
- * Возвращает размер файла человеко-читаемом формате
- *
- * @param string $file Путь к файлу
- *
- * @return string Размер в читаемом формате
- */
- function formatFileSize(string $file): string
- {
- if (file_exists($file) && is_file($file)) {
- return formatSize(filesize($file));
- }
-
- return formatSize(0);
- }
-
- /**
- * Возвращает время в человеко-читаемом формате
- *
- * @param int $time Кол. секунд timestamp
- * @param int $crumbs Кол. элементов
- *
- * @return string Время в читаемом формате
- */
- function formatTime(int $time, int $crumbs = 2): string
- {
- if ($time < 1) {
- return '0';
- }
-
- $units = [
- __('main.plural_years') => 31536000,
- __('main.plural_months') => 2592000,
- __('main.plural_days') => 86400,
- __('main.plural_hours') => 3600,
- __('main.plural_minutes') => 60,
- __('main.plural_seconds') => 1,
- ];
-
- $return = [];
-
- foreach ($units as $unit => $seconds) {
- $format = floor($time / $seconds);
- $time %= $seconds;
-
- if ($format >= 1) {
- $return[] = plural($format, $unit);
- }
- }
-
- return implode(' ', array_slice($return, 0, $crumbs));
- }
-
- /**
- * Очищает строку от мата по базе слов
- *
- * @param string|null $str строка
- *
- * @return string Обработанная строка
- */
- function antimat(?string $str): string
- {
- return Antimat::replace((string) $str);
- }
-
- /**
- * Возвращает рейтинг в виде звезд
- *
- * @param int|float $rating рейтинг
- *
- * @return HtmlString Преобразованный рейтинг
- */
- function ratingVote($rating): HtmlString
- {
- $rating = round($rating / 0.5) * 0.5;
-
- $full_stars = floor($rating);
- $half_stars = ceil($rating - $full_stars);
- $empty_stars = 5 - $full_stars - $half_stars;
-
- $output = '<div class="star-rating fa-lg text-danger">';
- $output .= str_repeat('<i class="fas fa-star"></i>', $full_stars);
- $output .= str_repeat('<i class="fas fa-star-half-alt"></i>', $half_stars);
- $output .= str_repeat('<i class="far fa-star"></i>', $empty_stars);
- $output .= '( ' . $rating . ' )</div>';
-
- return new HtmlString($output);
- }
-
- /**
- * Возвращает календарь
- *
- * @param int $time
- *
- * @return HtmlString календарь
- */
- function getCalendar(int $time = SITETIME): HtmlString
- {
- $calendar = new Calendar();
-
- return new HtmlString($calendar->getCalendar($time));
- }
-
- /**
- * Возвращает количество пользователей онлайн по типам
- *
- * @return array Массив данных
- */
- function statsOnline(): array
- {
- return Cache::remember('online', 60, static function () {
- $users = Online::query()
- ->select('user_id')
- ->distinct('user_id')
- ->whereNotNull('user_id')
- ->get();
-
- $usersCount = $users->count();
- $guestsCount = Online::query()->whereNull('user_id')->count();
- $total = $usersCount + $guestsCount;
-
- $metrika = new Metrika();
- $metrika->getCounter($usersCount + $guestsCount);
-
- return [$usersCount, $guestsCount, $total, $users];
- });
- }
-
- /**
- * Возвращает количество пользователей онлайн
- *
- * @return HtmlString|null
- */
- function showOnline(): ?HtmlString
- {
- if (setting('onlines')) {
- $online = statsOnline();
-
- return new HtmlString(view('app/_online', compact('online')));
- }
-
- return null;
- }
-
- /**
- * Get online widget
- *
- * @return mixed
- */
- function onlineWidget(): HtmlString
- {
- $online = statsOnline();
-
- return new HtmlString(view('widgets/_online', compact('online')));
- }
-
- /**
- * Возвращает статистику посещений
- *
- * @return array статистика посещений
- */
- function statsCounter(): array
- {
- return Cache::remember('counter', 30, static function () {
- $counter = Counter::query()->first();
-
- return $counter ? $counter->toArray() : [];
- });
- }
-
- /**
- * Выводит счетчик посещений
- *
- * @return HtmlString|null
- */
- function showCounter(): ?HtmlString
- {
- $metrika = new Metrika();
- $metrika->saveStatistic();
-
- $counter = statsCounter();
-
- if (setting('incount') > 0) {
- return new HtmlString(view('app/_counter', compact('counter')));
- }
-
- return null;
- }
-
- /**
- * Возвращает количество пользователей
- *
- * @return string Количество пользователей
- */
- function statsUsers(): string
- {
- return Cache::remember('statUsers', 1800, static function () {
- $startDay = mktime(0, 0, 0, dateFixed(SITETIME, 'n', true));
-
- $stat = User::query()->count();
- $new = User::query()->where('created_at', '>', $startDay)->count();
-
- if ($new) {
- $stat .= '/+' . $new;
- }
-
- return $stat;
- });
- }
-
- /**
- * Возвращает количество администраторов
- *
- * @return int Количество администраторов
- */
- function statsAdmins(): int
- {
- return Cache::remember('statAdmins', 3600, static function () {
- return User::query()->whereIn('level', User::ADMIN_GROUPS)->count();
- });
- }
-
- /**
- * Возвращает количество жалоб
- *
- * @return int Количество жалоб
- */
- function statsSpam(): int
- {
- return Spam::query()->count();
- }
-
- /**
- * Возвращает количество забанненых пользователей
- *
- * @return int Количество забаненных
- */
- function statsBanned(): int
- {
- return User::query()
- ->where('level', User::BANNED)
- ->where('timeban', '>', SITETIME)
- ->count();
- }
-
- /**
- * Возвращает количество записей в истории банов
- *
- * @return int Количество записей
- */
- function statsBanHist(): int
- {
- return Banhist::query()->count();
- }
-
- /**
- * Возвращает количество ожидающих подтверждения регистрации
- *
- * @return int Количество ожидающих
- */
- function statsRegList(): int
- {
- return User::query()->where('level', User::PENDED)->count();
- }
-
- /**
- * Возвращает количество забаненных по IP
- *
- * @return int Количество забаненных
- */
- function statsIpBanned(): int
- {
- return Ban::query()->count();
- }
-
- /**
- * Возвращает количество фотографий в галерее
- *
- * @return string Количество фотографий
- */
- function statsPhotos(): string
- {
- return Cache::remember('statPhotos', 900, static function () {
- $stat = Photo::query()->count();
- $totalNew = Photo::query()->where('created_at', '>', strtotime('-1 day', SITETIME))->count();
-
- return formatShortNum($stat) . ($totalNew ? '/+' . $totalNew : '');
- });
- }
-
- /**
- * Возвращает количество новостей
- *
- * @return string Количество новостей
- */
- function statsNews(): string
- {
- return Cache::remember('statNews', 300, static function () {
- $total = News::query()->count();
-
- $totalNew = News::query()
- ->where('created_at', '>', strtotime('-1 day', SITETIME))
- ->count();
-
- return formatShortNum($total) . ($totalNew ? '/+' . $totalNew : '');
- });
- }
-
- /**
- * Возвращает количество записей в черном списке
- *
- * @return string Количество записей
- */
- function statsBlacklist(): string
- {
- $blacklist = BlackList::query()
- ->selectRaw('type, count(*) as total')
- ->groupBy('type')
- ->pluck('total', 'type')
- ->all();
-
- $list = $blacklist + ['login' => 0, 'email' => 0, 'domain' => 0];
-
- return $list['login'] . '/' . $list['email'] . '/' . $list['domain'];
- }
-
- /**
- * Возвращает количество записей в антимате
- *
- * @return int Количество записей
- */
- function statsAntimat(): int
- {
- return Antimat::query()->count();
- }
-
- /**
- * Возвращает количество стикеров
- *
- * @return int Количество стикеров
- */
- function statsStickers(): int
- {
- return Sticker::query()->count();
- }
-
- /**
- * Возвращает дату последнего сканирования сайта
- *
- * @return int|string Дата последнего сканирования
- */
- function statsChecker()
- {
- if (file_exists(storage_path('framework/cache/checker.php'))) {
- return dateFixed(filemtime(storage_path('framework/cache/checker.php')), 'd.m.Y');
- }
-
- return 0;
- }
-
- /**
- * Возвращает количество приглашений на регистрацию
- *
- * @return string Количество приглашений
- */
- function statsInvite(): string
- {
- $invited = Invite::query()->where('used', 0)->count();
- $usedInvited = Invite::query()->where('used', 1)->count();
-
- return $invited . '/' . $usedInvited;
- }
-
- /**
- * Возвращает следующею и предыдущую фотографию в галерее
- *
- * @param int $id Id фотографий
- *
- * @return array|null Массив данных
- */
- function photoNavigation(int $id): ?array
- {
- if (! $id) {
- return null;
- }
-
- $next = Photo::query()
- ->where('id', '>', $id)
- ->orderBy('id')
- ->pluck('id')
- ->first();
-
- $prev = Photo::query()
- ->where('id', '<', $id)
- ->orderByDesc('id')
- ->pluck('id')
- ->first();
-
- return compact('next', 'prev');
- }
-
- /**
- * Возвращает количество статей в блогах
- *
- * @return string Количество статей
- */
- function statsBlog(): string
- {
- return Cache::remember('statArticles', 900, static function () {
- $stat = Article::query()->count();
- $totalNew = Article::query()->where('created_at', '>', strtotime('-1 day', SITETIME))->count();
-
- return formatShortNum($stat) . ($totalNew ? '/+' . $totalNew : '');
- });
- }
-
- /**
- * Возвращает количество тем и сообщений в форуме
- *
- * @return string Количество тем и сообщений
- */
- function statsForum(): string
- {
- return Cache::remember('statForums', 600, static function () {
- $topics = Topic::query()->count();
- $posts = Post::query()->count();
-
- $totalNew = Post::query()
- ->where('created_at', '>', strtotime('-1 day', SITETIME))
- ->count();
-
- return formatShortNum($topics) . '/' . formatShortNum($posts) . ($totalNew ? '/+' . $totalNew : '');
- });
- }
-
- /**
- * Возвращает количество сообщений в гостевой книге
- *
- * @return string Количество сообщений
- */
- function statsGuestbook(): string
- {
- return Cache::remember('statGuestbook', 600, static function () {
- $total = Guestbook::query()->count();
-
- $totalNew = Guestbook::query()
- ->where('created_at', '>', strtotime('-1 day', SITETIME))
- ->count();
-
- return formatShortNum($total) . ($totalNew ? '/+' . $totalNew : '');
- });
- }
-
- /**
- * Возвращает количество сообщений в админ-чате
- *
- * @return string Количество сообщений
- */
- function statsChat(): string
- {
- return Cache::remember('statChat', 3600, static function () {
- $total = Chat::query()->count();
-
- $totalNew = Chat::query()
- ->where('created_at', '>', strtotime('-1 day', SITETIME))
- ->count();
-
- return formatShortNum($total) . ($totalNew ? '/+' . $totalNew : '');
- });
- }
-
- /**
- * Возвращает время последнего сообщения в админ-чате
- *
- * @return int Время сообщения
- */
- function statsNewChat(): int
- {
- return Chat::query()->max('created_at') ?? 0;
- }
-
- /**
- * Возвращает количество файлов в загруз-центре
- *
- * @return string Количество файлов
- */
- function statsLoad(): string
- {
- return Cache::remember('statLoads', 900, static function () {
- $totalLoads = Load::query()->sum('count_downs');
-
- $totalNew = Down::query()->where('active', 1)
- ->where('created_at', '>', strtotime('-1 day', SITETIME))
- ->count();
-
- return formatShortNum($totalLoads) . ($totalNew ? '/+' . $totalNew : '');
- });
- }
-
- /**
- * Возвращает количество новых файлов
- *
- * @return int Количество файлов
- */
- function statsNewLoad(): int
- {
- return Down::query()->where('active', 0)->count();
- }
-
- /**
- * Возвращает количество объявлений
- *
- * @return string Количество статей
- */
- function statsBoard(): string
- {
- return Cache::remember('statBoards', 900, static function () {
- $stat = formatShortNum(Item::query()->where('expires_at', '>', SITETIME)->count());
- $totalNew = Item::query()->where('updated_at', '>', strtotime('-1 day', SITETIME))->count();
-
- return formatShortNum($stat) . ($totalNew ? '/+' . $totalNew : '');
- });
- }
-
- /**
- * Обфусцирует email
- *
- * @param string $email email
- *
- * @return string Обфусцированный email
- */
- function cryptMail(string $email): string
- {
- $output = '';
- $symbols = str_split($email);
-
- foreach ($symbols as $symbol) {
- $output .= '&#' . ord($symbol) . ';';
- }
-
- return $output;
- }
-
- /**
- * Частично скрывает email
- *
- * @param string $email
- *
- * @return string
- */
- function hideMail(string $email): string
- {
- return preg_replace('/(?<=.).(?=.*@)/u', '*', $email);
- }
-
- /**
- * Возвращает статистику текущих голосований из кэш-файла
- *
- * @return string Статистика текущий голосований
- */
- function statVotes(): string
- {
- return Cache::remember('statVotes', 900, static function () {
- $votes = Vote::query()
- ->selectRaw('count(*) AS cnt, coalesce(sum(count), 0) AS sum')
- ->where('closed', 0)
- ->first();
-
- if (! $votes) {
- $votes->cnt = $votes->sum = 0;
- }
-
- return $votes->cnt . '/' . $votes->sum;
- });
- }
-
- /**
- * Возвращает дату последней новости из кэш-файла
- *
- * @return string Дата последней новости
- */
- function statsNewsDate()
- {
- $newsDate = Cache::remember('statNewsDate', 900, static function () {
- /** @var News $news */
- $news = News::query()->orderByDesc('created_at')->first();
-
- return $news->created_at ?? 0;
- });
-
- return $newsDate ? dateFixed($newsDate, 'd.m.Y') : 0;
- }
-
- /**
- * Возвращает последние новости
- *
- * @return HtmlString Новость
- */
- function lastNews(): HtmlString
- {
- $news = null;
-
- if (setting('lastnews') > 0) {
- $news = Cache::remember('lastNews', 1800, static function () {
- return News::query()
- ->where('top', 1)
- ->orderByDesc('created_at')
- ->limit(setting('lastnews'))
- ->get();
- });
- }
-
- return new HtmlString(view('widgets/_news', compact('news')));
- }
-
- /**
- * Возвращает иконку расширения
- *
- * @param string $ext Расширение файла
- *
- * @return HtmlString Иконка
- */
- function icons(string $ext): HtmlString
- {
- switch ($ext) {
- case 'php':
- $ico = 'file-code';
- break;
- case 'ppt':
- $ico = 'file-powerpoint';
- break;
- case 'doc':
- case 'docx':
- $ico = 'file-word';
- break;
- case 'xls':
- case 'xlsx':
- $ico = 'file-excel';
- break;
- case 'txt':
- case 'css':
- case 'dat':
- case 'html':
- case 'htm':
- $ico = 'file-alt';
- break;
- case 'wav':
- case 'amr':
- case 'mp3':
- case 'mid':
- $ico = 'file-audio';
- break;
- case 'zip':
- case 'rar':
- case '7z':
- case 'gz':
- $ico = 'file-archive';
- break;
- case '3gp':
- case 'mp4':
- $ico = 'file-video';
- break;
- case 'jpg':
- case 'jpeg':
- case 'bmp':
- case 'wbmp':
- case 'gif':
- case 'png':
- $ico = 'file-image';
- break;
- case 'ttf':
- $ico = 'font';
- break;
- case 'pdf':
- $ico = 'file-pdf';
- break;
- default:
- $ico = 'file';
- }
- return new HtmlString('<i class="far fa-' . $ico . '"></i>');
- }
-
- /**
- * Перемешивает элементы ассоциативного массива, сохраняя ключи
- *
- * @param array &$array Исходный массив, переданный по ссылке
- *
- * @return bool Флаг успешного выполнения операции
- */
- function shuffleAssoc(array &$array): bool
- {
- $keys = array_keys($array);
-
- shuffle($keys);
- $new = [];
-
- foreach ($keys as $key) {
- $new[$key] = $array[$key];
- }
-
- $array = $new;
-
- return true;
- }
-
- /**
- * Закрывает bb-теги
- *
- * @param string $html
- *
- * @return string
- */
- function closeTags(string $html): string
- {
- preg_match_all('#\[([a-z]+)(?:=.*)?(?<![/])\]#iU', $html, $result);
- $openTags = $result[1];
-
- preg_match_all('#\[/([a-z]+)\]#iU', $html, $result);
- $closedTags = $result[1];
-
- if ($openTags === $closedTags) {
- return $html;
- }
-
- $diff = array_diff_assoc($openTags, $closedTags);
- $tags = array_reverse($diff);
-
- foreach ($tags as $value) {
- $html .= '[/' . $value . ']';
- }
-
- return $html;
- }
-
- /**
- * Возвращает обрезанный текст с закрытием тегов
- *
- * @param string $value
- * @param int $words
- * @param string $end
- *
- * @return HtmlString
- */
- function bbCodeTruncate(string $value, int $words = 20, string $end = '...'): HtmlString
- {
- $value = Str::words($value, $words, $end);
- $bbText = bbCode(closeTags($value));
-
- return new HtmlString(preg_replace('/\[(.*?)\]/', '', $bbText));
- }
-
- /**
- * Возвращает обрезанную до заданного количества букв строке
- *
- * @param HtmlString|string $value Исходная строка
- * @param int $limit Максимальное количество символов в результате
- * @param string $end
- *
- * @return string Обрезанная строка
- */
- function truncateString($value, int $limit = 100, string $end = '...'): string
- {
- $value = strip_tags($value);
-
- if (mb_strlen($value, 'utf-8') <= $limit) {
- return $value;
- }
-
- $string = mb_substr($value, 0, $limit + 1);
- if ($lastSpace = mb_strrpos($string, ' ', 0, 'utf-8')) {
- $string = mb_substr($string, 0, $lastSpace, 'utf-8');
- } else {
- $string = mb_substr($string, 0, $limit, 'utf-8');
- }
-
- return trim($string) . $end;
- }
-
- /**
- * Возвращает обрезанную до заданного количества слов строке
- *
- * @param HtmlString|string $value Исходная строка
- * @param int $words Максимальное количество слов в результате
- * @param string $end
- *
- * @return string Обрезанная строка
- */
- function truncateWord($value, int $words = 20, string $end = '...'): string
- {
- $value = strip_tags($value);
-
- return Str::words(trim($value), $words, $end);
- }
-
- /**
- * Возвращает обрезанную строку с удалением перевода строки
- *
- * @param HtmlString|string $value
- * @param int $words
- * @param string $end
- *
- * @return string
- */
- function truncateDescription($value, int $words = 20, string $end = ''): string
- {
- $value = strip_tags(preg_replace('/\s+/', ' ', $value));
-
- return Str::words(trim($value), $words, $end);
- }
-
- /**
- * Возвращает код платной рекламы
- *
- * @param string $place
- *
- * @return HtmlString|null
- */
- function getAdvertPaid(string $place): ?HtmlString
- {
- $adverts = PaidAdvert::statAdverts();
-
- if (isset($adverts[$place])) {
- $links = [];
- foreach ($adverts[$place] as $advert) {
- $links[] = Arr::random($advert);
- }
-
- return new HtmlString(implode('<br>', $links));
- }
-
- return null;
- }
-
- /**
- * Возвращает код админской рекламы
- *
- * @return HtmlString|null
- */
- function getAdvertAdmin(): ?HtmlString
- {
- $adverts = AdminAdvert::statAdverts();
-
- if ($adverts) {
- $result = Arr::random($adverts);
-
- return new HtmlString(view('adverts/_admin_links', compact('result')));
- }
-
- return null;
- }
-
- /**
- * Возвращает код пользовательской рекламы
- *
- * @return HtmlString|null
- */
- function getAdvertUser(): ?HtmlString
- {
- $adverts = Advert::statAdverts();
-
- if ($adverts) {
- $total = count($adverts);
- $show = setting('rekusershow') > $total ? $total : setting('rekusershow');
-
- $links = Arr::random($adverts, $show);
- $result = implode('<br>', $links);
-
- return new HtmlString(view('adverts/_links', compact('result')));
- }
-
- return null;
- }
-
- /**
- * Выводит последние фотографии
- *
- * @param int $show Количество последних фотографий
- *
- * @return HtmlString Список фотографий
- */
- function recentPhotos(int $show = 5): HtmlString
- {
- $photos = Cache::remember('recentPhotos', 1800, static function () use ($show) {
- return Photo::query()
- ->orderByDesc('created_at')
- ->limit($show)
- ->with('files')
- ->get();
- });
-
- return new HtmlString(view('widgets/_photos', compact('photos')));
- }
-
- /**
- * Выводит последние темы форума
- *
- * @param int $show Количество последних тем форума
- *
- * @return HtmlString Список тем
- */
- function recentTopics(int $show = 5): HtmlString
- {
- $topics = Cache::remember('recentTopics', 300, static function () use ($show) {
- return Topic::query()
- ->orderByDesc('updated_at')
- ->limit($show)
- ->get();
- });
-
- return new HtmlString(view('widgets/_topics', compact('topics')));
- }
-
- /**
- * Выводит последние файлы в загрузках
- *
- * @param int $show Количество последних файлов в загрузках
- *
- * @return HtmlString Список файлов
- */
- function recentDowns(int $show = 5): HtmlString
- {
- $downs = Cache::remember('recentDowns', 600, static function () use ($show) {
- return Down::query()
- ->where('active', 1)
- ->orderByDesc('created_at')
- ->limit($show)
- ->with('category')
- ->get();
- });
-
- return new HtmlString(view('widgets/_downs', compact('downs')));
- }
-
- /**
- * Выводит последние статьи в блогах
- *
- * @param int $show Количество последних статей в блогах
- *
- * @return HtmlString Список статей
- */
- function recentArticles(int $show = 5): HtmlString
- {
- $articles = Cache::remember('recentArticles', 600, static function () use ($show) {
- return Article::query()
- ->orderByDesc('created_at')
- ->limit($show)
- ->get();
- });
-
- return new HtmlString(view('widgets/_articles', compact('articles')));
- }
-
- /**
- * Выводит последние объявления
- *
- * @param int $show Количество последних объявлений
- *
- * @return HtmlString Список объявлений
- */
- function recentBoards(int $show = 5): HtmlString
- {
- $items = Cache::remember('recentBoards', 600, static function () use ($show) {
- return Item::query()
- ->where('expires_at', '>', SITETIME)
- ->orderByDesc('created_at')
- ->limit($show)
- ->get();
- });
-
- return new HtmlString(view('widgets/_boards', compact('items')));
- }
-
- /**
- * Возвращает количество предложений и проблем
- *
- * @return string Количество предложений и проблем
- */
- function statsOffers(): string
- {
- return Cache::remember('offers', 600, static function () {
- $offers = Offer::query()->where('type', 'offer')->count();
- $problems = Offer::query()->where('type', 'issue')->count();
-
- return $offers . '/' . $problems;
- });
- }
-
- /**
- * Пересчитывает счетчики
- *
- * @param string $mode сервис счетчиков
- *
- * @return void
- */
- function restatement(string $mode)
- {
- switch ($mode) {
- case 'forums':
- DB::update('update topics set count_posts = (select count(*) from posts where topics.id = posts.topic_id)');
- DB::update('update forums set count_topics = (select count(*) from topics where forums.id = topics.forum_id)');
- DB::update('update forums set count_posts = (select coalesce(sum(count_posts), 0) from topics where forums.id = topics.forum_id)');
- break;
-
- case 'blogs':
- DB::update('update blogs set count_articles = (select count(*) from articles where blogs.id = articles.category_id)');
- DB::update('update articles set count_comments = (select count(*) from comments where relate_type = "' . Article::$morphName . '" and articles.id = comments.relate_id)');
- break;
-
- case 'loads':
- DB::update('update loads set count_downs = (select count(*) from downs where loads.id = downs.category_id and active = ?)', [1]);
- DB::update('update downs set count_comments = (select count(*) from comments where relate_type = "' . Down::$morphName . '" and downs.id = comments.relate_id)');
- break;
-
- case 'news':
- DB::update('update news set count_comments = (select count(*) from comments where relate_type = "' . News::$morphName . '" and news.id = comments.relate_id)');
- break;
-
- case 'photos':
- DB::update('update photos set count_comments = (select count(*) from comments where relate_type = "' . Photo::$morphName . '" and photos.id = comments.relate_id)');
- break;
-
- case 'offers':
- DB::update('update offers set count_comments = (select count(*) from comments where relate_type = "' . Offer::$morphName . '" and offers.id = comments.relate_id)');
- break;
-
- case 'boards':
- DB::update('update boards set count_items = (select count(*) from items where boards.id = items.board_id and items.expires_at > ' . SITETIME . ');');
- break;
-
- case 'votes':
- DB::update('update votes set count = (select coalesce(sum(result), 0) from voteanswer where votes.id = voteanswer.vote_id)');
- break;
- }
- }
-
- /**
- * Возвращает количество строк в файле
- *
- * @param string $file Путь к файлу
- *
- * @return int Количество строк
- */
- function counterString(string $file): int
- {
- $countLines = 0;
- if (file_exists($file)) {
- $countLines = count(file($file));
- }
-
- return $countLines;
- }
-
- /**
- * Форматирует вывод числа
- *
- * @param int|float $num число
- *
- * @return HtmlString Форматированное число
- */
- function formatNum($num): HtmlString
- {
- if ($num > 0) {
- $data = '<span style="color:#00aa00">+' . $num . '</span>';
- } elseif ($num < 0) {
- $data = '<span style="color:#ff0000">' . $num . '</span>';
- } else {
- $data = '<span>0</span>';
- }
-
- return new HtmlString($data);
- }
-
- /**
- * Форматирует вывод числа
- *
- * @param int $num
- *
- * @return string
- */
- function formatShortNum(int $num)
- {
- if (! is_numeric($num)) {
- return '0b';
- }
-
- if ($num > 1000000000000) {
- return round($num / 1000000000000, 1) . 'T';
- }
-
- if ($num > 1000000000) {
- return round($num / 1000000000, 1) . 'B';
- }
-
- if ($num > 1000000) {
- return round($num / 1000000, 1) . 'M';
- }
-
- if ($num > 1000) {
- return round($num / 1000, 1) . 'K';
- }
-
- return $num;
- }
-
- /**
- * Обрабатывает и уменьшает изображение
- *
- * @param string|null $path Путь к изображению
- * @param array $params Параметры изображения
- *
- * @return array Обработанные параметры
- */
- function resizeProcess(?string $path, array $params = []): array
- {
- if (empty($params['alt'])) {
- $params['alt'] = basename($path);
- }
-
- if (empty($params['class'])) {
- $params['class'] = 'img-fluid';
- }
-
- if (! file_exists(public_path($path)) || ! is_file(public_path($path))) {
- return [
- 'path' => '/assets/img/images/photo.png',
- 'source' => false,
- 'params' => $params,
- ];
- }
-
- [$width, $height] = getimagesize(public_path($path));
-
- if ($width <= setting('previewsize') && $height <= setting('previewsize')) {
- return [
- 'path' => $path,
- 'source' => $path,
- 'params' => $params,
- ];
- }
-
- $thumb = ltrim(str_replace('/', '_', $path), '_');
-
- if (! file_exists(public_path('uploads/thumbnails/' . $thumb))) {
- $img = Image::make(public_path($path));
- $img->resize(setting('previewsize'), setting('previewsize'), static function (Constraint $constraint) {
- $constraint->aspectRatio();
- $constraint->upsize();
- });
-
- $img->save(public_path('uploads/thumbnails/' . $thumb));
- }
-
- return [
- 'path' => '/uploads/thumbnails/' . $thumb,
- 'source' => $path,
- 'params' => $params,
- ];
- }
-
- /**
- * Возвращает уменьшенное изображение
- *
- * @param string|null $path Путь к изображению
- * @param array $params Параметры изображения
- *
- * @return HtmlString Уменьшенное изображение
- */
- function resizeImage(?string $path, array $params = []): HtmlString
- {
- $image = resizeProcess($path, $params);
-
- $strParams = [];
- foreach ($image['params'] as $key => $param) {
- $strParams[] = $key . '="' . check($param) . '"';
- }
-
- $strParams = implode(' ', $strParams);
-
- return new HtmlString('<img src="' . $image['path'] . '" data-source="' . $image['source'] . '" ' . $strParams . '>');
- }
-
- /**
- * Удаляет директорию рекурсивно
- *
- * @param string $dir путь к директории
- *
- * @return void
- */
- function deleteDir(string $dir)
- {
- if (file_exists($dir)) {
- if ($files = glob($dir . '/*')) {
- foreach ($files as $file) {
- is_dir($file) ? deleteDir($file) : unlink($file);
- }
- }
- rmdir($dir);
- }
- }
-
- /**
- * Удаляет файл
- *
- * @param string $path Путь к файлу
- *
- * @return bool
- */
- function deleteFile(string $path): bool
- {
- if (file_exists($path) && is_file($path)) {
- unlink($path);
- }
-
- if (in_array(getExtension($path), ['jpg', 'jpeg', 'gif', 'png'], true)) {
- $thumb = ltrim(str_replace([public_path(), '/'], ['', '_'], $path), '_');
- $thumb = public_path('uploads/thumbnails/' . $thumb);
-
- if (file_exists($thumb) && is_file($thumb)) {
- unlink($thumb);
- }
- }
-
- return true;
- }
-
- /**
- * Отправляет уведомление об упоминании в приват
- *
- * @param string $text Текст сообщения
- * @param string $url Путь к странице
- * @param string $title Название страницу
- *
- * @return void
- */
- function sendNotify(string $text, string $url, string $title)
- {
- /*$parseText = preg_replace('|\[quote(.*?)\](.*?)\[/quote\]|s', '', $text);*/
- preg_match_all('/(?<=^|\s|=)@([\w\-]+)/', $text, $matches);
-
- if (! empty($matches[1])) {
- $login = getUser('login') ?? setting('guestsuser');
- $usersAnswer = array_unique(array_diff($matches[1], [$login]));
-
- foreach ($usersAnswer as $user) {
- $user = getUserByLogin($user);
-
- if ($user && $user->notify) {
- $notify = textNotice('notify', compact('login', 'url', 'title', 'text'));
- $user->sendMessage(null, $notify);
- }
- }
- }
- }
-
- /**
- * Возвращает приватное сообщение
- *
- * @param string $type Тип сообщения
- * @param array $replace Массив заменяемых параметров
- *
- * @return string Сформированный текст
- */
- function textNotice(string $type, array $replace = []): string
- {
- /** @var Notice $message */
- $message = Notice::query()->where('type', $type)->first();
-
- if (! $message) {
- return __('main.text_missing');
- }
-
- foreach ($replace as $key => $val) {
- $message->text = str_replace('%' . $key . '%', $val, $message->text);
- }
-
- return $message->text;
- }
-
- /**
- * Возвращает блок статистики производительности
- *
- * @return HtmlString|null Статистика производительности
- */
- function performance(): ?HtmlString
- {
- if (isAdmin() && setting('performance')) {
- $queries = getQueryLog();
- $timeQueries = array_sum(array_column($queries, 'time'));
-
- return new HtmlString(view('app/_performance', compact('queries', 'timeQueries')));
- }
-
- return null;
- }
-
- /**
- * Очистка кеш-файлов
- *
- * @param string|array|null $keys
- *
- * @return bool Результат выполнения
- */
- function clearCache($keys = null): bool
- {
- if ($keys) {
- if (!is_array($keys)) {
- $keys = [$keys];
- }
-
- foreach ($keys as $key) {
- Cache::forget($key);
- }
-
- return true;
- }
-
- Cache::flush();
-
- return true;
- }
-
- /**
- * Возвращает текущую страницу
- *
- * @param string|null $url
- *
- * @return string|null Текущая страница
- */
- function returnUrl(?string $url = null): ?string
- {
- $request = request();
-
- if ($request->is('/', 'login', 'register', 'recovery', 'restore', 'ban', 'closed')) {
- return null;
- }
-
- $query = $request->has('return') ? $request->input('return') : $request->path();
-
- return '?return=' . urlencode($url ?? '/' . $query);
- }
-
- /**
- * Saves error logs
- *
- * @param int $code
- * @param string|null $message
- *
- * @return void
- */
- function saveErrorLog(int $code, ?string $message = null)
- {
- $errorCodes = [401, 403, 404, 405, 419, 429, 500, 503, 666];
-
- if (setting('errorlog') && in_array($code, $errorCodes, true)) {
- Error::query()->create([
- 'code' => $code,
- 'request' => utfSubstr(request()->getRequestUri(), 0, 250),
- 'referer' => utfSubstr(request()->header('referer'), 0, 250),
- 'user_id' => getUser('id'),
- 'message' => utfSubstr($message, 0, 250),
- 'ip' => getIp(),
- 'brow' => getBrowser(),
- 'created_at' => SITETIME,
- ]);
- }
- }
-
- /**
- * Возвращает ошибку
- *
- * @param string|array $errors ошибки
- *
- * @return HtmlString Сформированный блок с ошибкой
- */
- function showError($errors): HtmlString
- {
- $errors = (array) $errors;
-
- return new HtmlString(view('app/_error', compact('errors')));
- }
-
- /**
- * @return HtmlString
- */
- function getCaptcha(): HtmlString
- {
- return new HtmlString(view('app/_captcha'));
- }
-
- /**
- * Сохраняет flash уведомления
- *
- * @param string $status Статус уведомления
- * @param mixed $message Массив или текст с уведомлениями
- *
- * @return void
- *
- * @deprecated since 10.1 - Use redirect->with('success', 'Message') or session()->flash()
- */
- function setFlash(string $status, $message)
- {
- session()->put('flash.' . $status, $message);
- }
-
- /**
- * Сохраняет POST данные введенных пользователем
- *
- * @param array $data Массив полей
- *
- * @deprecated since 10.1
- */
- function setInput(array $data)
- {
- session()->flash('input', json_encode($data));
- }
-
- /**
- * Возвращает значение из POST данных
- *
- * @param string $key Имя поля
- * @param mixed $default
- *
- * @return mixed Сохраненное значение
- *
- * @deprecated since 10.1 - Use old('field', 'default');
- */
- function getInput(string $key, $default = null)
- {
- if (session()->missing('input')) {
- return $default;
- }
-
- $input = json_decode(session()->get('input', []), true);
-
- return Arr::get($input, $key, $default);
- }
-
- /**
- * Подсвечивает блок с полем для ввода сообщения
- *
- * @param string $field Имя поля
- *
- * @return string CSS класс ошибки
- */
- function hasError(string $field): string
- {
- // Новая валидация
- if (session()->has('errors')) {
- /** @var ViewErrorBag $errors */
- $errors = session()->get('errors');
-
- return $errors->has($field) ? ' is-invalid' : ' is-valid';
- }
-
- $isValid = session()->has('flash.danger') ? ' is-valid' : '';
-
- return session()->has('flash.danger.' . $field) ? ' is-invalid' : $isValid;
- }
-
- /**
- * Возвращает блок с текстом ошибки
- *
- * @param string $field Имя поля
- *
- * @return string|null Блоки ошибки
- */
- function textError(string $field): ?string
- {
- // Новая валидация
- if (session()->has('errors')) {
- /** @var ViewErrorBag $errors */
- $errors = session()->get('errors');
-
- return $errors->first($field);
- }
-
- return session()->get('flash.danger.' . $field);
- }
-
- /**
- * Отправляет уведомления на email
- *
- * @param string $view
- * @param array $data
- *
- * @return bool Результат отправки
- */
- function sendMail(string $view, array $data): bool
- {
- Mail::send($view, $data, function (Message $message) use ($data) {
- $message->subject($data['subject'])
- ->to($data['to'])
- ->from(config('mail.from.address'), config('mail.from.name'));
-
- if (isset($data['from'])) {
- [$fromEmail, $fromName] = $data['from'];
- $message->replyTo($fromEmail, $fromName);
- }
-
- if (isset($data['unsubscribe'])) {
- $headers = $message->getHeaders();
- $headers->addTextHeader('List-Unsubscribe', '<' . config('app.url') . '/unsubscribe?key=' . $data['unsubscribe'] . '>');
- }
- });
-
- return ! Mail::failures();
- }
-
- /**
- * Возвращает расширение файла
- *
- * @param string $filename Имя файла
- *
- * @return string расширение
- */
- function getExtension(string $filename): string
- {
- return pathinfo($filename, PATHINFO_EXTENSION);
- }
-
- /**
- * Возвращает имя файла без расширения
- *
- * @param string $filename Имя файла
- *
- * @return string Имя без расширения
- */
- function getBodyName(string $filename): string
- {
- return pathinfo($filename, PATHINFO_FILENAME);
- }
-
- /**
- * Склоняет числа
- *
- * @param int $num Число
- * @param mixed $forms Массив склоняемых слов (один, два, много)
- *
- * @return string Форматированная строка
- */
- function plural(int $num, $forms): string
- {
- if (! is_array($forms)) {
- $forms = explode(',', $forms);
- }
-
- if (count($forms) === 1) {
- return $num . ' ' . $forms[0];
- }
-
- if ($num % 100 > 10 && $num % 100 < 15) {
- return $num . ' ' . $forms[2];
- }
-
- if ($num % 10 === 1) {
- return $num . ' ' . $forms[0];
- }
-
- if ($num % 10 > 1 && $num % 10 < 5) {
- return $num . ' ' . $forms[1];
- }
-
- return $num . ' ' . $forms[2];
- }
-
- /**
- * Обрабатывает BB-код
- *
- * @param string $text Необработанный текст
- * @param bool $parse Обрабатывать или вырезать код
- *
- * @return HtmlString Обработанный текст
- */
- function bbCode(string $text, bool $parse = true): HtmlString
- {
- $bbCode = new BBCode();
- $checkText = check($text);
-
- if (! $parse) {
- return new HtmlString($bbCode->clear($checkText));
- }
-
- $parseText = $bbCode->parse($checkText);
- $parseText = $bbCode->parseStickers($parseText);
-
- return new HtmlString($parseText);
- }
-
- /**
- * Определяет IP пользователя
- *
- * @return string IP пользователя
- */
- function getIp(): string
- {
- $cf = new CloudFlare(request());
-
- return $cf->ip();
- }
-
- /**
- * Определяет браузер
- *
- * @param string|null $userAgent
- *
- * @return string|null Браузер и версия браузера
- */
- function getBrowser(string $userAgent = null): string
- {
- $browser = new Browser();
- if ($userAgent) {
- $browser->setUserAgent($userAgent);
- }
-
- $brow = $browser->getBrowser();
- $version = implode('.', array_slice(explode('.', $browser->getVersion()), 0, 2));
-
- $browser = $version === Browser::VERSION_UNKNOWN ? $brow : $brow . ' ' . $version;
-
- return mb_substr($browser, 0, 25, 'utf-8');
- }
-
- /**
- * Является ли пользователь авторизованным
- *
- * @return User|bool
- */
- function checkAuth()
- {
- if (session()->has(['id', 'password'])) {
- $user = getUserById(session()->get('id'));
-
- if ($user && session()->get('password') === $user->password) {
- return $user;
- }
- }
-
- return false;
- }
-
- /**
- * Является ли пользователь администратором
- *
- * @param string|null $level Уровень доступа
- *
- * @return bool Является ли пользователь администратором
- */
- function isAdmin(?string $level = null): bool
- {
- return access($level ?? User::EDITOR);
- }
-
- /**
- * Имеет ли пользователь доступ по уровню
- *
- * @param string $level Уровень доступа
- *
- * @return bool Разрешен ли доступ
- */
- function access(string $level): bool
- {
- $access = array_flip(User::ALL_GROUPS);
-
- return getUser()
- && isset($access[$level], $access[getUser('level')])
- && $access[getUser('level')] <= $access[$level];
- }
-
- /**
- * Возвращает объект пользователя по логину
- *
- * @param string|null $login Логин пользователя
- *
- * @return Builder|Model|null
- */
- function getUserByLogin(?string $login): ?User
- {
- return User::query()->where('login', $login)->first();
- }
-
- /**
- * Возвращает объект пользователя по id
- *
- * @param int|null $id ID пользователя
- *
- * @return Builder|Model|null
- */
- function getUserById(?int $id): ?User
- {
- return User::query()->find($id);
- }
-
- /**
- * Возвращает объект пользователя по токену
- *
- * @param string $token Логин пользователя
- *
- * @return Builder|Model|null
- */
- function getUserByToken(string $token): ?User
- {
- return User::query()->where('apikey', $token)->first();
- }
-
- /**
- * Возвращает объект пользователя по логину или email
- *
- * @param string|null $login Логин или email пользователя
- *
- * @return Builder|Model|null
- */
- function getUserByLoginOrEmail(?string $login): ?User
- {
- $field = strpos($login, '@') ? 'email' : 'login';
-
- return User::query()->where($field, $login)->first();
- }
-
- /**
- * Возвращает данные пользователя по ключу
- *
- * @param string|null $key Ключ массива
- *
- * @return User|mixed
- */
- function getUser(?string $key = null)
- {
- static $user;
-
- if (! $user) {
- $user = checkAuth();
- }
-
- return $key ? ($user[$key] ?? null) : $user;
- }
-
- /**
- * Разбивает массив по страницам
- *
- * @param array $items
- * @param int $perPage
- * @param array $appends
- *
- * @return LengthAwarePaginator
- */
- function paginate(array $items, int $perPage, array $appends = []): LengthAwarePaginator
- {
- $currentPage = LengthAwarePaginator::resolveCurrentPage();
- $slice = array_slice($items, $perPage * ($currentPage - 1), $perPage, true);
-
- $collection = new LengthAwarePaginator($slice, count($items), $perPage);
- $collection->setPath(request()->url());
- $collection->appends($appends);
-
- return $collection;
- }
-
- /**
- * Возвращает сформированный код base64 картинки
- *
- * @param string $path Путь к картинке
- * @param array $params Параметры
- *
- * @return HtmlString Сформированный код
- */
- function imageBase64(string $path, array $params = []): HtmlString
- {
- $type = getExtension($path);
- $data = file_get_contents($path);
-
- if (! isset($params['class'])) {
- $params['class'] = 'img-fluid';
- }
-
- if (empty($params['alt'])) {
- $params['alt'] = basename($path);
- }
-
- $strParams = [];
- foreach ($params as $key => $param) {
- $strParams[] = $key . '="' . $param . '"';
- }
-
- $strParams = implode(' ', $strParams);
-
- return new HtmlString('<img src="data:image/' . $type . ';base64,' . base64_encode($data) . '"' . $strParams . '>');
- }
-
- /**
- * Выводит прогресс-бар
- *
- * @param int $percent
- * @param int|float|string|null $title
- *
- * @return HtmlString
- */
- function progressBar(int $percent, $title = null): HtmlString
- {
- if (! $title) {
- $title = $percent . '%';
- }
-
- return new HtmlString(view('app/_progressbar', compact('percent', 'title')));
- }
-
- /**
- * Возвращает форматированный список запросов
- *
- * @return array
- */
- function getQueryLog(): array
- {
- $queries = DB::getQueryLog();
-
- $formattedQueries = [];
-
- foreach ($queries as $query) {
- foreach ($query['bindings'] as $key => $binding) {
- if (is_string($binding)) {
- $query['bindings'][$key] = ctype_print($binding) ? "'$binding'" : '[binary]';
- }
-
- $query['bindings'][$key] = $binding ?? 'null';
- }
-
- $sql = str_replace(['%', '?'], ['%%', '%s'], $query['query']);
- $sql = vsprintf($sql, $query['bindings']);
-
- $formattedQueries[] = ['query' => $sql, 'time' => $query['time']];
- }
-
- return $formattedQueries;
- }
-
- /**
- * Выводит список забаненных ip
- *
- * @param bool $clear Нужно ли сбросить кеш
- *
- * @return array Массив IP
- */
- function ipBan(bool $clear = false): array
- {
- if ($clear) {
- clearCache('ipBan');
- }
-
- return Cache::rememberForever('ipBan', static function () {
- return Ban::query()->get()->pluck('id', 'ip')->all();
- });
- }
-
- /**
- * Возвращает настройки сайта по ключу
- *
- * @param string|null $key Ключ массива
- * @param mixed $default Значение по умолчанию
- *
- * @return mixed Данные
- */
- function setting(?string $key = null, $default = null)
- {
- static $settings;
-
- if (! $settings) {
- $settings = Setting::getSettings();
- }
-
- return $key ? ($settings[$key] ?? $default) : $settings;
- }
-
- /**
- * Возвращает имя сайта из ссылки
- *
- * @param string $url Ссылка на сайт
- *
- * @return string Имя сайта
- */
- function siteDomain(string $url): string
- {
- return parse_url(strtolower($url), PHP_URL_HOST);
- }
-
- /**
- * Получает версию
- *
- * @param string $version
- *
- * @return string
- */
- function parseVersion(string $version): string
- {
- $ver = explode('.', strtok($version, '-'));
-
- return $ver[0] . '.' . $ver[1] . '.' . ($ver[2] ?? 0);
- }
-
- /**
- * Проверяет captcha
- *
- * @return bool
- */
- function captchaVerify(): bool
- {
- $request = request();
-
- if (setting('captcha_type') === 'recaptcha_v2') {
- $recaptcha = new ReCaptcha(setting('recaptcha_private'));
-
- $response = $recaptcha->setExpectedHostname($_SERVER['SERVER_NAME'])
- ->verify($request->input('g-recaptcha-response'), getIp());
-
- return $response->isSuccess();
- }
-
- if (setting('captcha_type') === 'recaptcha_v3') {
- $recaptcha = new ReCaptcha(setting('recaptcha_private'));
-
- $response = $recaptcha->setExpectedHostname($_SERVER['SERVER_NAME'])
- ->setScoreThreshold(0.5)
- ->verify($request->input('protect'), getIp());
-
- return $response->isSuccess();
- }
-
- if (setting('captcha_type') === 'graphical') {
- return strtolower($request->input('protect')) === $request->session()->get('protect');
- }
-
- return false;
- }
-
- /**
- * Возвращает уникальное имя
- *
- * @param string|null $extension
- *
- * @return string
- */
- function uniqueName(string $extension = null): string
- {
- if ($extension) {
- $extension = '.' . $extension;
- }
-
- return str_replace('.', '', uniqid('', true)) . $extension;
- }
-
- /**
- * Возвращает курсы валют
- *
- * @return HtmlString
- */
- function getCourses(): ?HtmlString
- {
- $courses = Cache::remember('courses', 3600, static function () {
- try {
- $client = new Client(['timeout' => 3.0]);
- $response = $client->get('//www.cbr-xml-daily.ru/daily_json.js');
-
- $content = json_decode($response->getBody()->getContents(), true);
- } catch (Exception $e) {
- $content = null;
- }
-
- return $content;
- });
-
- return new HtmlString(view('app/_courses', compact('courses')));
- }