<?php
class App
{
/**
* Возвращает текущую страницу
* @param null $url
* @return string текущая страница
*/
public static function returnUrl($url = null)
{
if (Request::is('/', 'login', 'register', 'lostpassword', 'ban', 'closed')) {
return false;
}
$query = Request::has('return') ? Request::input('return') : Request::path();
return '?return='.urlencode(is_null($url) ? $query : $url);
}
/**
* Возвращает подключенный шаблон
* @param $template
* @param array $params массив параметров
* @param boolean $return выводить или возвращать код
* @return string сформированный код
* @internal param string $view имя шаблона
*/
public static function view($template, $params = [], $return = false)
{
$log = static::user('login');
$config = self::setting();
$params +=compact('config', 'log');
$blade = new Jenssegers\Blade\Blade([APP.'/views', HOME.'/themes'], STORAGE.'/cache');
if ($return) {
return $blade->render($template, $params);
} else {
echo $blade->render($template, $params);
}
}
/**
* Сохраняет страницы с ошибками
* @param integer $code код ошибки
* @param string $message текст ошибки
* @return string сформированная страница с ошибкой
*/
public static function abort($code, $message = null)
{
if ($code == 403) {
header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
}
if ($code == 404) {
header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
}
if (App::setting('errorlog') && in_array($code, [403, 404])) {
DBM::run()->insert('error', [
'num' => $code,
'request' => utf_substr(App::server('REQUEST_URI'), 0, 200),
'referer' => utf_substr(App::server('HTTP_REFERER'), 0, 200),
'username' => App::getUsername(),
'ip' => App::getClientIp(),
'brow' => App::getUserAgent(),
'time' => SITETIME,
]);
DBM::run()->delete('error', [
'num' => $code,
'time' => ['<', SITETIME - 3600 * 24 * App::setting('maxlogdat')]]
);
}
exit(self::view('errors.'.$code, compact('message')));
}
/**
* Переадресовывает пользователя
* @param string $url адрес переадресации
* @param boolean $permanent постоянное перенаправление
*/
public static function redirect($url, $permanent = false)
{
if (isset($_SESSION['captcha'])) $_SESSION['captcha'] = null;
if ($permanent){
header($_SERVER['SERVER_PROTOCOL'].' 301 Moved Permanently');
}
exit(header('Location: '.$url));
}
/**
* Сохраняет flash уведомления
* @param string $status статус уведомления
* @param mixed $message массив или текст с уведомлениями
*/
public static function setFlash($status, $message)
{
$_SESSION['flash'][$status] = $message;
}
/**
* Возвращает flash уведомления
* @return string сформированный блок с уведомлениями
* @internal param array $errors массив уведомлений
*/
public static function getFlash()
{
self::view('app/_flash');
}
/**
* Сохраняет POST данные введенных пользователем
* @param array $data массив полей
*/
public static function setInput(array $data)
{
$prepareData = [];
foreach($data as $key => $value) {
if (is_object($value)) {
continue;
}
$prepareData[$key] = $value;
}
$_SESSION['input'] = $prepareData;
}
/**
* Возвращает значение из POST данных
* @param string $name имя поля
* @param string $default
* @return string сохраненный текст
*/
public static function getInput($name, $default = '')
{
return isset($_SESSION['input'][$name]) ? $_SESSION['input'][$name] : $default;
}
/**
* Подсвечивает блок с полем для ввода сообщения
* @param string $field имя поля
* @return string CSS класс ошибки
*/
public static function hasError($field)
{
return isset($_SESSION['flash']['danger'][$field]) ? ' has-error' : '';
}
/**
* Возвращает блок с текстом ошибки
* @param string $field имя поля
* @return string блоки ошибки
*/
public static function textError($field)
{
if (isset($_SESSION['flash']['danger'][$field])) {
$error = $_SESSION['flash']['danger'][$field];
return '<div class="text-danger">'.$error.'</div>';
}
}
/**
* Проверяет является ли email валидным
* @param string $email адрес email
* @return boolean результат проверки
*/
public static function isMail($email)
{
return preg_match('#^([a-z0-9_\-\.])+\@([a-z0-9_\-\.])+(\.([a-z0-9])+)+$#', $email);
}
/**
* Отправка уведомления на email
* @param mixed $to Получатель
* @param string $subject Тема письма
* @param string $body Текст сообщения
* @param array $headers Дополнительные параметры
* @return boolean Результат отправки
*/
/* public static function sendMail($to, $subject, $body, $headers = [])
{
if (empty($headers['from'])) $headers['from'] = [env('SITE_EMAIL') => env('SITE_ADMIN')];
$message = Swift_Message::newInstance()
->setTo($to)
->setSubject($subject)
->setBody($body, 'text/html')
->setFrom($headers['from'])
->setReturnPath(env('SITE_EMAIL'));
if (env('MAIL_DRIVER') == 'smtp') {
$transport = Swift_SmtpTransport::newInstance(env('MAIL_HOST'), env('MAIL_PORT'), 'ssl')
->setUsername(env('MAIL_USERNAME'))
->setPassword(env('MAIL_PASSWORD'));
} else {
$transport = new Swift_MailTransport();
}
$mailer = new Swift_Mailer($transport);
return $mailer->send($message);
}*/
/**
* Возвращает форматированную дату
* @param string $format отформатированная дата
* @param mixed $date временная метки или дата
* @return string отформатированная дата
*/
public static function date($format, $date = null)
{
$date = (is_null($date)) ? time() : strtotime($date);
$eng = ['January','February','March','April','May','June','July','August','September','October','November','December'];
$rus = ['января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'];
return str_replace($eng, $rus, date($format, $date));
}
/**
* Возвращает расширение файла
* @param string $filename имя файла
* @return string расширение
*/
public static function getExtension($filename)
{
return pathinfo($filename, PATHINFO_EXTENSION);
}
/**
* Возвращает размер файла
* @param string $filename путь к файлу
* @param integer $decimals кол. чисел после запятой
* @return string форматированный вывод размера
*/
public static function filesize($filename, $decimals = 1)
{
if (!file_exists($filename)) return 0;
$bytes = filesize($filename);
$size = ['B','kB','MB','GB','TB'];
$factor = floor((strlen($bytes) - 1) / 3);
$unit = isset($size[$factor]) ? $size[$factor] : '';
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)).$unit;
}
/**
* Склоняет числа
* @param integer $num число
* @param array $forms массив склоняемых слов (один, два, много)
* @return string форматированная строка
*/
public static function plural($num, array $forms)
{
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];
}
/**
* Валидирует даты
* @param string $date дата
* @param string $format формат даты
* @return boolean результат валидации
*/
public static function validateDate($date, $format = 'Y-m-d H:i:s')
{
$d = DateTime::createFromFormat($format, $date);
return $d && $d->format($format) == $date;
}
/**
* Обрабатывает BB-код
* @param string $text Необработанный текст
* @param boolean $parse Обрабатывать или вырезать код
* @return string Обработанный текст
*/
public static function bbCode($text, $parse = true)
{
$bbcode = new BBCodeParser(self::setting());
if ( ! $parse) return $bbcode->clear($text);
$text = $bbcode->parse($text);
$text = $bbcode->parseSmiles($text);
return $text;
}
/**
* Определяет браузер
* @param string|null $userAgent
* @return string браузер и версия браузера
*/
public static function getUserAgent($userAgent = null)
{
$browser = new Browser();
if ($userAgent) {
$browser->setUserAgent($userAgent);
}
$brow = $browser->getBrowser();
$version = implode('.', array_slice(explode('.', $browser->getVersion()), 0, 2));
return mb_substr($version == 'unknown' ? $brow : $brow.' '.$version, 0, 25, 'utf-8');
}
/**
* Определяет IP пользователя
* @return string IP пользователя
*/
public static function getClientIp()
{
$ip = Request::ip();
return $ip == '::1' ? '127.0.0.1' : $ip;
}
/**
* Возвращает серверные переменные
* @param string|null $key ключ массива
* @param string|null $default значение по умолчанию
* @return mixed данные
*/
public static function server($key = null, $default = null)
{
$server = Request::server($key, $default);
if ($key == 'REQUEST_URI') $server = urldecode($server);
if ($key == 'PHP_SELF') $server = current(explode('?', static::server('REQUEST_URI')));
return check($server);
}
public static function getUsername()
{
return isset($_SESSION['login']) ? check($_SESSION['login']) : self::setting('guestsuser');
}
/**
* Возвращает данные пользователя по ключу
* @param string $key ключ массива
* @return string данные
*/
public static function user($key = null)
{
if (Registry::has('user')) {
if (empty($key)) return Registry::get('user');
return isset(Registry::get('user')[$key]) ? Registry::get('user')[$key] : '';
}
}
/**
* Возвращает настройки сайта по ключу
* @param string $key ключ массива
* @return string данные
*/
public static function setting($key = null)
{
if (Registry::has('config')) {
if (empty($key)) return Registry::get('config');
return isset(Registry::get('config')[$key]) ? Registry::get('config')[$key] : '';
}
}
/**
* Авторизует пользователя
* @param string $login Логин или никнэйм
* @param string $password Пароль пользователя
* @param boolean $remember Запомнить пароль
* @return boolean Результат авторизации
*/
public static function login($login, $password, $remember = true)
{
$domain = check_string(self::setting('home'));
if (!empty($login) && !empty($password)) {
$user = DB::run()->queryFetch("SELECT `login`, `password` FROM `users` WHERE LOWER(`login`)=? OR LOWER(`nickname`)=? LIMIT 1;", [$login, $login]);
/* Миграция старых паролей */
if (preg_match('/^[a-f0-9]{32}$/', $user['password']))
{
if (md5(md5($password)) == $user['password']) {
$user['password'] = password_hash($password, PASSWORD_BCRYPT);
DBM::run()->update('users', [
'password' => $user['password'],
], ['login' => $user['login']]);
}
}
if ($user && password_verify($password, $user['password'])) {
if ($remember) {
setcookie('login', $user['login'], time() + 3600 * 24 * 365, '/', $domain);
setcookie('password', md5($user['password'].env('APP_KEY')), time() + 3600 * 24 * 365, '/', $domain, null, true);
}
$_SESSION['ip'] = self::getClientIp();
$_SESSION['login'] = $user['login'];
$_SESSION['password'] = md5(env('APP_KEY').$user['password']);
// Сохранение привязки к соц. сетям
if (!empty($_SESSION['social'])) {
DBM::run()->insert('socials', [
'user' => $user['login'],
'network' => $_SESSION['social']->network,
'uid' => $_SESSION['social']->uid,
]);
}
DB::run()->query("UPDATE `users` SET `visits`=`visits`+1, `timelastlogin`=? WHERE `login`=?", [SITETIME, $user['login']]);
$authorization = DB::run()->querySingle("SELECT `id` FROM `login` WHERE `user`=? AND `time`>? LIMIT 1;", [$user['login'], SITETIME - 30]);
if (empty($authorization)) {
DB::run()->query("INSERT INTO `login` (`user`, `ip`, `brow`, `time`, `type`) VALUES (?, ?, ?, ?, ?);", [$user['login'], self::getClientIp(), self::getUserAgent(), SITETIME, 1]);
DB::run()->query("DELETE FROM `login` WHERE `user`=? AND `time` < (SELECT MIN(`time`) FROM (SELECT `time` FROM `login` WHERE `user`=? ORDER BY `time` DESC LIMIT 50) AS del);", [$user['login'], $user['login']]);
}
return $user;
}
}
return false;
}
/**
* Авторизует через социальные сети
* @param string $token идентификатор Ulogin
*/
public static function socialLogin($token)
{
$domain = check_string(self::setting('home'));
$curl = new Curl\Curl();
$network = $curl->get('http://ulogin.ru/token.php', [
'token' => $token,
'host' => $_SERVER['HTTP_HOST']
]);
if ($network && empty($network->error)) {
$_SESSION['social'] = $network;
$social = DBM::run()->selectFirst('socials', ['network' => $network->network, 'uid' => $network->uid]);
if ($social && $user = user($social['user'])) {
setcookie('login', $user['login'], time() + 3600 * 24 * 365, '/', $domain);
setcookie('password', md5($user['password'].env('APP_KEY')), time() + 3600 * 24 * 365, '/', $domain, null, true);
$_SESSION['login'] = $user['login'];
$_SESSION['password'] = md5(env('APP_KEY').$user['password']);
$_SESSION['ip'] = App::getClientIp();
self::setFlash('success', 'Добро пожаловать, '.$user['login'].'!');
self::redirect('/');
}
}
}
/**
* Генерирует постраничную навигация
* @param array $page массив данных
* @return string сформированный блок
*/
public static function pagination($page)
{
if ($page['total'] > 0) {
if (empty($page['crumbs'])) $page['crumbs'] = 3;
$url = array_except($_GET, 'page');
$request = $url ? '&'.http_build_query($url) : null;
$pages = [];
$pg_cnt = ceil($page['total'] / $page['limit']);
$idx_fst = max($page['current'] - $page['crumbs'], 1);
$idx_lst = min($page['current'] + $page['crumbs'], $pg_cnt);
if ($page['current'] != 1) {
$pages[] = [
'page' => $page['current'] - 1,
'title' => 'Предыдущая',
'name' => '«',
];
}
if ($page['current'] > $page['crumbs'] + 1) {
$pages[] = [
'page' => 1,
'title' => '1 страница',
'name' => 1,
];
if ($page['current'] != $page['crumbs'] + 2) {
$pages[] = [
'separator' => true,
'name' => ' ... ',
];
}
}
for ($i = $idx_fst; $i <= $idx_lst; $i++) {
if ($i == $page['current']) {
$pages[] = [
'current' => true,
'name' => $i,
];
} else {
$pages[] = [
'page' => $i,
'title' => $i.' страница',
'name' => $i,
];
}
}
if ($page['current'] < $pg_cnt - $page['crumbs']) {
if ($page['current'] != $pg_cnt - $page['crumbs'] - 1) {
$pages[] = [
'separator' => true,
'name' => ' ... ',
];
}
$pages[] = [
'page' => $pg_cnt,
'title' => $pg_cnt . ' страница',
'name' => $pg_cnt,
];
}
if ($page['current'] != $pg_cnt) {
$pages[] = [
'page' => $page['current'] + 1,
'title' => 'Следующая',
'name' => '»',
];
}
self::view('app._pagination', compact('pages', 'request'));
}
}
/**
* Генерирует постраничную навигация для форума
* @param array $topic массив данных
* @return string сформированный блок
*/
public static function forumPagination($topic) {
if ($topic['posts']) {
$pages = [];
$link = '/topic/'.$topic['id'];
$pg_cnt = ceil($topic['posts'] / App::setting('forumpost'));
for ($i = 1; $i <= 5; $i++) {
if ($i <= $pg_cnt) {
$pages[] = [
'page' => $i,
'title' => $i.' страница',
'name' => $i,
];
}
}
if (5 < $pg_cnt) {
if (6 < $pg_cnt) {
$pages[] = array(
'separator' => true,
'name' => ' ... ',
);
}
$pages[] = array(
'page' => $pg_cnt,
'title' => $pg_cnt.' страница',
'name' => $pg_cnt,
);
}
self::view('forum._pagination', compact('pages', 'link'));
}
}
/**
* Обрабатывает постраничную навигацию
* @param integer $limit элементов на страницу
* @param integer $total всего элементов
* @return array массив подготовленных данных
*/
public static function paginate($limit, $total)
{
$current = Request::input('page');
if ($current < 1) $current = 1;
if ($total && $current * $limit >= $total) {
$current = ceil($total / $limit);
}
$offset = intval(($current * $limit) - $limit);
return compact('current', 'offset', 'limit', 'total');
}
/**
* Устанавливает права доступа на папки
* @return void
*/
public static function install()
{
$storage = glob(dirname(__DIR__).'/storage/*', GLOB_ONLYDIR);
$uploads = glob(dirname(dirname(__DIR__)).'/public/uploads/*', GLOB_ONLYDIR);
$dirs = array_merge($storage, $uploads);
foreach ($dirs as $dir) {
$old = umask(0);
chmod ($dir, 0777);
umask($old);
}
}
/**
* Возвращает сформированный код base64 картинки
* @param string $path путь к картинке
* @param array $params параметры
* @return string сформированный код
*/
public static function imageBase64($path, array $params = [])
{
$type = pathinfo($path, PATHINFO_EXTENSION);
$data = file_get_contents($path);
if (! isset($params['class'])) {
$params['class'] = 'img-responsive';
}
$strParams = [];
foreach ($params as $key => $param) {
$strParams[] = $key.'="'.$param.'"';
}
$strParams = implode(' ', $strParams);
return '<img src="data:image/'.$type.';base64,'.base64_encode($data).'"'.$strParams.'>';
}
}