2017-11-03

This commit is contained in:
Visman 2017-11-03 20:06:22 +07:00
parent e3abb67d67
commit 37f80f6fb8
104 changed files with 3370 additions and 2670 deletions

View file

@ -15,6 +15,7 @@ class Install
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
@ -24,6 +25,7 @@ class Install
/**
* Маршрутиризация
*
* @return Page
*/
public function routing()
@ -38,7 +40,7 @@ class Install
. preg_replace('%:(80|443)$%', '', $_SERVER['HTTP_HOST'])
. substr($uri, 0, (int) strrpos($uri, '/'));
$this->c->Lang->load('common', $this->c->config['o_default_lang']);
$this->c->Lang->load('common', $this->c->config->o_default_lang);
$this->c->user = new User(['id' => 2, 'group_id' => $this->c->GROUP_ADMIN], $this->c);
$r = $this->c->Router;
@ -54,7 +56,7 @@ class Install
$page = $this->c->$page->$action($route[2]);
break;
default:
$page = $this->c->Redirect->setPage('Install')->setMessage('Redirect to install');
$page = $this->c->Redirect->page('Install')->message('Redirect to install');
break;
}
return $page;

View file

@ -14,6 +14,7 @@ class Primary
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
@ -25,28 +26,27 @@ class Primary
* Проверка на обслуживание
* Проверка на обновление
* Проверка на бан
*
* @return Page|null
*/
public function check()
{
if ($this->c->config['o_maintenance'] && ! $this->c->MAINTENANCE_OFF) {
if (! in_array($this->c->UserCookie->id(), $this->c->admins)
|| ! in_array($this->c->user->id, $this->c->admins)
) {
return $this->c->Maintenance;
}
if ($this->c->config->o_maintenance && ! $this->c->MAINTENANCE_OFF) {
if (! in_array($this->c->Cookie->uId, $this->c->admins->list) //????
|| ! in_array($this->c->user->id, $this->c->admins->list) //????
) {
return $this->c->Maintenance;
}
}
if (empty($this->c->config['i_fork_revision'])
|| $this->c->config['i_fork_revision'] < $this->c->FORK_REVISION
if ($this->c->config->i_fork_revision < $this->c->FORK_REVISION
) {
header('Location: db_update.php'); //????
exit;
}
$ban = $this->c->CheckBans->check();
if (is_array($ban)) {
return $this->c->Ban->ban($ban);
if (! $this->c->user->isAdmin && $this->c->bans->check($this->c->user)) {
return $this->c->Ban->ban($this->c->user);
}
}
}

View file

@ -14,6 +14,7 @@ class Routing
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
@ -23,6 +24,7 @@ class Routing
/**
* Маршрутиризация
*
* @return Page
*/
public function routing()
@ -44,7 +46,7 @@ class Routing
$r->add('POST', '/login/{email}/{key}/{hash}', 'Auth:changePassPost');
// регистрация
if ($config['o_regs_allow'] == '1') {
if ($config->o_regs_allow == '1') {
$r->add('GET', '/registration', 'Rules:confirmation', 'Register');
$r->add('POST', '/registration/agree', 'Register:reg', 'RegisterForm');
$r->add('GET', '/registration/activate/{id:\d+}/{key}/{hash}', 'Register:activate', 'RegActivate');
@ -58,19 +60,19 @@ class Routing
$r->add('GET', '/registration[/{tail:.*}]', 'Redirect:toIndex');
}
// просмотр разрешен
if ($user->gReadBoard == '1') {
if ($user->g_read_board == '1') {
// главная
$r->add('GET', '/', 'Index:view', 'Index');
// правила
if ($config['o_rules'] == '1' && (! $user->isGuest || $config['o_regs_allow'] == '1')) {
if ($config->o_rules == '1' && (! $user->isGuest || $config->o_regs_allow == '1')) {
$r->add('GET', '/rules', 'Rules:view', 'Rules');
}
// поиск
if ($user->gSearch == '1') {
if ($user->g_search == '1') {
$r->add('GET', '/search', 'Search:view', 'Search');
}
// юзеры
if ($user->gViewUsers == '1') {
if ($user->g_view_users == '1') {
// список пользователей
$r->add('GET', '/userlist[/{page:[1-9]\d*}]', 'Userlist:view', 'Userlist');
// юзеры
@ -127,8 +129,8 @@ class Routing
break;
case $r::NOT_FOUND:
// ... 404 Not Found
if ($user->gReadBoard != '1' && $user->isGuest) {
$page = $this->c->Redirect->setPage('Login');
if ($user->g_read_board != '1' && $user->isGuest) {
$page = $this->c->Redirect->page('Login');
} else {
$page = $this->c->Message->message('Bad request');
}

View file

@ -1,120 +0,0 @@
<?php
namespace ForkBB\Core;
abstract class AbstractModel
{
/**
* Данные модели
* @var array
*/
protected $data;
abstract protected function beforeConstruct(array $data);
/**
* Конструктор
* @param array $data
*/
public function __construct(array $data = [])
{
$data = $this->beforeConstruct($data);
foreach ($data as $key => $val) {
if (is_string($key)) {
$this->data[$this->camelCase($key)] = $val;
}
}
}
/**
* Проверяет наличие свойства
* @param mixed $key
* @return bool
*/
public function __isset($key)
{
return is_string($key) && isset($this->data[$key]);
}
/**
* Удаляет свойство
* @param mixed $key
*/
public function __unset($key)
{
if (is_string($key)) {
unset($this->data[$key]);
}
}
/**
* Устанавливает значение для свойства
* При $key = __attrs ожидаем массив в $val
* @param mixed $key
* @param mixed $vak
*/
public function __set($key, $val)
{
if ('__attrs' === $key) {
if (is_array($val)) {
foreach ($val as $x => $y) {
$x = $this->camelCase($x);
$this->$x = $y;
}
}
} elseif (is_string($key)) {
$method = 'set' . ucfirst($key);
if (method_exists($this, $method)) {
$this->$method($val);
} else {
$this->data[$key] = $val;
}
}
}
/**
* Возвращает значение свойства
* При $key = __attrs возвращает все свойства
* @param mixed $key
* @return mixed
*/
public function __get($key)
{
if ('__attrs' === $key) {
$data = [];
foreach ($this->data as $x => $y) {
$data[$this->underScore($x)] = $y; //????
}
return $data;
} elseif (is_string($key)) {
$method = 'get' . ucfirst($key);
if (method_exists($this, $method)) {
return $this->$method();
} else {
return isset($this->data[$key]) ? $this->data[$key] : null;
}
}
}
/**
* Преобразует строку в camelCase
* @param string $str
* @return string
*/
protected function camelCase($str)
{
return lcfirst(str_replace('_', '', ucwords($str, '_')));
}
/**
* Преобразует строку в under_score
* @param string $str
* @return string
*/
protected function underScore($str)
{
return preg_replace('%([A-Z])%', function($match) {
return '_' . strtolower($match[1]);
}, $str);
}
}

View file

@ -18,8 +18,8 @@ class FileCache implements ProviderCacheInterface
*
* @param string $dir
*
* @throws \InvalidArgumentException
* @throws \RuntimeException
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function __construct($dir)
{
@ -63,7 +63,8 @@ class FileCache implements ProviderCacheInterface
* @param mixed $value
* @param int $ttl
*
* @throws \RuntimeException
* @throws RuntimeException
*
* @return bool
*/
public function set($key, $value, $ttl = null)
@ -84,7 +85,8 @@ class FileCache implements ProviderCacheInterface
*
* @param string $key
*
* @throws \RuntimeException
* @throws RuntimeException
*
* @return bool
*/
public function delete($key)
@ -141,7 +143,8 @@ class FileCache implements ProviderCacheInterface
*
* @param string $key
*
* @throws \InvalidArgumentException
* @throws InvalidArgumentException
*
* @return string
*/
protected function file($key)

View file

@ -18,6 +18,7 @@ class Container
/**
* Конструктор
*
* @param array config
*/
public function __construct(array $config = null)
@ -37,6 +38,7 @@ class Container
/**
* Adding config
*
* @param array config
*/
public function config(array $config)
@ -53,9 +55,12 @@ class Container
/**
* Gets a service or parameter.
*
* @param string $id
*
* @throws InvalidArgumentException
*
* @return mixed
* @throws \InvalidArgumentException
*/
public function __get($id)
{
@ -79,7 +84,7 @@ class Container
$toShare = false;
$config = (array) $this->multiple[$id];
} else {
throw new InvalidArgumentException('Wrong property name '.$id);
throw new InvalidArgumentException('Wrong property name: ' . $id);
}
// N.B. "class" is just the first element, regardless of its key
$class = array_shift($config);
@ -107,6 +112,7 @@ class Container
/**
* Sets a service or parameter.
* Provides a fluent interface.
*
* @param string $id
* @param mixed $service
*/
@ -121,8 +127,10 @@ class Container
/**
* Gets data from array.
*
* @param array $array
* @param array $tree
*
* @return mixed
*/
public function fromArray(array $array, array $tree)
@ -145,21 +153,23 @@ class Container
* @param string $name The parameter name
* @param mixed $value The parameter value
*
* @throws InvalidArgumentException
*
* @return ContainerInterface Self reference
*/
public function setParameter($name, $value)
{
$segments = explode('.', $name);
$n = count($segments);
$ptr =& $this->config;
$ptr = &$this->config;
foreach ($segments as $s) {
if (--$n) {
if (!array_key_exists($s, $ptr)) {
if (! array_key_exists($s, $ptr)) {
$ptr[$s] = [];
} elseif (!is_array($ptr[$s])) {
throw new \InvalidArgumentException("Scalar \"{$s}\" in the path \"{$name}\"");
} elseif (! is_array($ptr[$s])) {
throw new InvalidArgumentException("Scalar '{$s}' in the path '{$name}'");
}
$ptr =& $ptr[$s];
$ptr = &$ptr[$s];
} else {
$ptr[$s] = $value;
}

View file

@ -1,118 +0,0 @@
<?php
namespace ForkBB\Core;
use ForkBB\Core\Secury;
class Cookie
{
/**
* @var Secury
*/
protected $secury;
/**
* Префикс для наименований
* @var string
*/
protected $prefix;
/**
* Домен
* @var string
*/
protected $domain;
/**
* Путь
* @var string
*/
protected $path;
/**
* Флаг передачи кук по защищенному соединению
* @var bool
*/
protected $secure;
/**
* Конструктор
*
* @param Secury $secury
* @param array $options
*/
public function __construct(Secury $secury, array $options)
{
$this->secury = $secury;
$options += [
'prefix' => '',
'domain' => '',
'path' => '',
'secure' => false,
];
$this->prefix = (string) $options['prefix'];
$this->domain = (string) $options['domain'];
$this->path = (string) $options['path'];
$this->secure = (bool) $options['secure'];
}
/**
* Устанавливает куку
*
* @param string $name
* @param string $value
* @param int $expire
* @param string $path
* @param string $domain
* @param bool $secure
* @param bool $httponly
*
* @return bool
*/
public function set($name, $value, $expire = 0, $path = null, $domain = null, $secure = false, $httponly = true)
{
$name = $this->prefix . $name;
$path = isset($path) ? $path : $this->path;
$domain = isset($domain) ? $domain : $this->domain;
$secure = $this->secure || (bool) $secure;
$result = setcookie($name, $value, $expire, $path, $domain, $secure, (bool) $httponly);
if ($result) {
$_COOKIE[$name] = $value;
}
return $result;
}
/**
* Получает значение куки
*
* @param string $name
* @param mixed $default
*
* @return mixed
*/
public function get($name, $default = null)
{
$name = $this->prefix . $name;
return isset($_COOKIE[$name]) ? $this->secury->replInvalidChars($_COOKIE[$name]) : $default;
}
/**
* Удаляет куку
*
* @param string $name
* @param string $path
* @param string $domain
*
* @return bool
*/
public function delete($name, $path = null, $domain = null)
{
$result = $this->set($name, '', 1, $path, $domain);
if ($result) {
unset($_COOKIE[$this->prefix . $name]);
}
return $result;
}
}

View file

@ -18,6 +18,7 @@ class Csrf
/**
* Конструктор
*
* @param Secury $secury
* @param User $user
*/
@ -29,9 +30,11 @@ class Csrf
/**
* Возвращает csrf токен
*
* @param string $marker
* @param array $args
* @param string|int $time
*
* @return string
*/
public function create($marker, array $args = [], $time = null)
@ -48,9 +51,11 @@ class Csrf
/**
* Проверка токена
*
* @param mixed $token
* @param string $marker
* @param array $args
*
* @return bool
*/
public function verify($token, $marker, array $args = [])

View file

@ -2,10 +2,10 @@
namespace ForkBB\Core;
use ForkBB\Core\DBStatement;
use PDO;
use PDOStatement;
use PDOException;
use ForkBB\Core\DBStatement;
class DB extends PDO
{

View file

@ -34,6 +34,25 @@ class Mysql
'%^SERIAL$%i' => 'INT(10) UNSIGNED AUTO_INCREMENT',
];
/**
* Подстановка типов полей для карты БД
* @var array
*/
protected $types = [
'bool' => 'b',
'boolean' => 'b',
'tinyint' => 'i',
'smallint' => 'i',
'mediumint' => 'i',
'int' => 'i',
'integer' => 'i',
'bigint' => 'i',
'decimal' => 'i',
'dec' => 'i',
'float' => 'i',
'double' => 'i',
];
/**
* Конструктор
*
@ -524,4 +543,26 @@ class Mysql
'server info' => $this->db->getAttribute(\PDO::ATTR_SERVER_INFO),
] + $other;
}
/**
* Формирует карту базы данных
*
* @return array
*/
public function getMap()
{
$stmt = $this->db->query('SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME LIKE ?s', ["{$this->dbPrefix}%"]);
$result = [];
$table = null;
while ($row = $stmt->fetch()) {
if ($table !== $row['TABLE_NAME']) {
$table = $row['TABLE_NAME'];
$tableNoPref = substr($table, strlen($this->dbPrefix));
$result[$tableNoPref] = [];
}
$type = strtolower($row['DATA_TYPE']);
$result[$tableNoPref][$row['COLUMN_NAME']] = isset($this->types[$type]) ? $this->types[$type] : 's';
}
return $result;
}
}

View file

@ -24,6 +24,8 @@ class Func
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
{
@ -61,10 +63,13 @@ class Func
}
/**
* Пагинация
*
* @param int $all
* @param int $cur
* @param string $marker
* @param array $args
*
* @return array
*/
public function paginate($all, $cur, $marker, array $args = [])

View file

@ -27,6 +27,7 @@ class Lang
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
@ -37,8 +38,10 @@ class Lang
/**
* Ищет сообщение в загруженных переводах
*
* @param string $message
* @param string $lang
*
* @return string|array
*/
public function get($message, $lang = null)
@ -58,6 +61,7 @@ class Lang
/**
* Загрузка языкового файла
*
* @param string $name
* @param string $lang
* @param string $path
@ -95,9 +99,12 @@ class Lang
/**
* Получение массива перевода из строки (.po файла)
*
* @param string $str
* @return array
*
* @throws RuntimeException
*
* @return array
*/
protected function arrayFromStr($str)
{
@ -242,7 +249,9 @@ class Lang
/**
* Получение оригинальной строки с удалением кавычек
* и преобразованием спецсимволов
*
* @param string $line
*
* @return string
*/
protected function originalLine($line)
@ -256,5 +265,4 @@ class Lang
$line
);
}
}

View file

@ -54,6 +54,7 @@ class Mail
/**
* Конструктор
*
* @param mixed $host
* @param mixed $user
* @param mixed $pass
@ -81,9 +82,11 @@ class Mail
/**
* Валидация email
*
* @param mixed $email
* @param bool $strict
* @param bool $idna
*
* @return false|string
*/
public function valid($email, $strict = false, $idna = false)
@ -113,6 +116,7 @@ class Mail
/**
* Сброс
*
* @return Mail
*/
public function reset()
@ -125,7 +129,9 @@ class Mail
/**
* Задает тему письма
*
* @param string $subject
*
* @return Mail
*/
public function setSubject($subject)
@ -136,8 +142,10 @@ class Mail
/**
* Добавляет заголовок To
*
* @param string|array $email
* @param string $name
*
* @return Mail
*/
public function addTo($email, $name = null)
@ -157,8 +165,10 @@ class Mail
/**
* Задает заголовок To
*
* @param string|array $email
* @param string $name
*
* @return Mail
*/
public function setTo($email, $name = null)
@ -169,8 +179,10 @@ class Mail
/**
* Задает заголовок From
*
* @param string $email
* @param string $name
*
* @return Mail
*/
public function setFrom($email, $name = null)
@ -184,8 +196,10 @@ class Mail
/**
* Задает заголовок Reply-To
*
* @param string $email
* @param string $name
*
* @return Mail
*/
public function setReplyTo($email, $name = null)
@ -199,8 +213,10 @@ class Mail
/**
* Форматирование адреса
*
* @param string|array $email
* @param string $name
*
* @return string
*/
protected function formatAddress($email, $name = null)
@ -215,7 +231,9 @@ class Mail
/**
* Кодирование заголовка/имени
*
* @param string $str
*
* @return string
*/
protected function encodeText($str)
@ -229,7 +247,9 @@ class Mail
/**
* Фильтрация имени
*
* @param string $name
*
* @return string
*/
protected function filterName($name)
@ -239,7 +259,9 @@ class Mail
/**
* Установка папки для поиска шаблонов писем
*
* @param string $folder
*
* @return Mail
*/
public function setFolder($folder)
@ -250,7 +272,9 @@ class Mail
/**
* Установка языка для поиска шаблонов писем
*
* @param string $language
*
* @return Mail
*/
public function setLanguage($language)
@ -261,9 +285,12 @@ class Mail
/**
* Задает сообщение по шаблону
*
* @param string $tpl
* @param array $data
*
* @throws MailException
*
* @return Mail
*/
public function setTpl($tpl, array $data)
@ -286,7 +313,9 @@ class Mail
/**
* Задает сообщение
*
* @param string $message
*
* @return Mail
*/
public function setMessage($message)
@ -300,7 +329,9 @@ class Mail
/**
* Отправляет письмо
*
* @throws MailException
*
* @return bool
*/
public function send()
@ -335,6 +366,7 @@ class Mail
/**
* Отправка письма через функцию mail
*
* @return bool
*/
protected function mail()
@ -349,7 +381,9 @@ class Mail
/**
* Переводит заголовки из массива в строку
*
* @param array $headers
*
* @return string
*/
protected function strHeaders(array $headers)
@ -363,7 +397,9 @@ class Mail
/**
* Отправка письма через smtp
*
* @throws SmtpException
*
* @return bool
*/
protected function smtp()
@ -423,9 +459,12 @@ class Mail
* Отправляет данные на сервер
* Проверяет ответ
* Возвращает код ответа
*
* @param string $data
* @param mixed $code
*
* @throws SmtpException
*
* @return string
*/
protected function smtpData($data, $code)
@ -454,7 +493,9 @@ class Mail
/**
* Выделяет email из заголовка
*
* @param string $str
*
* @return string
*/
protected function getEmailFrom($str)
@ -469,6 +510,7 @@ class Mail
/**
* Возвращает имя сервера или его ip
*
* @return string
*/
protected function hostname()

View file

@ -1,244 +0,0 @@
<?php
namespace ForkBB\Core;
class Request
{
/**
* @var Secury
*/
protected $secury;
/**
* Конструктор
*
* @param Secury $secury
*/
public function __construct($secury)
{
$this->secury = $secury;
}
/**
* @param string $key
*
* @return bool
*/
public function isRequest($key)
{
return $this->isPost($key) || $this->isGet($key);
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function request($key, $default = null)
{
if (($result = $this->post($key)) === null
&& ($result = $this->get($key)) === null
) {
return $default;
}
return $result;
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function requestStr($key, $default = null)
{
if (($result = $this->postStr($key)) === null
&& ($result = $this->getStr($key)) === null
) {
return $default;
}
return $result;
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function requestInt($key, $default = null)
{
if (($result = $this->postInt($key)) === null
&& ($result = $this->getInt($key)) === null
) {
return $default;
}
return $result;
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function requestBool($key, $default = null)
{
if (($result = $this->postBool($key)) === null
&& ($result = $this->getBool($key)) === null
) {
return $default;
}
return $result;
}
/**
* @param string $key
*
* @return bool
*/
public function isPost($key)
{
return isset($_POST[$key]);
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function post($key, $default = null)
{
if (isset($_POST[$key])) {
return $this->secury->replInvalidChars($_POST[$key]);
}
return $default;
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function postStr($key, $default = null)
{
if (isset($_POST[$key]) && is_string($_POST[$key])) {
return (string) $this->secury->replInvalidChars($_POST[$key]);
}
return $default;
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function postInt($key, $default = null)
{
if (isset($_POST[$key]) && is_numeric($_POST[$key]) && is_int(0 + $_POST[$key])) {
return (int) $_POST[$key];
}
return $default;
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function postBool($key, $default = null)
{
if (isset($_POST[$key]) && is_string($_POST[$key])) {
return (bool) $_POST[$key];
}
return $default;
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function postKey($key, $default = null)
{
if (isset($_POST[$key]) && is_array($_POST[$key])) {
$k = key($_POST[$key]);
if (null !== $k) {
return is_int($k) ? (int) $k : (string) $this->secury->replInvalidChars($k);
}
}
return $default;
}
/**
* @param string $key
*
* @return bool
*/
public function isGet($key)
{
return isset($_GET[$key]);
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function get($key, $default = null)
{
if (isset($_GET[$key])) {
return $this->secury->replInvalidChars($_GET[$key]);
}
return $default;
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function getStr($key, $default = null)
{
if (isset($_GET[$key]) && is_string($_GET[$key])) {
return (string) $this->secury->replInvalidChars($_GET[$key]);
}
return $default;
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function getInt($key, $default = null)
{
if (isset($_GET[$key]) && is_numeric($_GET[$key]) && is_int(0 + $_GET[$key])) {
return (int) $_GET[$key];
}
return $default;
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function getBool($key, $default = null)
{
if (isset($_GET[$key]) && is_string($_GET[$key])) {
return (bool) $_GET[$key];
}
return $default;
}
}

View file

@ -59,6 +59,7 @@ class Router
/**
* Конструктор
*
* @param string $base
*/
public function __construct($base)
@ -71,9 +72,11 @@ class Router
/**
* Проверка url на принадлежность форуму
*
* @param mixed $url
* @param string $defMarker
* @param array $defArgs
*
* @return string
*/
public function validate($url, $defMarker, array $defArgs = [])
@ -91,8 +94,10 @@ class Router
/**
* Возвращает ссылку на основании маркера
*
* @param string $marker
* @param array $args
*
* @return string
*/
public function link($marker = null, array $args = [])
@ -127,8 +132,10 @@ class Router
/**
* Метод определяет маршрут
*
* @param string $method
* @param string $uri
*
* @return array
*/
public function route($method, $uri)
@ -195,6 +202,7 @@ class Router
/**
* Метод добавдяет маршрут
*
* @param string|array $method
* @param string $route
* @param string $handler
@ -244,7 +252,9 @@ class Router
/**
* Метод разбирает динамический маршрут
*
* @param string $route
*
* @return array|false
*/
protected function parse($route)

View file

@ -16,9 +16,11 @@ class Secury
/**
* Конструктор
*
* @param array $hmac
* @throws \InvalidArgumentException
* @throws \UnexpectedValueException
*
* @throws InvalidArgumentException
* @throws UnexpectedValueException
*/
public function __construct(array $hmac)
{
@ -33,7 +35,9 @@ class Secury
/**
* Обертка для hash_hmac
*
* @param string $data
*
* @return string
*/
public function hash($data)
@ -43,10 +47,13 @@ class Secury
/**
* Обертка для hash_hmac
*
* @param string $data
* @param string $key
*
* @throws InvalidArgumentException
*
* @return string
* @throws \InvalidArgumentException
*/
public function hmac($data, $key)
{
@ -58,9 +65,12 @@ class Secury
/**
* Возвращает случайный набор байтов заданной длины
*
* @param int $len
*
* @throws RuntimeException
*
* @return string
* @throws \RuntimeException
*/
public function randomKey($len)
{
@ -85,7 +95,9 @@ class Secury
/**
* Возвращает случайную строку заданной длины состоящую из символов 0-9 и a-f
*
* @param int $len
*
* @return string
*/
public function randomHash($len)
@ -96,7 +108,9 @@ class Secury
/**
* Возвращает случайную строку заданной длины состоящую из цифр, латиницы,
* знака минус и символа подчеркивания
*
* @param int $len
*
* @return string
*/
public function randomPass($len)
@ -112,7 +126,9 @@ class Secury
/**
* Replacing invalid UTF-8 characters and remove control characters
*
* @param string|array $data
*
* @return string|array
*/
public function replInvalidChars($data)

View file

@ -75,6 +75,7 @@ class Validator
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
@ -104,8 +105,10 @@ class Validator
/**
* Добавление новых валидаторов
*
* @param array $validators
* @param Validator
*
* @return Validator
*/
public function addValidators(array $validators)
{
@ -115,9 +118,12 @@ class Validator
/**
* Установка правил проверки
*
* @param array $list
* @return Validator
*
* @throws RuntimeException
*
* @return Validator
*/
public function setRules(array $list)
{
@ -149,7 +155,9 @@ class Validator
/**
* Установка дополнительных аргументов для конкретных "имя поля"."имя правила".
*
* @param array $arguments
*
* @return Validator
*/
public function setArguments(array $arguments)
@ -160,7 +168,9 @@ class Validator
/**
* Установка сообщений для конкретных "имя поля"."имя правила".
*
* @param array $messages
*
* @return Validator
*/
public function setMessages(array $messages)
@ -171,7 +181,9 @@ class Validator
/**
* Установка псевдонимов имен полей для сообщений об ошибках
*
* @param array $aliases
*
* @return Validator
*/
public function setAliases(array $aliases)
@ -183,9 +195,12 @@ class Validator
/**
* Проверка данных
* Удачная проверка возвращает true
*
* @param array $raw
*
* @throws RuntimeException
*
* @return bool
* @throws \RuntimeException
*/
public function validation(array $raw)
{
@ -204,7 +219,9 @@ class Validator
/**
* Проверяет наличие поля
*
* @param string $field
*
* @return bool
*/
public function __isset($field)
@ -215,9 +232,12 @@ class Validator
/**
* Проверяет поле согласно заданным правилам
* Возвращает значение запрашиваемого поля
*
* @param string
*
* @throws RuntimeException
*
* @return mixed
* @throws \RuntimeException
*/
public function __get($field)
{
@ -259,8 +279,10 @@ class Validator
/**
* Получение дополнительных аргументов
*
* @param string $field
* @param string $field
* @param string $rule
*
* @return mixed
*/
protected function getArguments($field, $rule)
@ -276,6 +298,7 @@ class Validator
/**
* Обработка ошибки
*
* @param mixed $error
* @param string $field
* @param string $rule
@ -302,7 +325,9 @@ class Validator
/**
* Возвращает статус проверки поля
*
* @param string $field
*
* @return bool
*/
public function getStatus($field)
@ -316,8 +341,10 @@ class Validator
/**
* Возвращает проверенные данные
* Поля с ошибками содержат значения по умолчанию или значения с ошибками
*
* @throws RuntimeException
*
* @return array
* @throws \RuntimeException
*/
public function getData()
{
@ -329,6 +356,7 @@ class Validator
/**
* Возращает массив ошибок
*
* @return array
*/
public function getErrors()

View file

@ -3,7 +3,7 @@
namespace ForkBB\Core;
use R2\Templating\Dirk;
use ForkBB\Models\Pages\Page;
use ForkBB\Models\Page;
use RuntimeException;
class View extends Dirk
@ -24,7 +24,9 @@ class View extends Dirk
/**
* Трансформация скомпилированного шаблона
*
* @param string $value
*
* @return string
*/
protected function compileTransformations($value)
@ -41,23 +43,38 @@ class View extends Dirk
);
}
public function rendering(Page $page)
/**
* Return result of templating
*
* @param Page $p
*
* @return null|string
*/
public function rendering(Page $p)
{
if (! $page->isReady()) {
throw new RuntimeException('The page model does not contain data ready');
}
$headers = $page->httpHeaders();
foreach ($headers as $header) {
foreach ($p->httpHeaders as $header) {
header($header);
}
$tpl = $page->getNameTpl();
// переадресация
if (null === $tpl) {
if (null === $p->nameTpl) {
return null;
}
return $this->fetch($tpl, $page->getData());
$p->prepare();
$this->templates[] = $p->nameTpl;
while ($_name = array_shift($this->templates)) {
$this->beginBlock('content');
foreach ($this->composers as $_cname => $_cdata) {
if (preg_match($_cname, $_name)) {
foreach ($_cdata as $_citem) {
extract((is_callable($_citem) ? $_citem($this) : $_citem) ?: []);
}
}
}
require($this->prepare($_name));
$this->endBlock(true);
}
return $this->block('content');
}
}

View file

@ -86,20 +86,28 @@ class CacheGenerator
return $this->c->DB->query('SELECT text, image FROM ::smilies ORDER BY disp_position')->fetchAll(\PDO::FETCH_KEY_PAIR); //???? text уникальное?
}
/**
* Возвращает массив карты базы данных
*/
public function dbMap()
{
return $this->c->DB->getMap();
}
/**
* Возвращает массив с описанием форумов для текущего пользователя
* @return array
*/
public function forums(User $user)
{
$stmt = $this->c->DB->query('SELECT g_read_board FROM ::groups WHERE g_id=?i:id', [':id' => $user->gId]);
$stmt = $this->c->DB->query('SELECT g_read_board FROM ::groups WHERE g_id=?i:id', [':id' => $user->group_id]);
$read = $stmt->fetchColumn();
$stmt->closeCursor();
$tree = $desc = $asc = [];
if ($read) {
$stmt = $this->c->DB->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.redirect_url, f.parent_forum_id, f.disp_position, fp.post_topics, fp.post_replies FROM ::categories AS c INNER JOIN ::forums AS f ON c.id=f.cat_id LEFT JOIN ::forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id=?i:gid) WHERE fp.read_forum IS NULL OR fp.read_forum=1 ORDER BY c.disp_position, c.id, f.disp_position', [':gid' => $user->groupId]);
$stmt = $this->c->DB->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.redirect_url, f.parent_forum_id, f.disp_position, fp.post_topics, fp.post_replies FROM ::categories AS c INNER JOIN ::forums AS f ON c.id=f.cat_id LEFT JOIN ::forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id=?i:gid) WHERE fp.read_forum IS NULL OR fp.read_forum=1 ORDER BY c.disp_position, c.id, f.disp_position', [':gid' => $user->group_id]);
while ($f = $stmt->fetch()) {
$tree[$f['parent_forum_id']][$f['fid']] = $f;
}

View file

@ -61,7 +61,7 @@ class CacheLoader
public function loadForums()
{
$mark = $this->cache->get('forums_mark');
$key = 'forums_' . $this->c->user->gId;
$key = 'forums_' . $this->c->user->group_id;
if (empty($mark)) {
$this->cache->set('forums_mark', time());

View file

@ -1,111 +0,0 @@
<?php
namespace ForkBB\Models\Actions;
use ForkBB\Core\Container;
class CheckBans
{
/**
* Контейнер
* @var Container
*/
protected $c;
/**
* Содержит массив с описание бана для проверяемого юзера
*/
protected $ban;
/**
* Конструктор
* @param Container $container
*/
public function __construct(Container $container)
{
$this->c = $container;
}
/**
* Возвращает массив с описанием бана или null
* @return null|array
*/
public function check()
{
$user = $this->c->user;
if ($user->isAdmin) {
return null;
} elseif ($user->isGuest) {
$banned = $this->isBanned(null, null, $user->ip);
} else {
$banned = $this->isBanned($user->username, $user->email, $user->ip);
}
if ($banned) {
$this->c->Online->delete($user); //???? а зачем это надо?
return $this->ban;
} else {
return null;
}
}
/**
* Проверяет наличие бана на основании имени юзера, email и(или) ip
* Удаляет просроченные баны
* @param string $username
* @param string $email
* @param string $userIp
* @return int
*/
public function isBanned($username = null, $email = null, $userIp = null)
{
$bans = $this->c->bans;
if (empty($bans)) {
return 0;
}
if (isset($username)) {
$username = mb_strtolower($username, 'UTF-8');
}
if (isset($userIp)) {
// Add a dot or a colon (depending on IPv4/IPv6) at the end of the IP address to prevent banned address
// 192.168.0.5 from matching e.g. 192.168.0.50
$add = strpos($userIp, '.') !== false ? '.' : ':';
$userIp .= $add;
}
$banned = 0;
$remove = [];
$now = time();
foreach ($bans as $cur) {
if ($cur['expire'] != '' && $cur['expire'] < $now) {
$remove[] = $cur['id'];
continue;
} elseif (isset($username) && $cur['username'] != '' && $username == mb_strtolower($cur['username'])) {
$this->ban = $cur;
$banned = 1;
break;
} elseif (isset($email) && $cur['email'] != '' && $email == $cur['email']) {
$this->ban = $cur;
$banned = 2;
break;
} elseif (isset($userIp) && $cur['ip'] != '') {
foreach (explode(' ', $cur['ip']) as $ip) {
$ip .= $add;
if (substr($userIp, 0, strlen($ip)) == $ip) {
$this->ban = $cur;
$banned = 3;
break 2;
}
}
}
}
if (! empty($remove))
{
$this->c->DB->exec('DELETE FROM ::bans WHERE id IN (?ai:remove)', [':remove' => $remove]);
$this->c->{'bans update'};
}
return $banned;
}
}

23
app/Models/AdminList.php Normal file
View file

@ -0,0 +1,23 @@
<?php
namespace ForkBB\Models;
use ForkBB\Models\Model;
class AdminList extends Model
{
/**
* Загружает список id админов из кеша/БД
*
* @return AdminList
*/
public function init()
{
if ($this->c->Cache->has('admins')) {
$this->list = $this->c->Cache->get('admins');
} else {
$this->load();
}
return $this;
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace ForkBB\Models\AdminList;
use ForkBB\Models\MethodModel;
class Load extends MethodModel
{
/**
* Заполняет модель данными из БД
* Создает кеш
*
* @return AdminList
*/
public function load()
{
$list = $this->c->DB->query('SELECT id FROM ::users WHERE group_id=?i', [$this->c->GROUP_ADMIN])->fetchAll(\PDO::FETCH_COLUMN);
$this->model->list = $list;
$this->c->Cache->set('admins', $list);
return $this->model;
}
}

46
app/Models/BanList.php Normal file
View file

@ -0,0 +1,46 @@
<?php
namespace ForkBB\Models;
use ForkBB\Models\Model;
class BanList extends Model
{
/**
* Загружает список банов из кеша/БД
*
* @return BanList
*/
public function init()
{
if ($this->c->Cache->has('banlist')) {
$list = $this->c->Cache->get('banlist');
$this->otherList = $list['otherList'];
$this->userList = $list['userList'];
$this->ipList = $list['ipList'];
} else {
$this->load();
}
return $this;
}
/**
* Фильтрует значение
*
* @param mixed $val
* @param bool $toLower
*
* @return null|string
*/
public function trimToNull($val, $toLower = false)
{
$val = trim($val);
if ($val == '') {
return null;
} elseif ($toLower) {
return mb_strtolower($val, 'UTF-8');
} else {
return $val;
}
}
}

View file

@ -0,0 +1,67 @@
<?php
namespace ForkBB\Models\BanList;
use ForkBB\Models\MethodModel;
use ForkBB\Models\User;
class Check extends MethodModel
{
/**
* Проверяет наличие бана (для текущего пользователя) на основании имени пользователя/ip
* Удаляет просроченные баны
*
* @param User $user
*
* @return bool
*/
public function check(User $user)
{
// админ
if ($user->isAdmin) {
return false;
}
// удаление просроченных банов
$now = time();
$ids = [];
foreach ($this->model->otherList as $id => $row) {
if (null !== $row['expire'] && $row['expire'] < $now) {
$ids[] = $id;
}
}
if (! empty($ids)) {
$this->model->delete($ids);
}
// проверка гостя
if ($user->isGuest) {
$ip = $this->model->trimToNull($user->ip);
if (null === $ip) {
return false; //????
}
$add = strpos($ip, ':') === false ? '.' : ':'; //????
$ip .= $add;
foreach ($this->model->ipList as $addr => $id) {
$addr .= $add;
if (substr($ip, 0, strlen($addr)) == $addr) {
if (isset($this->model->otherList[$id])) {
$user->__banInfo = $this->model->otherList[$id];
}
return true;
}
}
// проверка пользователя
} else {
$name = $this->model->trimToNull($user->username, true);
if (isset($this->model->userList[$name])) {
$id = $this->model->userList[$name];
if (isset($this->model->otherList[$id])) {
$user->__banInfo = $this->model->otherList[$id];
}
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace ForkBB\Models\BanList;
use ForkBB\Models\MethodModel;
class Delete extends MethodModel
{
/**
* Удаляет из банов записи по списку номеров
* Обновляет кеш
*
* @param array $ids
*
* @return BanList
*/
public function delete(array $ids)
{
if (! empty($ids)) {
$this->c->DB->exec('DELETE FROM ::bans WHERE id IN (?ai:ids)', [':ids' => $ids]);
$this->model->load();
}
return $this->model;
}
}

View file

@ -0,0 +1,35 @@
<?php
namespace ForkBB\Models\BanList;
use ForkBB\Models\MethodModel;
use ForkBB\Models\User;
class IsBanned extends MethodModel
{
/**
* Проверяет наличие бана на основании имени пользователя и(или) email
*
* @param User $user
*
* @return int
*/
public function isBanned(User $user)
{
$name = $this->trimToNull($this->model->username, true);
if (null !== $name && isset($this->model->userList[$name])) {
return 1;
}
$email = $this->trimToNull($this->model->email);
if (null !== $email) {
foreach ($this->model->otherList as $row) {
if (null === $row['email']) {
continue;
} elseif ($email == $row['email']) {
return 2;
}
}
}
return 0;
}
}

View file

@ -0,0 +1,60 @@
<?php
namespace ForkBB\Models\BanList;
use ForkBB\Models\MethodModel;
class Load extends MethodModel
{
/**
* Загружает список банов из БД
* Создает кеш
*
* @return BanList
*/
public function load()
{
$userList = [];
$ipList = [];
$otherList = [];
$stmt = $this->c->DB->query('SELECT id, username, ip, email, message, expire FROM ::bans');
while ($row = $stmt->fetch()) {
$name = $this->model->trimToNull($row['username'], true);
if (null !== $name) {
$userList[$name] = $row['id'];
}
$ips = $this->model->trimToNull($row['ip']);
if (null !== $ips) {
foreach (explode(' ', $ips) as $ip) {
$ip = trim($ip);
if ($ip != '') {
$ipList[$ip] = $row['id'];
}
}
}
$email = $this->model->trimToNull($row['email']);
$message = $this->model->trimToNull($row['message']);
$expire = empty($row['expire']) ? null : $row['expire'];
if (! isset($email) && ! isset($message) && ! isset($expire)) {
continue;
}
$otherList[$row['id']] = [
'email' => $email,
'message' => $message,
'expire' => $expire,
];
}
$this->model->otherList = $otherList;
$this->model->userList = $userList;
$this->model->ipList = $ipList;
$this->c->Cache->set('banlist', [
'otherList' => $otherList,
'userList' => $userList,
'ipList' => $ipList,
]);
return $this->model;
}
}

View file

@ -0,0 +1,41 @@
<?php
namespace ForkBB\Models;
use ForkBB\Models\Model;
class CensorshipList extends Model
{
/**
* Загружает список цензуры из кеша/БД
*
* @return BanList
*/
public function init()
{
if ($this->c->Cache->has('censorship')) {
$list = $this->c->Cache->get('censorship');
$this->searchList = $list['searchList'];
$this->replaceList = $list['replaceList'];
} else {
$this->load();
}
return $this;
}
/**
* Выполняет цензуру при необходимости
*
* @param string $str
*
* @return string
*/
public function censor($str)
{
if ($this->c->config->o_censoring == '1') {
return (string) preg_replace($this->searchList, $this->replaceList, $str);
} else {
return $str;
}
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace ForkBB\Models\CensorshipList;
use ForkBB\Models\MethodModel;
class Load extends MethodModel
{
/**
* Заполняет модель данными из БД
* Создает кеш
*
* @return CensorshipList
*/
public function load()
{
$stmt = $this->c->DB->query('SELECT search_for, replace_with FROM ::censoring');
$search = [];
$replace = [];
while ($row = $stmt->fetch()) {
$replace[] = $row['replace_with'];
$search[] = '%(?<![\p{L}\p{N}])('.str_replace('\*', '[\p{L}\p{N}]*?', preg_quote($row['search_for'], '%')).')(?![\p{L}\p{N}])%iu';
}
$this->model->searchList = $search;
$this->model->replaceList = $replace;
$this->c->Cache->set('censorship', [
'searchList' => $search,
'replaceList' => $replace,
]);
return $this->model;
}
}

23
app/Models/Config.php Normal file
View file

@ -0,0 +1,23 @@
<?php
namespace ForkBB\Models;
use ForkBB\Models\DataModel;
class Config extends DataModel
{
/**
* Заполняет модель данными из кеша/БД
*
* @return Config
*/
public function init()
{
if ($this->c->Cache->has('config')) {
$this->setAttrs($this->c->Cache->get('config'));
} else {
$this->load();
}
return $this;
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace ForkBB\Models\Config;
use ForkBB\Models\MethodModel;
class Load extends MethodModel
{
/**
* Заполняет модель данными из БД
* Создает кеш
*
* @return Config
*/
public function load()
{
$config = $this->c->DB->query('SELECT conf_name, conf_value FROM ::config')->fetchAll(\PDO::FETCH_KEY_PAIR);
$this->model->setAttrs($config);
$this->c->Cache->set('config', $config);
return $this->model;
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace ForkBB\Models\Config;
use ForkBB\Models\MethodModel;
class Save extends MethodModel
{
/**
* Сохраняет изменения модели в БД
* Удаляет кеш
*
* @return Config
*/
public function save()
{
$modified = $this->model->getModified();
if (empty($modified)) {
return;
}
$values = $this->model->getAttrs();
foreach ($modified as $name) {
$vars = [
':value' => $values[$name],
':name' => $name
];
//????
$count = $this->c->DB->exec('UPDATE ::config SET conf_value=?s:value WHERE conf_name=?s:name', $vars);
if ($count === 0) {
$this->c->DB->exec('INSERT INTO ::config (conf_name, conf_value) VALUES (?s:name, ?s:value)', $vars);
}
}
$this->c->Cache->delete('config');
return $this->model;
}
}

212
app/Models/Cookie.php Normal file
View file

@ -0,0 +1,212 @@
<?php
namespace ForkBB\Models;
use ForkBB\Models\Model;
use ForkBB\Models\User;
use ForkBB\Core\Container;
use RuntimeException;
class Cookie extends Model
{
const NAME = 'user';
/**
* Флаг запрета записи свойств
* @var bool
*/
protected $noSet = false;
/**
* Конструктор
*
* @param array $options
* @param Container $container
*/
public function __construct(array $options, Container $container)
{
parent::__construct($container);
$this->a = $options + [
'prefix' => '',
'domain' => '',
'path' => '',
'secure' => false,
'time' => 31536000,
'key1' => 'key1',
'key2' => 'key2',
];
$this->init();
$this->noSet = true;
}
/**
* Устанавливает куку
*
* @param string $name
* @param string $value
* @param int $expire
* @param string $path
* @param string $domain
* @param bool $secure
* @param bool $httponly
*
* @return bool
*/
public function set($name, $value, $expire = 0, $path = null, $domain = null, $secure = false, $httponly = true)
{
$result = setcookie(
$this->prefix . $name,
$value,
$expire,
$path ?: $this->path,
$domain ?: $this->domain,
(bool) $this->secure || (bool) $secure,
(bool) $httponly
);
if ($result) {
$_COOKIE[$this->prefix . $name] = $value;
}
return $result;
}
/**
* Получает значение куки
*
* @param string $name
* @param mixed $default
*
* @return mixed
*/
public function get($name, $default = null)
{
$name = $this->prefix . $name;
return isset($_COOKIE[$name]) ? $this->c->Secury->replInvalidChars($_COOKIE[$name]) : $default;
}
/**
* Удаляет куку
*
* @param string $name
* @param string $path
* @param string $domain
*
* @return bool
*/
public function delete($name, $path = null, $domain = null)
{
$result = $this->set($name, '', 1, $path, $domain);
if ($result) {
unset($_COOKIE[$this->prefix . $name]);
}
return $result;
}
/**
* Выделение данных из куки аутентификации
*/
protected function init()
{
$ckUser = $this->get(self::NAME);
if (null === $ckUser
|| ! preg_match('%^(\-)?(\d{1,10})_(\d{10})_([a-f\d]{32,})_([a-f\d]{32,})$%Di', $ckUser, $ms)
) {
return;
}
if (2 > $ms[2]
|| time() > $ms[3]
|| ! hash_equals(
$this->c->Secury->hmac($ms[1] . $ms[2] . $ms[3] . $ms[4], $this->key1),
$ms[5]
)
) {
return;
}
$this->uRemember = empty($ms[1]);
$this->uId = (int) $ms[2];
$this->uExpire = (int) $ms[3];
$this->uHash = $ms[4];
}
/**
* Проверка хэша пароля
*
* @param User $user
*
* @return bool
*/
public function verifyUser(User $user)
{
return $this->uId === (int) $user->id
&& hash_equals(
(string) $this->uHash,
$this->c->Secury->hmac($user->password . $this->uExpire, $this->key2)
);
}
/**
* Установка куки аутентификации юзера
*
* @param User $user
* @param bool $remember
*
* @return bool
*/
public function setUser(User $user, $remember = null)
{
if ($user->isGuest) {
return $this->deleteUser();
}
if ($remember
|| (null === $remember
&& $this->uId === (int) $user->id
&& $this->uRemember
)
) {
$expTime = time() + $this->time;
$expire = $expTime;
$pfx = '';
} else {
$expTime = time() + $this->c->config->o_timeout_visit;
$expire = 0;
$pfx = '-';
}
$passHash = $this->c->Secury->hmac($user->password . $expTime, $this->key2);
$ckHash = $this->c->Secury->hmac($pfx . $user->id . $expTime . $passHash, $this->key1);
return $this->set(self::NAME, $pfx . $user->id . '_' . $expTime . '_' . $passHash . '_' . $ckHash, $expire);
}
/**
* Удаление куки аутентификации юзера
*
* @return bool
*/
public function deleteUser()
{
if (null === $this->get(self::NAME)) {
return true;
} else {
return $this->delete(self::NAME);
}
}
/**
* Устанавливает значение для свойства
*
* @param string $name
* @param mixed $val
*
* @throws RuntimeException
*/
public function __set($name, $val)
{
if ($this->noSet) {
throw new RuntimeException('Model attributes in read-only mode');
}
parent::__set($name, $val);
}
}

25
app/Models/DBMap.php Normal file
View file

@ -0,0 +1,25 @@
<?php
namespace ForkBB\Models;
use ForkBB\Models\Model;
class DBMap extends Model
{
/**
* Загружает карту БД из кеша/БД
*
* @return DBMap
*/
public function init()
{
if ($this->c->Cache->has('db_map')) {
$this->a = $this->c->Cache->get('db_map');
} else {
$map = $this->c->DB->getMap();
$this->c->Cache->set('db_map', $map);
$this->a = $map;
}
return $this;
}
}

91
app/Models/DataModel.php Normal file
View file

@ -0,0 +1,91 @@
<?php
namespace ForkBB\Models;
use ForkBB\Core\Container;
use ForkBB\Models\Model;
use InvalidArgumentException;
use RuntimeException;
abstract class DataModel extends Model
{
/**
* Массив флагов измененных свойств модели
* @var array
*/
protected $modified = [];
/**
* Конструктор
*
* @param array $attrs
* @param Container $container
*/
public function __construct(array $attrs, Container $container)
{
parent::__construct($container);
$this->a = $attrs;
}
/**
* Устанавливает значения для свойств
*
* @param array $attrs
*
* @return DataModel
*/
public function setAttrs(array $attrs)
{
$this->a = $attrs; //????
$this->modified = [];
return $this;
}
/**
* Возвращает значения свойств в массиве
*
* @return array
*/
public function getAttrs()
{
return $this->a; //????
}
/**
* Возвращает массив имен измененных свойств модели
*
* @return array
*/
public function getModified()
{
return array_keys($this->modified);
}
/**
* Обнуляет массив флагов измененных свойств модели
*/
public function resModified()
{
$this->modified = [];
}
/**
* Устанавливает значение для свойства
*
* @param string $name
* @param mixed $val
*/
public function __set($name, $val)
{
// запись свойства без отслеживания изменений
if (strpos($name, '__') === 0) {
return parent::__set(substr($name, 2), $val);
}
$old = isset($this->a[$name]) ? $this->a[$name] : null;
parent::__set($name, $val);
if ($old !== $this->a[$name]) {
$this->modified[$name] = true;
}
}
}

54
app/Models/Forum.php Normal file
View file

@ -0,0 +1,54 @@
<?php
namespace ForkBB\Models;
use ForkBB\Models\DataModel;
use ForkBB\Core\Container;
class Forum extends DataModel
{
/**
* @param array $attrs
*
* @return Forum
*/
public function replAtttrs(array $attrs)
{
foreach ($attrs as $key => $val) {
$this->{'__' . $key} = $val; //????
}
$modified = array_diff(array_keys($this->modified), array_keys($attrs));
$this->modified = [];
foreach ($modified as $key) {
$this->modified[$key] = true;
}
return $this;
}
protected function getSubforums()
{
$sub = [];
if (! empty($this->a['subforums'])) {
foreach ($this->a['subforums'] as $id) {
$sub[$id] = $this->c->forums->forum($id);
}
}
return $sub;
}
protected function getDescendants()
{
$all = [];
if (! empty($this->a['descendants'])) {
foreach ($this->a['descendants'] as $id) {
$all[$id] = $this->c->forums->forum($id);
}
}
return $all;
}
protected function getParent()
{
return $this->c->forums->forum($this->parent_forum_id);
}
}

62
app/Models/ForumList.php Normal file
View file

@ -0,0 +1,62 @@
<?php
namespace ForkBB\Models;
use ForkBB\Models\Model;
use RuntimeException;
class ForumList extends Model
{
/**
* Загружает список доступных разделов для текущего пользователя из кеша/БД
*
* @return ForumList
*/
public function init()
{
$mark = $this->c->Cache->get('forums_mark');
if (empty($mark)) {
$this->c->Cache->set('forums_mark', time());
return $this->load();
}
$result = $this->c->Cache->get('forums_' . $this->c->user->group_id);
if (empty($result['time']) || $result['time'] < $mark) {
return $this->load();
}
$this->list = $result['list']; //????
return $this;
}
/**
* Проверяет доступность раздела
*
* @param int $id
*
* @return bool
*/
public function isAvailable($id)
{
return isset($this->list[$id]); //????
}
/**
*
* @param int $id
*
* @return null|Forum
*/
public function forum($id)
{
if (isset($this->forums[$id])) {
return $this->forums[$id];
} elseif ($this->isAvailable($id)) {
$forum = $this->c->ModelForum->setAttrs($this->list[$id]);
$this->a['forums'][$id] = $forum; //????
return $forum;
} else {
return null;
}
}
}

View file

@ -0,0 +1,93 @@
<?php
namespace ForkBB\Models\ForumList;
use ForkBB\Models\MethodModel;
class Load extends MethodModel
{
/**
* @var array
*/
protected $list = [];
/**
* Заполняет модель данными из БД для текущего пользователя
* Создает кеш
*
* @return ForumList
*/
public function load()
{
$this->getList();
$this->model->list = $this->list; //????
$this->c->Cache->set('forums_' . $this->c->user->group_id, [
'time' => time(),
'list' => $this->list,
]);
return $this->model;
}
/**
* Получает данные из БД
*/
protected function getList()
{
if ($this->c->user->g_read_board != '1') {
return;
}
$list = [];
$vars = [':gid' => $this->c->user->group_id];
$sql = 'SELECT c.id AS cid, c.cat_name, f.id, f.forum_name, f.redirect_url, f.parent_forum_id,
f.disp_position, fp.post_topics, fp.post_replies
FROM ::categories AS c
INNER JOIN ::forums AS f ON c.id=f.cat_id
LEFT JOIN ::forum_perms AS fp ON (fp.group_id=?i:gid AND fp.forum_id=f.id)
WHERE fp.read_forum IS NULL OR fp.read_forum=1
ORDER BY c.disp_position, c.id, f.disp_position';
$stmt = $this->c->DB->query($sql, $vars);
while ($row = $stmt->fetch()) {
$list[$row['id']] = $row;
}
if (empty($list)) {
return;
}
$this->createList($list);
}
/**
* Формирует список доступных разделов
*
* @param array $list
* @param int $parent
*
* @return array
*/
protected function createList(array $list, $parent = 0)
{
$sub = [];
$all = [];
foreach ($list as $id => $f) {
if ($parent === $id || $parent !== $f['parent_forum_id']) {
continue;
}
$sub[] = $id;
$all = array_merge($this->createList($list, $id), $all);
}
if ($parent === 0) {
if (empty($sub)) {
return [];
}
$list[0]['id'] = $parent;
$list[0]['ready'] = true;
}
$all = array_merge($sub, $all);
$list[$parent]['subforums'] = $sub ?: null;
$list[$parent]['descendants'] = $all ?: null;
$this->list[$parent] = array_filter($list[$parent], function($val) {
return $val !== null;
});
return $all;
}
}

View file

@ -0,0 +1,132 @@
<?php
namespace ForkBB\Models\ForumList;
use ForkBB\Models\MethodModel;
class LoadTree extends MethodModel
{
/**
* Загружает данные в модели разделов для указанного раздела и всех его потомков
*
* @param int $rootId
*
* @return null|Forum
*/
public function loadTree($rootId)
{
$root = $this->model->forum($rootId);
if (null === $root) {
return null;
}
$list = [];
if (! $root->ready) {
$list[] = $rootId;
}
foreach ($root->descendants as $id => $descendant) {
if (! $descendant->ready) {
$list[] = $id;
}
}
$this->loadData($list);
if (! $this->c->user->isGuest) {
$this->checkForNew(array_keys($root->descendants)); //????
}
return $root;
}
/**
* Загружает данные из БД по списку id разделов
*
* @param array $list
*/
public function loadData(array $list)
{
if (empty($list)) {
return;
}
$vars = [
':uid' => $this->c->user->id,
':forums' => $list,
];
if ($this->c->user->isGuest) {
$sql = 'SELECT f.id, f.forum_desc, f.moderators, f.num_topics, f.sort_by,
f.num_posts, f.last_post, f.last_post_id, f.last_poster, f.last_topic
FROM ::forums AS f
WHERE id IN (?ai:forums)';
} elseif ($this->c->config->o_forum_subscriptions == '1') {
$sql = 'SELECT f.id, f.forum_desc, f.moderators, f.num_topics, f.sort_by,
f.num_posts, f.last_post, f.last_post_id, f.last_poster, f.last_topic,
mof.mf_mark_all_read, s.user_id AS is_subscribed
FROM ::forums AS f
LEFT JOIN ::forum_subscriptions AS s ON (s.user_id=?i:uid AND s.forum_id=f.id)
LEFT JOIN ::mark_of_forum AS mof ON (mof.uid=?i:uid AND mof.fid=f.id)
WHERE f.id IN (?ai:forums)';
} else {
$sql = 'SELECT f.id, f.forum_desc, f.moderators, f.num_topics, f.sort_by,
f.num_posts, f.last_post, f.last_post_id, f.last_poster, f.last_topic,
mof.mf_mark_all_read
FROM ::forums AS f
LEFT JOIN ::mark_of_forum AS mof ON (mof.uid=?i:id AND mof.fid=f.id)
WHERE f.id IN (?ai:forums)';
}
$stmt = $this->c->DB->query($sql, $vars);
while ($cur = $stmt->fetch()) {
$this->model->forum($cur['id'])->replAtttrs($cur)->ready = true;
}
}
/**
* Проверяет наличие новых сообщений в разделах по списку id
*
* @param array $list
*/
protected function checkForNew(array $list)
{
if (empty($list) || $this->c->user->isGuest) {
return;
}
// предварительная проверка разделов
$time = [];
$max = max((int) $this->c->user->last_visit, (int) $this->c->user->u_mark_all_read);
foreach ($list as $id) {
$forum = $this->model->forum($id);
$t = max($max, (int) $forum->mf_mark_all_read);
if ($forum->last_post > $t) {
$time[$id] = $t;
}
}
if (empty($time)) {
return;
}
// проверка по темам
$vars = [
':uid' => $this->c->user->id,
':forums' => array_keys($time),
':max' => $max,
];
$sql = 'SELECT t.forum_id, t.last_post
FROM ::topics AS t
LEFT JOIN ::mark_of_topic AS mot ON (mot.uid=?i:uid AND mot.tid=t.id)
WHERE t.forum_id IN(?ai:forums)
AND t.last_post>?i:max
AND t.moved_to IS NULL
AND (mot.mt_last_visit IS NULL OR t.last_post>mot.mt_last_visit)';
$stmt = $this->c->DB->query($sql, $vars);
while ($cur = $stmt->fetch()) {
if ($cur['last_post'] > $time[$cur['forum_id']]) {
$this->model->forum($cur['forum_id'])->newMessages = true; //????
}
}
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace ForkBB\Models;
use ForkBB\Core\Container;
use ForkBB\Models\Model;
abstract class MethodModel
{
/**
* Контейнер
* @var Container
*/
protected $c;
/**
* Модель
* @var Model
*/
protected $model;
/**
* Конструктор
*
* @param Model $model
* @param Container $container
*/
public function __construct(Model $model, Container $container)
{
$this->model = $model;
$this->c = $container;
}
}

115
app/Models/Model.php Normal file
View file

@ -0,0 +1,115 @@
<?php
namespace ForkBB\Models;
use ForkBB\Core\Container;
use InvalidArgumentException;
use RuntimeException;
abstract class Model
{
/**
* Контейнер
* @var Container
*/
protected $c;
/**
* Данные модели
* @var array
*/
protected $a = [];
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
{
$this->c = $container;
}
/**
* Проверяет наличие свойства
*
* @param mixed $name
*
* @return bool
*/
public function __isset($name)
{
return isset($this->a[$name]); //???? array_key_exists($name, $this->a)
}
/**
* Удаляет свойство
*
* @param mixed $name
*/
public function __unset($name)
{
unset($this->a[$name]);
}
/**
* Устанавливает значение для свойства
*
* @param string $name
* @param mixed $val
*/
public function __set($name, $val)
{
$method = 'set' . ucfirst($name);
if (method_exists($this, $method)) {
$this->$method($val);
} else {
$this->a[$name] = $val;
}
}
/**
* Возвращает значение свойства
*
* @param string $name
*
* @return mixed
*/
public function __get($name)
{
$method = 'get' . ucfirst($name);
if (method_exists($this, $method)) {
return $this->$method();
} else {
return isset($this->a[$name]) ? $this->a[$name] : null;
}
}
/**
* Выполняет подгружаемый метод при его наличии
*
* @param string $name
* @param array $args
*
* @throws RuntimeException
*
* @return mixed
*/
public function __call($name, array $args)
{
$key = str_replace(['ForkBB\\', '\\'], '', get_class($this));
if (empty($this->c->METHODS[$key][$name])) {
throw new RuntimeException("The {$name} method was not found");
}
$link = explode(':', $this->c->METHODS[$key][$name], 2);
$factory = new $link[0]($this, $this->c);
if (isset($link[1])) {
return $factory->{$link[1]}(...$args);
} else {
return $factory->$name(...$args);
}
}
}

View file

@ -3,71 +3,60 @@
namespace ForkBB\Models;
use ForkBB\Core\Container;
use ForkBB\Models\Model;
use ForkBB\Models\User;
use ForkBB\Models\Pages\Page;
use ForkBB\Models\Page;
class Online
class Online extends Model
{
/**
* Контейнер
* @var Container
*/
protected $c;
/**
* Флаг выполнения
* @var bool
*/
protected $done = false;
/**
* @var array
*/
protected $config;
/**
* Конструктор
* @param array $config
*
* @param Container $container
*/
public function __construct(Container $container)
{
$this->c = $container;
$this->config = $container->config;
parent::__construct($container);
$this->users = [];
$this->guests = [];
$this->bots = [];
}
/**
* Обработка данных пользователей онлайн
* Обновление данных текущего пользователя
* Возврат данных по пользователям онлайн
*
* @param Page $page
* @return array
*/
public function handle(Page $page)
public function calc(Page $page)
{
if ($this->done) {
return [[], [], []]; //????
return;
}
$this->done = true;
// string|null bool bool
list($position, $type, $filter) = $page->getDataForOnline(); //???? возможно стоит возвращать полное имя страницы для отображение
$position = $page->onlinePos;
if (null === $position) {
return [[], [], []]; //????
return;
}
$type = $page->onlineType;
$filter = $page->onlineFilter;
$this->updateUser($position);
$all = 0;
$now = time();
$tOnline = $now - $this->config['o_timeout_online'];
$tVisit = $now - $this->config['o_timeout_visit'];
$users = $guests = $bots = [];
$all = 0;
$now = time();
$tOnline = $now - $this->c->config->o_timeout_online;
$tVisit = $now - $this->c->config->o_timeout_visit;
$users = [];
$guests = [];
$bots = [];
$deleteG = false;
$deleteU = false;
$setIdle = false;
if ($this->config['o_users_online'] == '1' && $type) {
if ($this->c->config->o_users_online == '1' && $type) {
$stmt = $this->c->DB->query('SELECT user_id, ident, logged, idle, o_position, o_name FROM ::online ORDER BY logged');
} elseif ($type) {
$stmt = $this->c->DB->query('SELECT user_id, ident, logged, idle FROM ::online ORDER BY logged');
@ -142,16 +131,19 @@ class Online
}
// обновление максимального значение пользоватеелй онлайн
if ($this->config['st_max_users'] < $all) {
$this->c->DB->exec('UPDATE ::config SET conf_value=?s:value WHERE conf_name=?s:name', [':value' => $all, ':name' => 'st_max_users']);
$this->c->DB->exec('UPDATE ::config SET conf_value=?s:value WHERE conf_name=?s:name', [':value' => $now, ':name' => 'st_max_users_time']);
$this->c->{'config update'};
if ($this->c->config->st_max_users < $all) {
$this->c->config->st_max_users = $all;
$this->c->config->st_max_users_time = $now;
$this->c->config->save();
}
return [$users, $guests, $bots];
$this->users = $users;
$this->guests = $guests;
$this->bots = $bots;
}
/**
* Обновление данных текущего пользователя
*
* @param string $position
*/
protected function updateUser($position)

View file

@ -1,118 +1,181 @@
<?php
namespace ForkBB\Models\Pages;
namespace ForkBB\Models;
use ForkBB\Core\Container;
use ForkBB\Models\Model;
use RuntimeException;
abstract class Page
abstract class Page extends Model
{
/**
* Контейнер
* @var Container
*/
protected $c;
/**
* Конфигурация форума
* @var array
*/
protected $config;
/**
* HTTP статус ответа для данной страницы
* @var int
*/
protected $httpStatus = 200;
/**
* HTTP заголовки отличные от статуса
* @var array
*/
protected $httpHeaders = [];
/**
* Имя шаблона
* @var string
*/
protected $nameTpl;
/**
* Указатель на активный пункт навигации
* @var string
*/
protected $index = 'index';
/**
* Массив титула страницы
* @var array
*/
protected $titles = [];
/**
* Подготовленные данные для шаблона
* @var array
*/
protected $data = [];
/**
* Массив info, success, warning, error, validation информации
* @var array
*/
protected $iswev = [];
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = '';
/**
* Тип обработки пользователей онлайн
* Если false, то идет обновление данных
* Если true, то идет возврат данных (смотрите $onlineFilter)
* @var bool
*/
protected $onlineType = false;
/**
* Тип возврата данных при onlineType === true
* Если true, то из online должны вернутся только пользователи находящиеся на этой же странице
* Если false, то все пользователи online
* @var bool
*/
protected $onlineFilter = true;
/**
* Переменная для meta name="robots"
* @var string
*/
protected $robots;
/**
* Переменная для link rel="canonical"
* @var string
*/
protected $canonical;
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
{
$this->c = $container;
$this->config = $container->config;
parent::__construct($container);
$container->Lang->load('common');
$this->fIndex = 'index'; # string Указатель на активный пункт навигации
$this->httpStatus = 200; # int HTTP статус ответа для данной страницы
$this->httpHeaders = []; # array HTTP заголовки отличные от статуса
# $this->nameTpl = null; # null|string Имя шаблона
# $this->titles = []; # array Массив титула страницы | setTitles()
$this->fIswev = []; # array Массив info, success, warning, error, validation информации
# $this->onlinePos = ''; # null|string Позиция для таблицы онлайн текущего пользователя
$this->onlineType = false; # bool Тип обработки пользователей онлайн
# Если false, то идет обновление данных
# Если true, то идет возврат данных (смотрите onlineFilter)
$this->onlineFilter = true; # bool Тип возврата данных при onlineType === true
# Если true, то из online должны вернутся только пользователи находящиеся на этой же странице
# Если false, то все пользователи online
# $this->robots = ''; # string Переменная для meta name="robots"
# $this->canonical = ''; # string Переменная для link rel="canonical"
$this->fTitle = $container->config->o_board_title;
$this->fDescription = $container->config->o_board_desc;
$this->fAnnounce = $container->config->o_announcement_message;
$this->fRootLink = $container->Router->link('Index');
}
/**
* Подготовка страницы к отображению
*/
public function prepare()
{
$this->fNavigation = $this->fNavigation();
$this->maintenance();
}
/**
* Возвращает массив ссылок с описанием для построения навигации
*
* @return array
*/
protected function fNavigation()
{
$user = $this->c->user;
$r = $this->c->Router;
$nav = [
'index' => [$r->link('Index'), __('Index')]
];
if ($user->g_read_board == '1' && $user->g_view_users == '1') {
$nav['userlist'] = [$r->link('Userlist'), __('User list')];
}
if ($this->c->config->o_rules == '1' && (! $user->isGuest || $user->g_read_board == '1' || $this->c->config->o_regs_allow == '1')) {
$nav['rules'] = [$r->link('Rules'), __('Rules')];
}
if ($user->g_read_board == '1' && $user->g_search == '1') {
$nav['search'] = [$r->link('Search'), __('Search')];
}
if ($user->isGuest) {
$nav['register'] = [$r->link('Register'), __('Register')];
$nav['login'] = [$r->link('Login'), __('Login')];
} else {
$nav['profile'] = [$r->link('User', [
'id' => $user->id,
'name' => $user->username,
]), __('Profile')];
// New PMS
if ($this->c->config->o_pms_enabled == '1' && ($user->isAdmin || $user->messages_new > 0)) { //????
$nav['pmsnew'] = ['pmsnew.php', __('PM')]; //'<li id="nav"'.((PUN_ACTIVE_PAGE == 'pms_new' || $user['messages_new'] > 0) ? ' class="isactive"' : '').'><a href="pmsnew.php">'.__('PM').(($user['messages_new'] > 0) ? ' (<span'.((empty($this->c->config->o_pms_flasher) || PUN_ACTIVE_PAGE == 'pms_new') ? '' : ' class="remflasher"' ).'>'.$user['messages_new'].'</span>)' : '').'</a></li>';
}
// New PMS
if ($user->isAdmMod) {
$nav['admin'] = [$r->link('Admin'), __('Admin')];
}
$nav['logout'] = [$r->link('Logout', [
'token' => $this->c->Csrf->create('Logout'),
]), __('Logout')];
}
if ($user->g_read_board == '1' && $this->c->config->o_additional_navlinks != '') {
// position|name|link[|id]\n
if (preg_match_all('%^(\d+)\|([^\|\n\r]+)\|([^\|\n\r]+)(?:\|([^\|\n\r]+))?$%m', $this->c->config->o_additional_navlinks."\n", $matches)) {
$k = count($matches[0]);
for ($i = 0; $i < $k; ++$i) {
if (empty($matches[4][$i])) {
$matches[4][$i] = 'extra' . $i;
}
if (isset($nav[$matches[4][$i]])) {
$nav[$matches[4][$i]] = [$matches[3][$i], $matches[2][$i]];
} else {
$nav = array_merge(
array_slice($nav, 0, $matches[1][$i]),
[$matches[4][$i] => [$matches[3][$i], $matches[2][$i]]],
array_slice($nav, $matches[1][$i])
);
}
}
}
}
return $nav;
}
/**
* Вывод информации о режиме обслуживания для админа
*/
protected function maintenance()
{
if ($this->c->config->o_maintenance == '1' && $this->c->user->isAdmin) {
$this->a['fIswev']['w']['maintenance'] = __('Maintenance mode enabled', $this->c->Router->link('AdminOptions', ['#' => 'maintenance']));
}
}
/**
* Возвращает title страницы
* $this->pageTitle
*
* @param array $titles
*
* @return string
*/
protected function getPageTitle(array $titles = [])
{
if (empty($titles)) {
$titles = $this->titles;
}
$titles[] = $this->c->config->o_board_title;
return implode(__('Title separator'), $titles);
}
/**
* Возвращает массива заголовков страницы
* $this->pageHeaders
*
* @return array
*/
protected function getPageHeaders()
{
$headers = ['link rel="stylesheet" type="text/css" href="' . $this->c->PUBLIC_URL . '/style/' . $this->c->user->style . '/style.css' . '"'];
if ($this->robots) {
$headers[] = 'meta name="robots" content="' . $this->robots . '"';
}
if ($this->canonical) {
$headers[] = 'link rel="canonical" href="' . $this->canonical . '"';
}
return $headers;
}
/**
* Возвращает HTTP заголовки страницы
* $this->httpHeaders
*
* @return array
*/
public function httpHeaders()
protected function getHttpHeaders()
{
$headers = $this->httpHeaders;
$headers = $this->a['httpHeaders'];
if (! empty($status = $this->httpStatus())) {
$headers[] = $status;
}
@ -121,6 +184,7 @@ abstract class Page
/**
* Возвращает HTTP статус страницы или null
*
* @return null|string
*/
protected function httpStatus()
@ -147,190 +211,25 @@ abstract class Page
}
/**
* Возвращает флаг готовности данных
* @return bool
* Дописывает в массив титула страницы новый элемент
* $this->titles
*
* @param string @val
*/
public function isReady()
public function setTitles($val)
{
return ! empty($this->data);
}
/**
* Возвращает имя шаблона
* @return string
*/
public function getNameTpl()
{
return $this->nameTpl;
}
/**
* Возвращает данные для шаблона
* @return array
*/
public function getData()
{
return [
'pageTitle' => $this->pageTitle(),
'pageHeaders' => $this->pageHeaders(),
'fTitle' => $this->config['o_board_title'],
'fDescription' => $this->config['o_board_desc'],
'fNavigation' => $this->fNavigation(),
'fIndex' => $this->index,
'fAnnounce' => $this->fAnnounce(),
'fRootLink' => $this->c->Router->link('Index'),
'fIswev' => $this->getIswev(),
] + $this->data;
}
/**
* Возврат info, success, warning, error, validation информации
* @return array
*/
protected function getIswev()
{
if ($this->config['o_maintenance'] == '1' && $this->c->user->isAdmin) {
$this->iswev['w']['maintenance'] = __('Maintenance mode enabled', $this->c->Router->link('AdminOptions', ['#' => 'maintenance']));
}
return $this->iswev;
}
/**
* Установка info, success, warning, error, validation информации из вне
* @param array $iswev
* @return Page
*/
public function setIswev(array $iswev)
{
$this->iswev = $iswev;
return $this;
}
/**
* Формирует title страницы
* @param array $titles
* @return string
*/
protected function pageTitle(array $titles = [])
{
if (empty($titles)) {
$titles = $this->titles;
}
$titles[] = $this->config['o_board_title'];
return implode(__('Title separator'), $titles);
}
/**
* Генерация массива заголовков страницы
* @return array
*/
protected function pageHeaders()
{
$headers = ['link rel="stylesheet" type="text/css" href="' . $this->c->PUBLIC_URL . '/style/' . $this->c->user->style . '/style.css' . '"'];
if ($this->robots) {
$headers[] = 'meta name="robots" content="' . $this->robots . '"';
}
if ($this->canonical) {
$headers[] = 'link rel="canonical" href="' . $this->canonical . '"';
}
return $headers;
}
/**
* Возвращает текст объявления или null
* @return null|string
*/
protected function fAnnounce()
{
return empty($this->config['o_announcement']) ? null : $this->config['o_announcement_message'];
}
/**
* Возвращает массив ссылок с описанием для построения навигации
* @return array
*/
protected function fNavigation()
{
$user = $this->c->user;
$r = $this->c->Router;
$nav = [
'index' => [$r->link('Index'), __('Index')]
];
if ($user->gReadBoard == '1' && $user->gViewUsers == '1') {
$nav['userlist'] = [$r->link('Userlist'), __('User list')];
}
if ($this->config['o_rules'] == '1' && (! $user->isGuest || $user->gReadBoard == '1' || $this->config['o_regs_allow'] == '1')) {
$nav['rules'] = [$r->link('Rules'), __('Rules')];
}
if ($user->gReadBoard == '1' && $user->gSearch == '1') {
$nav['search'] = [$r->link('Search'), __('Search')];
}
if ($user->isGuest) {
$nav['register'] = [$r->link('Register'), __('Register')];
$nav['login'] = [$r->link('Login'), __('Login')];
if (empty($this->a['titles'])) {
$this->a['titles'] = [$val];
} else {
$nav['profile'] = [$r->link('User', [
'id' => $user->id,
'name' => $user->username,
]), __('Profile')];
// New PMS
if ($this->config['o_pms_enabled'] == '1' && ($user->isAdmin || $user->messagesNew > 0)) { //????
$nav['pmsnew'] = ['pmsnew.php', __('PM')]; //'<li id="nav"'.((PUN_ACTIVE_PAGE == 'pms_new' || $user['messages_new'] > 0) ? ' class="isactive"' : '').'><a href="pmsnew.php">'.__('PM').(($user['messages_new'] > 0) ? ' (<span'.((empty($this->config['o_pms_flasher']) || PUN_ACTIVE_PAGE == 'pms_new') ? '' : ' class="remflasher"' ).'>'.$user['messages_new'].'</span>)' : '').'</a></li>';
}
// New PMS
if ($user->isAdmMod) {
$nav['admin'] = [$r->link('Admin'), __('Admin')];
}
$nav['logout'] = [$r->link('Logout', [
'token' => $this->c->Csrf->create('Logout'),
]), __('Logout')];
$this->a['titles'][] = $val;
}
if ($user->gReadBoard == '1' && $this->config['o_additional_navlinks'] != '') {
// position|name|link[|id]\n
if (preg_match_all('%^(\d+)\|([^\|\n\r]+)\|([^\|\n\r]+)(?:\|([^\|\n\r]+))?$%m', $this->config['o_additional_navlinks']."\n", $matches)) {
$k = count($matches[0]);
for ($i = 0; $i < $k; ++$i) {
if (empty($matches[4][$i])) {
$matches[4][$i] = 'extra' . $i;
}
if (isset($nav[$matches[4][$i]])) {
$nav[$matches[4][$i]] = [$matches[3][$i], $matches[2][$i]];
} else {
$nav = array_merge(
array_slice($nav, 0, $matches[1][$i]),
[$matches[4][$i] => [$matches[3][$i], $matches[2][$i]]],
array_slice($nav, $matches[1][$i])
);
}
}
}
}
return $nav;
}
/**
* Возращает данные для управления обработкой пользователей онлайн
* @param bool $short
* @return bool|array
*/
public function getDataForOnline($short = false)
{
return $short
? null !== $this->onlinePos
: [$this->onlinePos, $this->onlineType, $this->onlineFilter];
}
/**
* Возвращает размер в байтах, Кбайтах, ...
*
* @param int $size
*
* @return string
*/
protected function size($size)
@ -346,8 +245,10 @@ abstract class Page
/**
* Возвращает число в формате языка текущего пользователя
*
* @param mixed $number
* @param int $decimals
*
* @return string
*/
protected function number($number, $decimals = 0)
@ -357,15 +258,16 @@ abstract class Page
: 'not a number';
}
/**
* Возвращает время в формате текущего пользователя
*
* @param int|string $timestamp
* @param bool $dateOnly
* @param string $dateFormat
* @param string $timeFormat
* @param bool $timeOnly
* @param bool $noText
*
* @return string
*/
protected function time($timestamp, $dateOnly = false, $dateFormat = null, $timeFormat = null, $timeOnly = false, $noText = false)
@ -380,10 +282,10 @@ abstract class Page
$timestamp += $diff;
if (null === $dateFormat) {
$dateFormat = $this->c->DATE_FORMATS[$user->dateFormat];
$dateFormat = $this->c->DATE_FORMATS[$user->date_format];
}
if(null === $timeFormat) {
$timeFormat = $this->c->TIME_FORMATS[$user->timeFormat];
$timeFormat = $this->c->TIME_FORMATS[$user->time_format];
}
$date = gmdate($dateFormat, $timestamp);
@ -406,29 +308,4 @@ abstract class Page
return $date . ' ' . gmdate($timeFormat, $timestamp);
}
}
/**
* Выполняет цензуру при необходимости
* @param string $str
* @return string
*/
protected function censor($str)
{
if ($this->config['o_censoring'] == '1') {
return (string) preg_replace($this->c->censoring[0], $this->c->censoring[1], $str);
} else {
return $str;
}
}
/**
* Заглушка
* @param string $name
* @param array $arguments
* @throws \RuntimeException
*/
public function __call($name, array $arguments)
{
throw new RuntimeException("'{$name}' method not found.");
}
}

View file

@ -0,0 +1,90 @@
<?php
namespace ForkBB\Models\Pages;
use ForkBB\Core\Container;
use ForkBB\Models\Page;
abstract class Admin extends Page
{
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
{
parent::__construct($container);
$this->aIndex = 'index'; # string Указатель на активный пункт навигации в меню админки
$this->fIndex = 'admin';
$this->onlinePos = 'admin';
$this->robots = 'noindex, nofollow';
$container->Lang->load('admin');
}
/**
* Подготовка страницы к отображению
*/
public function prepare()
{
$this->aNavigation = $this->aNavigation();
parent::prepare();
}
/**
* Возвращает массив ссылок с описанием для построения навигации админки
*
* @return array
*/
protected function aNavigation()
{
$user = $this->c->user;
$r = $this->c->Router;
$nav = [
'Moderator menu' => [
'index' => [$r->link('Admin'), __('Admin index')],
'users' => ['admin_users.php', __('Users')],
],
];
if ($user->isAdmin || $user->g_mod_ban_users == '1') {
$nav['Moderator menu']['bans'] = ['admin_bans.php', __('Bans')];
}
if ($user->isAdmin || $this->c->config->o_report_method == '0' || $this->c->config->o_report_method == '2') {
$nav['Moderator menu']['reports'] = ['admin_reports.php', __('Reports')];
}
if ($user->isAdmin) {
$nav['Admin menu'] = [
'options' => ['admin_options.php', __('Admin options')],
'permissions' => ['admin_permissions.php', __('Permissions')],
'categories' => ['admin_categories.php', __('Categories')],
'forums' => ['admin_forums.php', __('Forums')],
'groups' => [$r->link('AdminGroups'), __('User groups')],
'censoring' => ['admin_censoring.php', __('Censoring')],
'maintenance' => ['admin_maintenance.php', __('Maintenance')]
];
}
return $nav;
}
/**
* Возвращает title страницы
* $this->pageTitle
*
* @param array $titles
*
* @return string
*/
protected function getPageTitle(array $titles = [])
{
if (empty($titles)) {
$titles = $this->titles;
}
$titles[] = __('Admin title');
return parent::getPageTitle($titles);
}
}

View file

@ -1,105 +0,0 @@
<?php
namespace ForkBB\Models\Pages\Admin;
use ForkBB\Core\Container;
use ForkBB\Models\Pages\Page;
abstract class Admin extends Page
{
/**
* Указатель на активный пункт навигации админки
* @var string
*/
protected $adminIndex;
/**
* Указатель на активный пункт навигации
* @var string
*/
protected $index = 'admin';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var string
*/
protected $onlinePos = 'admin';
/**
* Переменная для meta name="robots"
* @var string
*/
protected $robots = 'noindex, nofollow';
/**
* Конструктор
* @param Container $container
*/
public function __construct(Container $container)
{
parent::__construct($container);
$container->Lang->load('admin');
}
/**
* Возвращает данные для шаблона
* @return array
*/
public function getData()
{
$data = parent::getData();
$data['aNavigation'] = $this->aNavigation();
$data['aIndex'] = $this->adminIndex;
return $data;
}
/**
* Формирует title страницы
* @param array $titles
* @return string
*/
protected function pageTitle(array $titles = [])
{
$titles = $this->titles;
$titles[] = __('Admin title');
return parent::pageTitle($titles);
}
/**
* Возвращает массив ссылок с описанием для построения навигации админки
* @return array
*/
protected function aNavigation()
{
$user = $this->c->user;
$r = $this->c->Router;
$nav = [
'Moderator menu' => [
'index' => [$r->link('Admin'), __('Admin index')],
'users' => ['admin_users.php', __('Users')],
],
];
if ($user->isAdmin || $user->gModBanUsers == '1') {
$nav['Moderator menu']['bans'] = ['admin_bans.php', __('Bans')];
}
if ($user->isAdmin || $this->config['o_report_method'] == '0' || $this->config['o_report_method'] == '2') {
$nav['Moderator menu']['reports'] = ['admin_reports.php', __('Reports')];
}
if ($user->isAdmin) {
$nav['Admin menu'] = [
'options' => ['admin_options.php', __('Admin options')],
'permissions' => ['admin_permissions.php', __('Permissions')],
'categories' => ['admin_categories.php', __('Categories')],
'forums' => ['admin_forums.php', __('Forums')],
'groups' => [$r->link('AdminGroups'), __('User groups')],
'censoring' => ['admin_censoring.php', __('Censoring')],
'maintenance' => ['admin_maintenance.php', __('Maintenance')]
];
}
return $nav;
}
}

View file

@ -4,21 +4,10 @@ namespace ForkBB\Models\Pages\Admin;
use ForkBB\Core\Container;
use ForkBB\Core\Validator;
use ForkBB\Models\Pages\Admin;
class Groups extends Admin
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'admin/groups';
/**
* Указатель на активный пункт навигации админки
* @var string
*/
protected $adminIndex = 'groups';
/**
* Массив групп
* @var array
@ -45,6 +34,7 @@ class Groups extends Admin
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
@ -66,6 +56,7 @@ class Groups extends Admin
}
}
}
$this->aIndex = 'groups';
}
/**
@ -84,6 +75,7 @@ class Groups extends Admin
/**
* Подготавливает данные для шаблона
*
* @return Page
*/
public function view()
@ -109,23 +101,23 @@ class Groups extends Admin
$this->c->Lang->load('admin_groups');
$this->data = [
'formActionNew' => $this->c->Router->link('AdminGroupsNew'),
'formTokenNew' => $this->c->Csrf->create('AdminGroupsNew'),
'formActionDefault' => $this->c->Router->link('AdminGroupsDefault'),
'formTokenDefault' => $this->c->Csrf->create('AdminGroupsDefault'),
'defaultGroup' => $this->config['o_default_user_group'],
'groupsNew' => $groupsNew,
'groupsDefault' => $groupsDefault,
'groupsList' => $groupsList,
'tabindex' => 0,
];
$this->nameTpl = 'admin/groups';
$this->formActionNew = $this->c->Router->link('AdminGroupsNew');
$this->formTokenNew = $this->c->Csrf->create('AdminGroupsNew');
$this->formActionDefault = $this->c->Router->link('AdminGroupsDefault');
$this->formTokenDefault = $this->c->Csrf->create('AdminGroupsDefault');
$this->defaultGroup = $this->c->config->o_default_user_group;
$this->groupsNew = $groupsNew;
$this->groupsDefault = $groupsDefault;
$this->groupsList = $groupsList;
$this->tabindex = 0;
return $this;
}
/**
* Устанавливает группу по умолчанию
*
* @return Page
*/
public function defaultPost()
@ -138,18 +130,20 @@ class Groups extends Admin
]);
if (! $v->validation($_POST)) {
$this->iswev = $v->getErrors();
$this->fIswev = $v->getErrors();
return $this->view();
}
$this->c->DB->exec('UPDATE ::config SET conf_value=?s:id WHERE conf_name=\'o_default_user_group\'', [':id' => $v->defaultgroup]);
$this->c->{'config update'};
return $this->c->Redirect->setPage('AdminGroups')->setMessage(__('Default group redirect'));
$this->c->config->o_default_user_group = $v->defaultgroup;
$this->c->config->save();
return $this->c->Redirect->page('AdminGroups')->message(__('Default group redirect'));
}
/**
* Подготавливает данные для создание группы
* Создает новую группу
*
* @param array $args
*
* @return Page
*/
public function newPost(array $args)
@ -163,7 +157,7 @@ class Groups extends Admin
]);
if (! $v->validation($_POST)) {
$this->iswev = $v->getErrors();
$this->fIswev = $v->getErrors();
return $this->view();
} else {
return $this->edit(['id' => $v->basegroup, '_new' => true]);
@ -175,7 +169,9 @@ class Groups extends Admin
/**
* Подготавливает данные для шаблона редактирования группы
*
* @param array $args
*
* @return Page
*/
public function edit(array $args)
@ -203,20 +199,20 @@ class Groups extends Admin
$this->c->Lang->load('admin_groups');
$this->data = [
'formAction' => $this->c->Router->link($marker, $vars),
'formToken' => $this->c->Csrf->create($marker, $vars),
'form' => $this->viewForm($id, $groups[$args['id']]),
'warn' => empty($groups[$args['id']]['g_moderator']) ? null : __('Moderator info'),
'tabindex' => 0,
];
$this->formAction = $this->c->Router->link($marker, $vars);
$this->formToken = $this->c->Csrf->create($marker, $vars);
$this->form = $this->viewForm($id, $groups[$args['id']]);
$this->warn = empty($groups[$args['id']]['g_moderator']) ? null : __('Moderator info');
$this->tabindex = 0;
return $this;
}
/**
* Запись данных по новой/измененной группе
*
* @param array $args
*
* @return Page
*/
public function editPost(array $args)
@ -274,7 +270,7 @@ class Groups extends Admin
]);
if (! $v->validation($_POST)) {
$this->iswev = $v->getErrors();
$this->fIswev = $v->getErrors();
$args['_data'] = $v->getData();
return $this->edit($args);
}
@ -334,8 +330,8 @@ class Groups extends Admin
$this->c->Cache->delete('forums_mark');
return $this->c->Redirect
->setPage('AdminGroups')
->setMessage($id === -1 ? __('Group added redirect') : __('Group edited redirect'));
->page('AdminGroups')
->message($id === -1 ? __('Group added redirect') : __('Group edited redirect'));
}
/**
@ -397,7 +393,7 @@ class Groups extends Admin
$y = __('Yes');
$n = __('No');
if ($id !== $this->c->GROUP_GUEST && $id != $this->config['o_default_user_group']) {
if ($id !== $this->c->GROUP_GUEST && $id != $this->c->config->o_default_user_group) {
$form['g_moderator'] = [
'type' => 'radio',
'value' => isset($data['g_moderator']) ? $data['g_moderator'] : 0,

View file

@ -2,32 +2,24 @@
namespace ForkBB\Models\Pages\Admin;
use ForkBB\Models\Pages\Admin;
class Index extends Admin
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'admin/index';
/**
* Указатель на активный пункт навигации админки
* @var string
*/
protected $adminIndex = 'index';
/**
* Подготавливает данные для шаблона
*
* @return Page
*/
public function index()
{
$this->c->Lang->load('admin_index');
$this->data = [
'revision' => $this->config['i_fork_revision'],
'linkStat' => $this->c->Router->link('AdminStatistics'),
];
$this->titles[] = __('Admin index');
$this->nameTpl = 'admin/index';
$this->titles = __('Admin index');
$this->revision = $this->c->config->i_fork_revision;
$this->linkStat = $this->c->Router->link('AdminStatistics');
return $this;
}
}

View file

@ -2,22 +2,13 @@
namespace ForkBB\Models\Pages\Admin;
use ForkBB\Models\Pages\Admin;
class Statistics extends Admin
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'admin/statistics';
/**
* Указатель на активный пункт навигации админки
* @var string
*/
protected $adminIndex = 'index';
/**
* phpinfo
*
* @return Page|null
*/
public function info()
@ -33,14 +24,17 @@ class Statistics extends Admin
/**
* Подготавливает данные для шаблона
*
* @return Page
*/
public function statistics()
{
$this->c->Lang->load('admin_index');
$this->titles[] = __('Server statistics');
$this->data['isAdmin'] = $this->c->user->isAdmin;
$this->data['linkInfo'] = $this->c->Router->link('AdminInfo');
$this->nameTpl = 'admin/statistics';
$this->titles = __('Server statistics');
$this->isAdmin = $this->c->user->isAdmin;
$this->linkInfo = $this->c->Router->link('AdminInfo');
// Get the server load averages (if possible)
if (@file_exists('/proc/loadavg') && is_readable('/proc/loadavg')) {
@ -57,38 +51,38 @@ class Statistics extends Admin
}
$ave = @explode(' ', $ave);
$this->data['serverLoad'] = isset($ave[2]) ? $ave[0].' '.$ave[1].' '.$ave[2] : __('Not available');
$this->serverLoad = isset($ave[2]) ? $ave[0].' '.$ave[1].' '.$ave[2] : __('Not available');
} elseif (!in_array(PHP_OS, array('WINNT', 'WIN32')) && preg_match('%averages?: ([\d\.]+),?\s+([\d\.]+),?\s+([\d\.]+)%i', @exec('uptime'), $ave)) {
$this->data['serverLoad'] = $ave[1].' '.$ave[2].' '.$ave[3];
$this->serverLoad = $ave[1].' '.$ave[2].' '.$ave[3];
} else {
$this->data['serverLoad'] = __('Not available');
$this->serverLoad = __('Not available');
}
// Get number of current visitors
$this->data['numOnline'] = $this->c->DB->query('SELECT COUNT(user_id) FROM ::online WHERE idle=0')->fetchColumn();
$this->numOnline = $this->c->DB->query('SELECT COUNT(user_id) FROM ::online WHERE idle=0')->fetchColumn();
$stat = $this->c->DB->statistics();
$this->data['dbVersion'] = $stat['db'];
$this->data['tSize'] = $this->size($stat['size']);
$this->data['tRecords'] = $this->number($stat['records']);
$this->dbVersion = $stat['db'];
$this->tSize = $this->size($stat['size']);
$this->tRecords = $this->number($stat['records']);
unset($stat['db'], $stat['size'], $stat['records']);
$this->data['tOther'] = $stat;
$this->tOther = $stat;
// Check for the existence of various PHP opcode caches/optimizers
if (function_exists('mmcache')) {
$this->data['accelerator'] = '<a href="http://' . __('Turck MMCache link') . '">' . __('Turck MMCache') . '</a>';
$this->accelerator = '<a href="http://' . __('Turck MMCache link') . '">' . __('Turck MMCache') . '</a>';
} elseif (isset($_PHPA)) {
$this->data['accelerator'] = '<a href="http://' . __('ionCube PHP Accelerator link') . '">' . __('ionCube PHP Accelerator') . '</a>';
$this->accelerator = '<a href="http://' . __('ionCube PHP Accelerator link') . '">' . __('ionCube PHP Accelerator') . '</a>';
} elseif (ini_get('apc.enabled')) {
$this->data['accelerator'] ='<a href="http://' . __('Alternative PHP Cache (APC) link') . '">' . __('Alternative PHP Cache (APC)') . '</a>';
$this->accelerator ='<a href="http://' . __('Alternative PHP Cache (APC) link') . '">' . __('Alternative PHP Cache (APC)') . '</a>';
} elseif (ini_get('zend_optimizer.optimization_level')) {
$this->data['accelerator'] = '<a href="http://' . __('Zend Optimizer link') . '">' . __('Zend Optimizer') . '</a>';
$this->accelerator = '<a href="http://' . __('Zend Optimizer link') . '">' . __('Zend Optimizer') . '</a>';
} elseif (ini_get('eaccelerator.enable')) {
$this->data['accelerator'] = '<a href="http://' . __('eAccelerator link') . '">' . __('eAccelerator') . '</a>';
$this->accelerator = '<a href="http://' . __('eAccelerator link') . '">' . __('eAccelerator') . '</a>';
} elseif (ini_get('xcache.cacher')) {
$this->data['accelerator'] = '<a href="http://' . __('XCache link') . '">' . __('XCache') . '</a>';
$this->accelerator = '<a href="http://' . __('XCache link') . '">' . __('XCache') . '</a>';
} else {
$this->data['accelerator'] = __('NA');
$this->accelerator = __('NA');
}
return $this;

View file

@ -4,62 +4,43 @@ namespace ForkBB\Models\Pages;
use ForkBB\Core\Validator;
use ForkBB\Core\Exceptions\MailException;
use ForkBB\Models\Page;
use ForkBB\Models\User;
class Auth extends Page
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'login';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = 'login';
/**
* Указатель на активный пункт навигации
* @var string
*/
protected $index = 'login';
/**
* Для передачи User из vCheckEmail() в forgetPost()
* @var User
*/
protected $tmpUser;
/**
* Переменная для meta name="robots"
* @var string
*/
protected $robots = 'noindex';
protected $tmpUser; //????
/**
* Выход пользователя
*
* @param array $args
* @retrun Page
*
* @return Page
*/
public function logout($args)
{
if (empty($args['token']) || ! $this->c->Csrf->verify($args['token'], 'Logout', $args)) {
return $this->c->Redirect->setPage('Index')->setMessage(__('Bad token'));
return $this->c->Redirect->page('Index')->message(__('Bad token'));
}
$this->c->UserCookie->deleteUserCookie();
$this->c->Cookie->deleteUser();
$this->c->Online->delete($this->c->user);
$this->c->UserMapper->updateLastVisit($this->c->user);
$this->c->user->updateLastVisit();
$this->c->Lang->load('auth');
return $this->c->Redirect->setPage('Index')->setMessage(__('Logout redirect'));
return $this->c->Redirect->page('Index')->message(__('Logout redirect'));
}
/**
* Подготовка данных для страницы входа на форум
*
* @param array $args
*
* @return Page
*/
public function login(array $args)
@ -74,24 +55,25 @@ class Auth extends Page
$args['_redirect'] = $this->c->Router->validate($args['_redirect'], 'Index');
}
$this->titles[] = __('Login');
$this->data = [
'formAction' => $this->c->Router->link('Login'),
'formToken' => $this->c->Csrf->create('Login'),
'forgetLink' => $this->c->Router->link('Forget'),
'regLink' => $this->config['o_regs_allow'] == '1'
? $this->c->Router->link('Register')
: null,
'username' => $args['_username'],
'redirect' => $args['_redirect'],
'save' => ! empty($args['_save'])
];
$this->fIndex = 'login';
$this->nameTpl = 'login';
$this->onlinePos = 'login';
$this->robots = 'noindex';
$this->titles = __('Login');
$this->formAction = $this->c->Router->link('Login');
$this->formToken = $this->c->Csrf->create('Login');
$this->forgetLink = $this->c->Router->link('Forget');
$this->regLink = $this->c->config->o_regs_allow == '1' ? $this->c->Router->link('Register') : null;
$this->username = $args['_username'];
$this->redirect = $args['_redirect'];
$this->save = ! empty($args['_save']);
return $this;
}
/**
* Вход на форум
*
* @return Page
*/
public function loginPost()
@ -109,9 +91,9 @@ class Auth extends Page
]);
if ($v->validation($_POST)) {
return $this->c->Redirect->setUrl($v->redirect)->setMessage(__('Login redirect'));
return $this->c->Redirect->url($v->redirect)->message(__('Login redirect'));
} else {
$this->iswev = $v->getErrors();
$this->fIswev = $v->getErrors();
return $this->login([
'_username' => $v->username,
'_redirect' => $v->redirect,
@ -122,27 +104,28 @@ class Auth extends Page
/**
* Проверка по базе и вход на форум
*
* @param Validator $v
* @param string $password
*
* @return array
*/
public function vLoginProcess(Validator $v, $password)
{
$error = false;
if (! empty($v->getErrors())) {
} elseif (! ($user = $this->c->UserMapper->getUser($v->username, 'username')) instanceof User) {
} elseif (! ($user = $this->c->ModelUser->load($v->username, 'username')) instanceof User) {
$error = __('Wrong user/pass');
} elseif ($user->isUnverified) {
$error = [__('Account is not activated'), 'w'];
} else {
$authorized = false;
$hash = $user->password;
$update = [];
// For FluxBB by Visman 1.5.10.74 and above
if (strlen($hash) == 40) {
if (hash_equals($hash, sha1($password . $this->c->SALT1))) {
$hash = password_hash($password, PASSWORD_DEFAULT);
$update['password'] = $hash;
$user->password = $hash;
$authorized = true;
}
} else {
@ -154,16 +137,16 @@ class Auth extends Page
} else {
// перезаписываем ip админа и модератора - Visman
if ($user->isAdmMod
&& $this->config['o_check_ip']
&& $user->registrationIp != $this->c->user->ip
&& $this->c->config->o_check_ip
&& $user->registration_ip != $this->c->user->ip
) {
$update['registration_ip'] = $this->c->user->ip;
$user->registration_ip = $this->c->user->ip;
}
// изменения юзера в базе
$this->c->UserMapper->updateUser($user->id, $update);
$user->update();
$this->c->Online->delete($this->c->user);
$this->c->UserCookie->setUserCookie($user->id, $hash, $v->save);
$this->c->Cookie->setUser($user);
}
}
return [$password, $error];
@ -171,32 +154,34 @@ class Auth extends Page
/**
* Подготовка данных для страницы восстановления пароля
*
* @param array $args
*
* @return Page
*/
public function forget(array $args)
{
$this->nameTpl = 'passphrase_reset';
$this->onlinePos = 'passphrase_reset';
$this->c->Lang->load('auth');
if (! isset($args['_email'])) {
$args['_email'] = '';
}
$this->c->Lang->load('auth');
$this->titles[] = __('Passphrase reset');
$this->data = [
'formAction' => $this->c->Router->link('Forget'),
'formToken' => $this->c->Csrf->create('Forget'),
'email' => $args['_email'],
];
$this->fIndex = 'login';
$this->nameTpl = 'passphrase_reset';
$this->onlinePos = 'passphrase_reset';
$this->robots = 'noindex';
$this->titles = __('Passphrase reset');
$this->formAction = $this->c->Router->link('Forget');
$this->formToken = $this->c->Csrf->create('Forget');
$this->email = $args['_email'];
return $this;
}
/**
* Отправка письма для восстановления пароля
*
* @return Page
*/
public function forgetPost()
@ -213,7 +198,7 @@ class Auth extends Page
]);
if (! $v->validation($_POST)) {
$this->iswev = $v->getErrors();
$this->fIswev = $v->getErrors();
return $this->forget([
'_email' => $v->email,
]);
@ -224,7 +209,7 @@ class Auth extends Page
$link = $this->c->Router->link('ChangePassword', ['email' => $v->email, 'key' => $key, 'hash' => $hash]);
$tplData = [
'fRootLink' => $this->c->Router->link('Index'),
'fMailer' => __('Mailer', $this->config['o_board_title']),
'fMailer' => __('Mailer', $this->c->config->o_board_title),
'username' => $this->tmpUser->username,
'link' => $link,
];
@ -235,7 +220,7 @@ class Auth extends Page
->setFolder($this->c->DIR_LANG)
->setLanguage($this->tmpUser->language)
->setTo($v->email, $this->tmpUser->username)
->setFrom($this->config['o_webmaster_email'], __('Mailer', $this->config['o_board_title']))
->setFrom($this->c->config->o_webmaster_email, __('Mailer', $this->c->config->o_board_title))
->setTpl('passphrase_reset.tpl', $tplData)
->send();
} catch (MailException $e) {
@ -243,33 +228,42 @@ class Auth extends Page
}
if ($isSent) {
$this->c->UserMapper->updateUser($this->tmpUser->id, ['activate_string' => $key, 'last_email_sent' => time()]);
return $this->c->Message->message(__('Forget mail', $this->config['o_admin_email']), false, 200);
$this->tmpUser->activate_string = $key;
$this->tmpUser->last_email_sent = time();
$this->tmpUser->update();
return $this->c->Message->message(__('Forget mail', $this->c->config->o_admin_email), false, 200);
} else {
return $this->c->Message->message(__('Error mail', $this->config['o_admin_email']), true, 200);
return $this->c->Message->message(__('Error mail', $this->c->config->o_admin_email), true, 200);
}
}
/**
* Дополнительная проверка email
*
* @param Validator $v
* @param string $username
* @param string $email
*
* @return array
*/
public function vCheckEmail(Validator $v, $email)
{
$error = false;
// есть ошибки
if (! empty($v->getErrors())) {
return [$email, false];
}
$error = false;
$user = $this->c->ModelUser;
$user->__email = $email;
// email забанен
} elseif ($this->c->CheckBans->isBanned(null, $email) > 0) {
if ($this->c->bans->isBanned($user) > 0) {
$error = __('Banned email');
// нет пользователя с таким email
} elseif (! ($user = $this->c->UserMapper->getUser($email, 'email')) instanceof User) {
} elseif (! $user->load($email, 'email') instanceof User) {
$error = __('Invalid email');
// за последний час уже был запрос на этот email
} elseif (! empty($user->lastEmailSent) && time() - $user->lastEmailSent < 3600) {
$error = [__('Email flood', (int) (($user->lastEmailSent + 3600 - time()) / 60)), 'e'];
} elseif (! empty($user->last_email_sent) && time() - $user->last_email_sent < 3600) {
$error = [__('Email flood', (int) (($user->last_email_sent + 3600 - time()) / 60)), 'e'];
} else {
$this->tmpUser = $user;
}
@ -278,23 +272,23 @@ class Auth extends Page
/**
* Подготовка данных для формы изменения пароля
*
* @param array $args
*
* @return Page
*/
public function changePass(array $args)
{
$this->nameTpl = 'change_passphrase';
$this->onlinePos = 'change_passphrase';
if (isset($args['_ok'])) {
unset($args['_ok']);
if (isset($args['_user'])) {
$user = $args['_user'];
unset($args['_user']);
} else {
// что-то пошло не так
if (! hash_equals($args['hash'], $this->c->Secury->hash($args['email'] . $args['key']))
|| ! ($user = $this->c->UserMapper->getUser($args['email'], 'email')) instanceof User
|| empty($user->activateString)
|| $user->activateString{0} !== 'p'
|| ! hash_equals($user->activateString, $args['key'])
|| ! ($user = $this->c->ModelUser->load($args['email'], 'email')) instanceof User
|| empty($user->activate_string)
|| $user->activate_string{0} !== 'p'
|| ! hash_equals($user->activate_string, $args['key'])
) {
return $this->c->Message->message(__('Bad request'), false);
}
@ -303,33 +297,39 @@ class Auth extends Page
$this->c->Lang->load('auth');
if ($user->isUnverified) {
$this->c->UserMapper->updateUser($user->id, ['group_id' => $this->config['o_default_user_group'], 'email_confirmed' => 1]);
$user->group_id = $this->c->config->o_default_user_group;
$user->email_confirmed = 1;
$user->update();
$this->c->{'users_info update'};
$this->iswev['i'][] = __('Account activated');
$this->a['fIswev']['i'][] = __('Account activated');
}
$this->titles[] = __('Change pass');
$this->data = [
'formAction' => $this->c->Router->link('ChangePassword', $args),
'formToken' => $this->c->Csrf->create('ChangePassword', $args),
];
$this->fIndex = 'login';
$this->nameTpl = 'change_passphrase';
$this->onlinePos = 'change_passphrase';
$this->robots = 'noindex';
$this->titles = __('Passphrase reset');
$this->formAction = $this->c->Router->link('ChangePassword', $args);
$this->formToken = $this->c->Csrf->create('ChangePassword', $args);
return $this;
}
/**
* Смена пароля
*
* @param array $args
*
* @return Page
*/
public function changePassPost(array $args)
{
// что-то пошло не так
if (! hash_equals($args['hash'], $this->c->Secury->hash($args['email'] . $args['key']))
|| ! ($user = $this->c->UserMapper->getUser($args['email'], 'email')) instanceof User
|| empty($user->activateString)
|| $user->activateString{0} !== 'p'
|| ! hash_equals($user->activateString, $args['key'])
|| ! ($user = $this->c->ModelUser->load($args['email'], 'email')) instanceof User
|| empty($user->activate_string)
|| $user->activate_string{0} !== 'p'
|| ! hash_equals($user->activate_string, $args['key'])
) {
return $this->c->Message->message(__('Bad request'), false);
}
@ -349,15 +349,18 @@ class Auth extends Page
]);
if (! $v->validation($_POST)) {
$this->iswev = $v->getErrors();
$args['_ok'] = true;
$this->fIswev = $v->getErrors();
$args['_user'] = $user;
return $this->changePass($args);
}
$data = $v->getData();
$this->c->UserMapper->updateUser($user->id, ['password' => password_hash($data['password'], PASSWORD_DEFAULT), 'email_confirmed' => 1, 'activate_string' => null]);
$user->password = password_hash($data['password'], PASSWORD_DEFAULT);
$user->email_confirmed = 1;
$user->activate_string = null;
$user->update();
$this->iswev['s'][] = __('Pass updated');
$this->a['fIswev']['s'][] = __('Pass updated');
return $this->login(['_redirect' => $this->c->Router->link('Index')]);
}
}

View file

@ -2,42 +2,41 @@
namespace ForkBB\Models\Pages;
use ForkBB\Models\Page;
use ForkBB\Models\User;
class Ban extends Page
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'ban';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = 'ban';
/**
* HTTP статус ответа для данной страницы
* @var int
*/
protected $httpStatus = 403;
/**
* Подготавливает данные для шаблона
* @param array $banned
*
* @param User $user
*
* @return Page
*/
public function ban(array $banned)
public function ban(User $user)
{
$this->titles[] = __('Info');
$ban = $user->banInfo;
if (! empty($banned['expire'])) {
$banned['expire'] = strtolower($this->time($banned['expire'], true));
if (! empty($ban['expire'])) {
$ban['expire'] = strtolower($this->time($ban['expire'], true));
}
$this->data = [
'banned' => $banned,
'adminEmail' => $this->config['o_admin_email'],
];
$this->httpStatus = 403;
$this->nameTpl = 'ban';
# $this->onlinePos = 'ban';
# $this->robots = 'noindex';
$this->titles = __('Info');
$this->ban = $ban;
$this->adminEmail = $this->c->config->o_admin_email;
return $this;
}
/**
* Подготовка страницы к отображению
*/
public function prepare()
{
}
}

View file

@ -6,22 +6,44 @@ trait CrumbTrait
{
/**
* Возвращает массив хлебных крошек
*
* @param mixed $args
*
* @return array
*/
protected function getCrumbs(...$args)
protected function crumbs(...$args)
{
$crumbs = [];
$active = true;
foreach ($args as $arg) {
if (isset($arg->forum_name)) {
while ($arg->id > 0) {
$this->titles = $arg->forum_name;
$crumbs[] = [
$this->c->Router->link('Forum', ['id' => $arg->id, 'name' => $arg->forum_name]),
$arg->forum_name,
$active,
];
$active = null;
$arg = $arg->parent;
}
} else {
$this->titles = (string) $arg;
$crumbs[] = [
null,
(string) $arg,
$active,
];
}
/*
if (is_array($arg)) {
$cur = array_shift($arg);
// массив разделов
if (is_array($cur)) {
$id = $arg[0];
while (true) {
$this->titles[] = $cur[$id]['forum_name'];
$this->titles = $cur[$id]['forum_name'];
$crumbs[] = [
$this->c->Router->link('Forum', ['id' => $id, 'name' => $cur[$id]['forum_name']]),
$cur[$id]['forum_name'],
@ -48,7 +70,7 @@ trait CrumbTrait
} else {
continue;
}
$this->titles[] = $name;
$this->titles = $name;
$crumbs[] = [
$this->c->Router->link($cur, $vars),
$name,
@ -57,13 +79,14 @@ trait CrumbTrait
}
// предположительно идет только название, без ссылки
} else {
$this->titles[] = (string) $arg;
$this->titles = (string) $arg;
$crumbs[] = [
null,
(string) $arg,
$active,
];
}
*/
$active = null;
}
// главная страница

View file

@ -2,36 +2,20 @@
namespace ForkBB\Models\Pages;
use ForkBB\Models\Page;
class Debug extends Page
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'layouts/debug';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = null;
/**
* Подготавливает данные для шаблона
*
* @return Page
*/
public function debug()
{
$this->data = [
'time' => $this->number(microtime(true) - $this->c->START, 3),
'numQueries' => $this->c->DB->getCount(),
'memory' => $this->size(memory_get_usage()),
'peak' => $this->size(memory_get_peak_usage()),
];
if ($this->c->DEBUG > 1) {
$total = 0;
$this->data['queries'] = array_map(
$this->queries = array_map(
function($a) use (&$total) {
$total += $a[1];
$a[1] = $this->number($a[1], 3);
@ -39,29 +23,36 @@ class Debug extends Page
},
$this->c->DB->getQueries()
);
$this->data['total'] = $this->number($total, 3);
$this->total = $this->number($total, 3);
} else {
$this->data['queries'] = null;
$this->queries = null;
}
$this->nameTpl = 'layouts/debug';
$this->onlinePos = null;
$this->numQueries = $this->c->DB->getCount();
$this->memory = $this->size(memory_get_usage());
$this->peak = $this->size(memory_get_peak_usage());
$this->time = $this->number(microtime(true) - $this->c->START, 3);
return $this;
}
/**
* Возвращает HTTP заголовки страницы
* @return array
* Подготовка страницы к отображению
*/
public function httpHeaders()
public function prepare()
{
return [];
}
/**
* Возвращает данные для шаблона
* Возвращает HTTP заголовки страницы
* $this->httpHeaders
*
* @return array
*/
public function getData()
protected function getHttpHeaders()
{
return $this->data;
return [];
}
}

View file

@ -2,23 +2,13 @@
namespace ForkBB\Models\Pages;
use ForkBB\Models\Page;
class Forum extends Page
{
use ForumsTrait;
use CrumbTrait;
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'forum';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = 'forum';
/**
* Подготовка данных для шаблона
* @param array $args
@ -29,41 +19,19 @@ class Forum extends Page
$this->c->Lang->load('forum');
$this->c->Lang->load('subforums');
list($fTree, $fDesc, $fAsc) = $this->c->forums;
// раздел отсутствует в доступных
if (empty($fDesc[$args['id']])) {
$forum = $this->c->forums->loadTree($args['id']);
if (empty($forum)) {
return $this->c->Message->message('Bad request');
}
$parent = isset($fDesc[$args['id']][0]) ? $fDesc[$args['id']][0] : 0;
$perm = $fTree[$parent][$args['id']];
// редирект, если раздел это ссылка
if (! empty($perm['redirect_url'])) {
return $this->c->Redirect->setUrl($perm['redirect_url']);
if (! empty($forum->redirect_url)) {
return $this->c->Redirect->url($forum->redirect_url);
}
$user = $this->c->user;
$vars = [
':fid' => $args['id'],
':uid' => $user->id,
':gid' => $user->groupId,
];
if ($user->isGuest) {
$sql = 'SELECT f.moderators, f.num_topics, f.sort_by, 0 AS is_subscribed FROM ::forums AS f WHERE f.id=?i:fid';
} else {
$sql = 'SELECT f.moderators, f.num_topics, f.sort_by, s.user_id AS is_subscribed, mof.mf_mark_all_read FROM ::forums AS f LEFT JOIN ::forum_subscriptions AS s ON (f.id=s.forum_id AND s.user_id=?i:uid) LEFT JOIN ::mark_of_forum AS mof ON (mof.uid=?i:uid AND f.id=mof.fid) WHERE f.id=?i:fid';
}
$curForum = $this->c->DB->query($sql, $vars)->fetch();
// нет данных по данному разделу
if (empty($curForum)) {
return $this->c->Message->message('Bad request'); //???? может в лог ошибок?
}
$page = isset($args['page']) ? (int) $args['page'] : 1;
if (empty($curForum['num_topics'])) {
if (empty($forum->num_topics)) {
// попытка открыть страницу которой нет
if ($page !== 1) {
return $this->c->Message->message('Bad request');
@ -73,16 +41,16 @@ class Forum extends Page
$offset = 0;
$topics = null;
} else {
$pages = ceil($curForum['num_topics'] / $user->dispTopics);
$pages = ceil($forum->num_topics / $user->disp_topics);
// попытка открыть страницу которой нет
if ($page < 1 || $page > $pages) {
return $this->c->Message->message('Bad request');
}
$offset = ($page - 1) * $user->dispTopics;
$offset = ($page - 1) * $user->disp_topics;
switch ($curForum['sort_by']) {
switch ($forum->sort_by) {
case 1:
$sortBy = 'posted DESC';
break;
@ -96,9 +64,9 @@ class Forum extends Page
}
$vars = [
':fid' => $args['id'],
':fid' => $args['id'],
':offset' => $offset,
':rows' => $user->dispTopics,
':rows' => $user->disp_topics,
];
$topics = $this->c->DB
->query("SELECT id FROM ::topics WHERE forum_id=?i:fid ORDER BY sticky DESC, {$sortBy}, id DESC LIMIT ?i:offset, ?i:rows", $vars)
@ -107,11 +75,11 @@ class Forum extends Page
if (! empty($topics)) {
$vars = [
':uid' => $user->id,
':uid' => $user->id,
':topics' => $topics,
];
if (! $user->isGuest && $this->config['o_show_dot'] == '1') {
if (! $user->isGuest && $this->c->config->o_show_dot == '1') {
$dots = $this->c->DB
->query('SELECT topic_id FROM ::posts WHERE poster_id=?i:uid AND topic_id IN (?ai:topics) GROUP BY topic_id', $vars)
->fetchAll(\PDO::FETCH_COLUMN);
@ -121,8 +89,8 @@ class Forum extends Page
}
if (! $user->isGuest) {
$lower = max((int) $user->uMarkAllRead, (int) $curForum['mf_mark_all_read']);
$upper = max($lower, (int) $user->lastVisit);
$lower = max((int) $user->u_mark_all_read, (int) $forum->mf_mark_all_read);
$upper = max($lower, (int) $user->last_visit);
}
if ($user->isGuest) {
@ -133,7 +101,7 @@ class Forum extends Page
$topics = $this->c->DB->query($sql, $vars)->fetchAll();
foreach ($topics as &$cur) {
$cur['subject'] = $this->censor($cur['subject']);
$cur['subject'] = $this->c->censorship->censor($cur['subject']);
// перенос темы
if ($cur['moved_to']) {
$cur['link'] = $this->c->Router->link('Topic', ['id' => $cur['moved_to'], 'name' => $cur['subject']]);
@ -144,7 +112,7 @@ class Forum extends Page
continue;
}
// страницы темы
$tPages = ceil(($cur['num_replies'] + 1) / $user->dispPosts);
$tPages = ceil(($cur['num_replies'] + 1) / $user->disp_posts);
if ($tPages > 1) {
$cur['pages'] = $this->c->Func->paginate($tPages, -1, 'Topic', ['id' => $cur['id'], 'name' => $cur['subject']]);
} else {
@ -153,7 +121,7 @@ class Forum extends Page
$cur['link'] = $this->c->Router->link('Topic', ['id' => $cur['id'], 'name' => $cur['subject']]);
$cur['link_last'] = $this->c->Router->link('ViewPost', ['id' => $cur['last_post_id']]);
$cur['views'] = $this->config['o_topic_views'] == '1' ? $this->number($cur['num_views']) : null;
$cur['views'] = $this->c->config->o_topic_views == '1' ? $this->number($cur['num_views']) : null;
$cur['replies'] = $this->number($cur['num_replies']);
$time = $cur['last_post'];
$cur['last_post'] = $this->time($cur['last_post']);
@ -182,24 +150,22 @@ class Forum extends Page
unset($cur);
}
$moders = empty($curForum['moderators']) ? [] : array_flip(unserialize($curForum['moderators']));
$newOn = $perm['post_topics'] == 1
|| (null === $perm['post_topics'] && $user->gPostTopics == 1)
$moders = empty($forum->moderators) ? [] : array_flip(unserialize($forum->moderators));
$newOn = $forum->post_topics == 1
|| (null === $forum->post_topics && $user->g_post_topics == 1)
|| $user->isAdmin
|| ($user->isAdmMod && isset($moders[$user->id]));
$this->onlinePos = 'forum-' . $args['id'];
$this->data = [
'forums' => $this->getForumsData($args['id']),
'topics' => $topics,
'crumbs' => $this->getCrumbs([$fDesc, $args['id']]),
'forumName' => $fDesc[$args['id']]['forum_name'],
'newTopic' => $newOn ? $this->c->Router->link('NewTopic', ['id' => $args['id']]) : null,
'pages' => $this->c->Func->paginate($pages, $page, 'Forum', ['id' => $args['id'], 'name' => $fDesc[$args['id']]['forum_name']]),
];
$this->canonical = $this->c->Router->link('Forum', ['id' => $args['id'], 'name' => $fDesc[$args['id']]['forum_name'], 'page' => $page]);
$this->fIndex = 'index';
$this->nameTpl = 'forum';
$this->onlinePos = 'forum-' . $args['id'];
$this->canonical = $this->c->Router->link('Forum', ['id' => $args['id'], 'name' => $forum->forum_name, 'page' => $page]);
$this->forums = $this->forumsData($args['id']);
$this->topics = $topics;
$this->crumbs = $this->crumbs($forum);
$this->forumName = $forum->forum_name;
$this->newTopic = $newOn ? $this->c->Router->link('NewTopic', ['id' => $args['id']]) : null;
$this->pages = $this->c->Func->paginate($pages, $page, 'Forum', ['id' => $args['id'], 'name' => $forum->forum_name]);
return $this;
}

View file

@ -6,88 +6,29 @@ trait ForumsTrait
{
/**
* Получение данных по разделам
* @param int $parent
*
* @param int $rootId
*
* @return array
*/
protected function getForumsData($parent = 0)
protected function forumsData($rootId = 0)
{
list($fTree, $fDesc, $fAsc) = $this->c->forums;
// раздел $parent не имеет подразделов для вывода или они не доступны
if (empty($fTree[$parent])) {
$root = $this->c->forums->loadTree($rootId);
if (empty($root)) {
return [];
}
$user = $this->c->user;
// текущие данные по подразделам
$vars = [
':id' => $user->id,
':forums' => array_slice($fAsc[$parent], 1),
];
if ($user->isGuest) {
$stmt = $this->c->DB->query('SELECT id, forum_desc, moderators, num_topics, num_posts, last_post, last_post_id, last_poster, last_topic FROM ::forums WHERE id IN (?ai:forums)', $vars);
} else {
$stmt = $this->c->DB->query('SELECT f.id, f.forum_desc, f.moderators, f.num_topics, f.num_posts, f.last_post, f.last_post_id, f.last_poster, f.last_topic, mof.mf_mark_all_read FROM ::forums AS f LEFT JOIN ::mark_of_forum AS mof ON (mof.uid=?i:id AND f.id=mof.fid) WHERE f.id IN (?ai:forums)', $vars);
}
$forums = [];
while ($cur = $stmt->fetch()) {
$forums[$cur['id']] = $cur;
}
// поиск новых
$new = [];
if (! $user->isGuest) {
// предварительная проверка разделов
$max = max((int) $user->lastVisit, (int) $user->uMarkAllRead);
foreach ($forums as $id => $cur) {
$t = max($max, (int) $cur['mf_mark_all_read']);
if ($cur['last_post'] > $t) {
$new[$id] = $t;
}
}
// проверка по темам
if (! empty($new)) {
$vars = [
':id' => $user->id,
':forums' => array_keys($new),
':max' => $max,
];
$stmt = $this->c->DB->query('SELECT t.forum_id, t.last_post FROM ::topics AS t LEFT JOIN ::mark_of_topic AS mot ON (mot.uid=?i:id AND mot.tid=t.id) WHERE t.forum_id IN(?ai:forums) AND t.last_post>?i:max AND t.moved_to IS NULL AND (mot.mt_last_visit IS NULL OR t.last_post>mot.mt_last_visit)', $vars);
$tmp = [];
while ($cur = $stmt->fetch()) {
if ($cur['last_post'] > $new[$cur['forum_id']]) {
$tmp[$cur['forum_id']] = true;
}
}
$new = $tmp;
}
}
$r = $this->c->Router;
// формированием таблицы разделов
$result = [];
foreach ($fTree[$parent] as $fId => $cur) {
// список подразделов
$subForums = [];
if (isset($fTree[$fId])) {
foreach ($fTree[$fId] as $f) {
$subForums[] = [
$r->link('Forum', [
'id' => $f['fid'],
'name' => $f['forum_name']
]),
$f['forum_name']
];
}
}
foreach ($root->subforums as $forumId => $forum) {
// модераторы
$moderators = [];
if (!empty($forums[$fId]['moderators'])) {
$mods = unserialize($forums[$fId]['moderators']);
if (! empty($forum->moderators)) {
$mods = unserialize($forum->moderators);
foreach ($mods as $name => $id) {
if ($user->gViewUsers == '1') {
if ($this->c->user->g_view_users == '1') {
$moderators[] = [
$r->link('User', [
'id' => $id,
@ -100,36 +41,49 @@ trait ForumsTrait
}
}
}
// список подразделов
$subForums = [];
foreach ($forum->subforums as $subId => $subforum) {
$subForums[] = [
$r->link('Forum', [
'id' => $subId,
'name' => $subforum->forum_name,
]),
$subforum->forum_name,
];
}
// статистика по разделам
$numT = 0;
$numP = 0;
$time = 0;
$postId = 0;
$poster = '';
$topic = '';
$fnew = false;
foreach ($fAsc[$fId] as $id) {
$fnew = $fnew || isset($new[$id]);
$numT += $forums[$id]['num_topics'];
$numP += $forums[$id]['num_posts'];
if ($forums[$id]['last_post'] > $time) {
$time = $forums[$id]['last_post'];
$postId = $forums[$id]['last_post_id'];
$poster = $forums[$id]['last_poster'];
$topic = $forums[$id]['last_topic'];
$numT = (int) $forum->num_topics;
$numP = (int) $forum->num_posts;
$time = (int) $forum->last_post;
$postId = (int) $forum->last_post_id;
$poster = $forum->last_poster;
$topic = $forum->last_topic;
$fnew = $forum->newMessages;
foreach ($forum->descendants as $chId => $children) {
$fnew = $fnew || $children->newMessages;
$numT += $children->num_topics;
$numP += $children->num_posts;
if ($children->last_post > $time) {
$time = $children->last_post;
$postId = $children->last_post_id;
$poster = $children->last_poster;
$topic = $children->last_topic;
}
}
$result[$cur['cid']]['name'] = $cur['cat_name'];
$result[$cur['cid']]['forums'][] = [
'fid' => $fId,
'forum_name' => $cur['forum_name'],
'forum_desc' => $forums[$fId]['forum_desc'],
$result[$forum->cid]['name'] = $forum->cat_name;
$result[$forum->cid]['forums'][] = [
'fid' => $forumId,
'forum_name' => $forum->forum_name,
'forum_desc' => $forum->forum_desc,
'forum_link' => $r->link('Forum', [
'id' => $fId,
'name' => $cur['forum_name']
'id' => $forumId,
'name' => $forum->forum_name,
]),
'redirect_url' => $cur['redirect_url'],
'redirect_url' => $forum->redirect_url,
'subforums' => $subForums,
'moderators' => $moderators,
'num_topics' => $numT,
@ -139,7 +93,7 @@ trait ForumsTrait
'last_post' => $this->time($time),
'last_post_id' => $postId > 0 ? $r->link('ViewPost', ['id' => $postId]) : null,
'last_poster' => $poster,
'last_topic' => $topic,
'last_topic' => $this->c->censorship->censor($topic),
'new' => $fnew,
];
}

View file

@ -2,39 +2,16 @@
namespace ForkBB\Models\Pages;
use ForkBB\Models\Page;
class Index extends Page
{
use ForumsTrait;
use OnlineTrait;
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'index';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = 'index';
/**
* Тип обработки пользователей онлайн
* @var bool
*/
protected $onlineType = true;
/**
* Тип возврата данных при onlineType === true
* Если true, то из online должны вернутся только пользователи находящиеся на этой же странице
* Если false, то все пользователи online
* @var bool
*/
protected $onlineFilter = false;
/**
* Подготовка данных для шаблона
*
* @return Page
*/
public function view()
@ -42,29 +19,31 @@ class Index extends Page
$this->c->Lang->load('index');
$this->c->Lang->load('subforums');
$stats = $this->c->users_info;
$stats = [];
$stats['total_users'] = $this->number($this->c->stats->userTotal);
$stats['total_posts'] = $this->number($this->c->stats->postTotal);
$stats['total_topics'] = $this->number($this->c->stats->topicTotal);
$stmt = $this->c->DB->query('SELECT SUM(num_topics), SUM(num_posts) FROM ::forums');
list($stats['total_topics'], $stats['total_posts']) = array_map([$this, 'number'], array_map('intval', $stmt->fetch(\PDO::FETCH_NUM)));
$stats['total_users'] = $this->number($stats['total_users']);
if ($this->c->user->gViewUsers == '1') {
if ($this->c->user->g_view_users == '1') {
$stats['newest_user'] = [
$this->c->Router->link('User', [
'id' => $stats['last_user']['id'],
'name' => $stats['last_user']['username'],
'id' => $this->c->stats->userLast['id'],
'name' => $this->c->stats->userLast['username'],
]),
$stats['last_user']['username']
$this->c->stats->userLast['username']
];
} else {
$stats['newest_user'] = $stats['last_user']['username'];
$stats['newest_user'] = $this->c->stats->userLast['username'];
}
$this->data['stats'] = $stats;
$this->data['online'] = $this->getUsersOnlineInfo();
$this->data['forums'] = $this->getForumsData();
$this->canonical = $this->c->Router->link('Index');
$this->nameTpl = 'index';
$this->onlinePos = 'index';
$this->onlineType = true;
$this->onlineFilter = false;
$this->canonical = $this->c->Router->link('Index');
$this->stats = $stats;
$this->online = $this->usersOnlineInfo();
$this->forums = $this->forumsData();
return $this;
}

View file

@ -4,29 +4,14 @@ namespace ForkBB\Models\Pages;
use ForkBB\Core\Container;
use ForkBB\Core\Validator;
use ForkBB\Models\Page;
use PDO;
use PDOException;
use RuntimeException;
class Install extends Page
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'layouts/install';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = null;
/**
* Переменная для meta name="robots"
* @var string
*/
protected $robots = 'noindex';
const PHP_MIN = '5.6.0';
/**
* Для MySQL
@ -36,33 +21,30 @@ class Install extends Page
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
{
$this->c = $container;
$this->config = $container->config;
$container->Lang->load('common', $this->config['o_default_lang']);
$container->Lang->load('common', $container->config->o_default_lang);
}
/**
* Возвращает данные для шаблона
* @return array
* Подготовка страницы к отображению
*/
public function getData()
public function prepare()
{
return $this->data + [
'pageHeads' => $this->pageHeads(),
'fIswev' => $this->getIswev(),
];
}
/**
* Возращает типы БД поддерживаемые PDO
*
* @param string $curType
*
* @return array
*/
protected function getDBTypes($curType = null)
protected function DBTypes($curType = null)
{
$dbTypes = [];
$pdoDrivers = PDO::getAvailableDrivers();
@ -93,15 +75,47 @@ class Install extends Page
/**
* Подготовка данных для страницы установки форума
*
* @param array $args
*
* @return Page
*/
public function install(array $args)
{
$this->nameTpl = 'layouts/install';
$this->onlinePos = null;
$this->robots = 'noindex';
$this->rev = $this->c->FORK_REVISION;
$this->formAction = $this->c->Router->link('Install');
// версия PHP
if (version_compare(PHP_VERSION, self::PHP_MIN, '<')) {
$this->a['fIswev']['e'][] = __('You are running error', 'PHP', PHP_VERSION, $this->c->FORK_REVISION, self::PHP_MIN);
}
// доступность папок на запись
$folders = [
$this->c->DIR_CONFIG,
$this->c->DIR_CACHE,
$this->c->DIR_PUBLIC . '/avatar',
];
foreach ($folders as $folder) {
if (! is_writable($folder)) {
$this->a['fIswev']['e'][] = __('Alert folder', $folder);
}
}
// доступность шаблона конфигурации
$config = file_get_contents($this->c->DIR_CONFIG . '/main.dist.php');
if (false === $config) {
$this->a['fIswev']['e'][] = __('No access to main.dist.php');
}
unset($config);
// язык
$langs = $this->c->Func->getLangs();
if (empty($langs)) {
$this->iswev['e'][] = 'No language pack.';
$this->a['fIswev']['e'][] = 'No language pack.';
$installLang = $installLangs = $defaultLangs = 'English';
} else {
if (isset($args['installlang'])) {
@ -123,27 +137,14 @@ class Install extends Page
}
}
unset($args['installlang']);
// версия PHP
$phpMin = '5.6.0';
if (version_compare(PHP_VERSION, $phpMin, '<')) {
$this->iswev['e'][] = __('You are running error', 'PHP', PHP_VERSION, $this->c->FORK_REVISION, $phpMin);
}
// доступность папок на запись
$folders = [
$this->c->DIR_CONFIG,
$this->c->DIR_CACHE,
$this->c->DIR_PUBLIC . '/avatar',
];
foreach ($folders as $folder) {
if (! is_writable($folder)) {
$this->iswev['e'][] = __('Alert folder', $folder);
}
}
$this->installLangs = $installLangs;
$this->installLang = $installLang;
$this->defaultLangs = $defaultLangs;
// стиль
$styles = $this->c->Func->getStyles();
if (empty($styles)) {
$this->iswev['e'][] = __('No styles');
$this->a['fIswev']['e'][] = __('No styles');
$defaultStyles = ['ForkBB'];
} else {
$defaultStyles = [];
@ -152,43 +153,46 @@ class Install extends Page
$defaultStyles[] = $style == $defStyle ? [$style, 1] : [$style];
}
}
unset($args['defaultstyle']);
// типы БД
$dbTypes = $this->getDBTypes(isset($args['dbtype']) ? $args['dbtype'] : null);
if (empty($dbTypes)) {
$this->iswev['e'][] = __('No DB extensions');
}
unset($args['dbtype']);
// доступность шаблона конфигурации
$config = file_get_contents($this->c->DIR_CONFIG . '/main.dist.php');
if (false === $config) {
$this->iswev['e'][] = __('No access to main.dist.php');
}
unset($config);
$this->defaultStyles = $defaultStyles;
// типы БД
$dbTypes = $this->DBTypes(isset($args['dbtype']) ? $args['dbtype'] : null);
if (empty($dbTypes)) {
$this->a['fIswev']['e'][] = __('No DB extensions');
}
$this->dbTypes = $dbTypes;
$this->a = $this->a + $args; //????
if (empty($args)) {
$this->dbhost = 'localhost';
$this->dbname = '';
$this->dbuser = '';
$this->dbprefix = '';
$this->username = '';
$this->email = '';
$this->title = __('My ForkBB Forum');
$this->descr = __('Description');
$this->baseurl = $this->c->BASE_URL;
} else {
$this->dbhost = $args['dbhost'];
$this->dbname = $args['dbname'];
$this->dbuser = $args['dbuser'];
$this->dbprefix = $args['dbprefix'];
$this->username = $args['username'];
$this->email = $args['email'];
$this->title = $args['title'];
$this->descr = $args['descr'];
$this->baseurl = $args['baseurl'];
}
$this->data = $args + [
'rev' => $this->c->FORK_REVISION,
'formAction' => $this->c->Router->link('Install'),
'installLangs' => $installLangs,
'installLang' => $installLang,
'dbTypes' => $dbTypes,
'dbhost' => 'localhost',
'dbname' => '',
'dbuser' => '',
'dbprefix' => '',
'username' => '',
'email' => '',
'title' => __('My ForkBB Forum'),
'descr' => __('Description'),
'baseurl' => $this->c->BASE_URL,
'defaultLangs' => $defaultLangs,
'defaultStyles' => $defaultStyles,
];
return $this;
}
/**
* Начальная стадия установки
*
* @return Page
*/
public function installPost()
@ -214,7 +218,7 @@ class Install extends Page
'rtrim_url' => [$this, 'vRtrimURL']
])->setRules([
'installlang' => 'string:trim',
'dbtype' => ['required|string:trim|in:' . implode(',', array_keys($this->getDBTypes())), __('Database type')],
'dbtype' => ['required|string:trim|in:' . implode(',', array_keys($this->DBTypes())), __('Database type')],
'dbhost' => ['required|string:trim|check_host', __('Database server hostname')],
'dbname' => ['required|string:trim', __('Database name')],
'dbuser' => ['string:trim', __('Database username')],
@ -235,50 +239,53 @@ class Install extends Page
if ($v->validation($_POST)) {
return $this->installEnd($v);
} else {
$this->iswev = $v->getErrors();
$this->fIswev = $v->getErrors();
return $this->install($v->getData());
}
}
/**
* Обработка base URL
*
* @param Validator $v
* @param string $url
* @param int $type
*
* @return array
*/
public function vRtrimURL(Validator $v, $url, $type)
public function vRtrimURL(Validator $v, $url)
{
return [rtrim($url, '/'), $type, false];
return [rtrim($url, '/'), true];
}
/**
* Дополнительная проверка префикса
*
* @param Validator $v
* @param string $prefix
* @param int $type
*
* @return array
*/
public function vCheckPrefix(Validator $v, $prefix, $type)
public function vCheckPrefix(Validator $v, $prefix)
{
$error = false;
$error = true;
if (strlen($prefix) == 0) {
} elseif (! preg_match('%^[a-z][a-z\d_]*$%i', $prefix)) {
$error = __('Table prefix error', $prefix);
} elseif ($v->dbtype == 'sqlite' && strtolower($prefix) == 'sqlite_') {
$error = __('Prefix reserved');
}
return [$prefix, $type, $error];
return [$prefix, $error];
}
/**
* Полная проверка подключения к БД
*
* @param Validator $v
* @param string $dbhost
* @param int $type
*
* @return array
*/
public function vCheckHost(Validator $v, $dbhost, $type)
public function vCheckHost(Validator $v, $dbhost)
{
$this->c->DB_USERNAME = $v->dbuser;
$this->c->DB_PASSWORD = $v->dbpass;
@ -287,7 +294,7 @@ class Install extends Page
$dbname = $v->dbname;
// есть ошибки, ни чего не проверяем
if (! empty($v->getErrors())) {
return [$dbhost, $type, false];
return [$dbhost, true];
}
// настройки подключения БД
$DBEngine = 'MyISAM';
@ -314,13 +321,13 @@ class Install extends Page
try {
$stat = $this->c->DB->statistics();
} catch (PDOException $e) {
return [$dbhost, $type, $e->getMessage()];
return [$dbhost, $e->getMessage()];
}
// проверка наличия таблицы пользователей в БД
try {
$stmt = $this->c->DB->query('SELECT 1 FROM ::users WHERE id=1 LIMIT 1');
if (! empty($stmt->fetch())) {
return [$dbhost, $type, __('Existing table error', $v->dbprefix, $v->dbname)];
return [$dbhost, __('Existing table error', $v->dbprefix, $v->dbname)];
}
} catch (PDOException $e) {
// все отлично, таблица пользователей не найдена
@ -329,12 +336,14 @@ class Install extends Page
if (isset($stat['character_set_database']) && $stat['character_set_database'] == 'utf8') {
$this->c->DB_DSN = str_replace('charset=utf8mb4', 'charset=utf8', $this->c->DB_DSN);
}
return [$dbhost, $type, false];
return [$dbhost, true];
}
/**
* Завершение установки форума
*
* @param Validator $v
*
* @return Page
*/
protected function installEnd(Validator $v)
@ -1002,7 +1011,7 @@ class Install extends Page
throw new RuntimeException('No access to main.dist.php.');
}
$repl = [
$repl = [ //????
'_BASE_URL_' => $v->baseurl,
'_DB_DSN_' => $this->c->DB_DSN,
'_DB_USERNAME_' => $this->c->DB_USERNAME,
@ -1016,7 +1025,7 @@ class Install extends Page
}
$result = file_put_contents($this->c->DIR_CONFIG . '/main.php', $config);
if (false === $result) {
throw new RuntimeException('No write to main.php.');
throw new RuntimeException('No write to main.php');
}
return $this->c->Redirect->toIndex();

View file

@ -3,65 +3,34 @@
namespace ForkBB\Models\Pages;
use ForkBB\Core\Container;
use ForkBB\Models\Page;
class Maintenance extends Page
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'maintenance';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = null;
/**
* HTTP статус ответа для данной страницы
* @var int
*/
protected $httpStatus = 503;
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
{
$this->c = $container;
$this->config = $container->config;
$container->Lang->load('common', $this->config['o_default_lang']);
$container->Lang->load('common', $container->config->o_default_lang);
parent::__construct($container);
$this->httpStatus = 503;
$this->nameTpl = 'maintenance';
# $this->onlinePos = null; //????
# $this->robots = 'noindex';
$this->titles = __('Maintenance');
# $this->fNavigation = null; //????
$this->maintenanceMessage = $this->c->config->o_maintenance_message;
}
/**
* Возвращает флаг готовности данных
* @return bool
* Подготовка страницы к отображению
*/
public function isReady()
public function prepare()
{
return true;
}
/**
* Возвращает данные для шаблона
* @return array
*/
public function getData()
{
$this->titles[] = __('Maintenance');
return [
'maintenanceMessage' => $this->config['o_maintenance_message'],
'pageTitle' => $this->pageTitle(),
'pageHeaders' => $this->pageHeaders(),
'fTitle' => $this->config['o_board_title'],
'fDescription' => $this->config['o_board_desc'],
'fNavigation' => null,
'fIndex' => $this->index,
'fAnnounce' => null,
'fRootLink' => $this->c->Router->link('Index'),
'fIswev' => null,
];
}
}

View file

@ -8,19 +8,22 @@ trait OnlineTrait
* Получение информации об онлайн посетителях
* @return null|array
*/
protected function getUsersOnlineInfo()
protected function usersOnlineInfo()
{
if ($this->config['o_users_online'] == '1') {
if ($this->c->config->o_users_online == '1') {
// данные онлайн посетителей
$this->c->Online->calc($this);
$users = $this->c->Online->users; //????
$guests = $this->c->Online->guests;
$bots = $this->c->Online->bots;
$list = [];
$data = [
'max' => $this->number($this->config['st_max_users']),
'max_time' => $this->time($this->config['st_max_users_time']),
'max' => $this->number($this->c->config->st_max_users),
'max_time' => $this->time($this->c->config->st_max_users_time),
];
// данные онлайн посетителей
list($users, $guests, $bots) = $this->c->Online->handle($this);
$list = [];
if ($this->c->user->gViewUsers == '1') {
if ($this->c->user->g_view_users == '1') {
foreach ($users as $id => $cur) {
$list[] = [
$this->c->Router->link('User', [

68
app/Models/Pages/Post.php Normal file
View file

@ -0,0 +1,68 @@
<?php
namespace ForkBB\Models\Pages;
class Post extends Page
{
use UsersTrait;
use OnlineTrait;
use CrumbTrait;
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'post';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = 'post';
/**
* Данные по текущей теме
* @var array
*/
protected $topic;
/**
* Подготовка данных для шаблона
* @param array $args
* @return Page
*/
public function newTopic(array $args)
{
list($fTree, $fDesc, $fAsc) = $this->c->forums;
// раздел отсутствует в доступных
if (empty($fDesc[$args['id']])) {
return $this->c->Message->message('Bad request');
}
$parent = isset($fDesc[$args['id']][0]) ? $fDesc[$args['id']][0] : 0;
$perm = $fTree[$parent][$args['id']];
// раздел является ссылкой
if (null !== $perm['redirect_url']) {
return $this->c->Message->message('Bad request');
}
$vars = [':fid' => $args['id']];
$sql = 'SELECT f.* FROM ::forums AS f WHERE f.id=?i:fid';
$forum = $this->c->DB->query($sql, $vars)->fetch();
$user = $this->c->user;
$moders = empty($forum['moderators']) ? [] : array_flip(unserialize($forum['moderators']));
if (! $user->isAdmin
&& (! $user->isAdmMod || ! isset($moders[$user->id]))
&& (null === $perm['post_topics'] && $user->g_post_topics == '0' || $perm['post_topics'] == '0')
) {
return $this->c->Message->message('Bad request');
}
return $this;
}
}

View file

@ -2,57 +2,29 @@
namespace ForkBB\Models\Pages;
use ForkBB\Models\Page;
class Redirect extends Page
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = null;
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = null;
/**
* Адрес перехода
* @var string
*/
protected $link;
/**
* Переменная для meta name="robots"
* @var string
*/
protected $robots = 'noindex';
/**
* Возвращает флаг готовности данных
* @return bool
*/
public function isReady()
{
return ! empty($this->link);
}
/**
* Перенаправление на главную страницу форума
*
* @return Page
*/
public function toIndex()
{
return $this->setPage('Index')->setMessage(__('Redirecting to index'));
return $this->page('Index')->message(__('Redirecting to index'));
}
/**
* Задает адрес перехода
*
* @param string $marker
* @param array $args
*
* @return Page
*/
public function setPage($marker, array $args = [])
public function page($marker, array $args = [])
{
$this->link = $this->c->Router->link($marker, $args);
return $this;
@ -60,10 +32,12 @@ class Redirect extends Page
/**
* Задает ссылку для перехода
*
* @param string $url
*
* @return Page
*/
public function setUrl($url)
public function url($url)
{
$this->link = $url;
return $this;
@ -71,47 +45,47 @@ class Redirect extends Page
/**
* Задает сообщение
*
* @param string $message
*
* @return Page
*/
public function setMessage($message)
public function message($message)
{
// переадресация без вывода сообщения
if ($this->config['o_redirect_delay'] == '0') {
if ($this->c->config->o_redirect_delay == '0') {
return $this;
}
$this->nameTpl = 'layouts/redirect';
$this->titles[] = __('Redirecting');
$this->data = [
'message' => $message,
'timeout' => (int) $this->config['o_redirect_delay'], //???? перенести в заголовки?
];
$this->titles = __('Redirecting');
$this->robots = 'noindex';
$this->message = $message;
$this->timeout = (int) $this->c->config->o_redirect_delay; //???? перенести в заголовки?
return $this;
}
/**
* Возвращает HTTP заголовки страницы
* $this->httpHeaders
*
* @return array
*/
public function httpHeaders()
protected function getHttpHeaders()
{
// переадресация без вывода сообщения
if (empty($this->data)) {
if (null === $this->nameTpl) {
$this->httpHeaders = [
'Location: ' . $this->link, //????
];
}
return parent::httpHeaders();
return parent::getHttpHeaders();
}
/**
* Возвращает данные для шаблона
* @return array
* Подготовка страницы к отображению
*/
public function getData()
public function prepare()
{
$this->data['link'] = $this->link;
return parent::getData();
}
}

View file

@ -4,37 +4,15 @@ namespace ForkBB\Models\Pages;
use ForkBB\Core\Validator;
use ForkBB\Core\Exceptions\MailException;
use ForkBB\Models\Page;
use ForkBB\Models\User;
class Register extends Page
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'register';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = 'register';
/**
* Указатель на активный пункт навигации
* @var string
*/
protected $index = 'register';
/**
* Переменная для meta name="robots"
* @var string
*/
protected $robots = 'noindex';
/**
* Обработчик регистрации
* @retrun Page
*
* @return Page
*/
public function reg()
{
@ -62,40 +40,47 @@ class Register extends Page
return $this->regEnd($v);
}
$this->iswev = $v->getErrors();
$this->fIswev = $v->getErrors();
// нет согласия с правилами
if (isset($this->iswev['cancel'])) {
return $this->c->Redirect->setPage('Index')->setMessage(__('Reg cancel redirect'));
if (isset($this->fIswev['cancel'])) {
return $this->c->Redirect->page('Index')->message(__('Reg cancel redirect'));
}
$this->titles[] = __('Register');
$this->data = [
'formAction' => $this->c->Router->link('RegisterForm'),
'formToken' => $this->c->Csrf->create('RegisterForm'),
'agree' => $v->agree,
'on' => '1',
'email' => $v->email,
'username' => $v->username,
];
$this->fIndex = 'register';
$this->nameTpl = 'register';
$this->onlinePos = 'register';
$this->titles = __('Register');
$this->robots = 'noindex';
$this->formAction = $this->c->Router->link('RegisterForm');
$this->formToken = $this->c->Csrf->create('RegisterForm');
$this->agree = $v->agree;
$this->on = '1';
$this->email = $v->email;
$this->username = $v->username;
return $this;
}
/**
* Дополнительная проверка email
*
* @param Validator $v
* @param string $username
* @param string $email
*
* @return array
*/
public function vCheckEmail(Validator $v, $email)
{
$error = false;
$user = $this->c->ModelUser;
$user->__email = $email;
// email забанен
if ($this->c->CheckBans->isBanned(null, $email) > 0) {
if ($this->c->bans->isBanned($user) > 0) {
$error = __('Banned email');
// найден хотя бы 1 юзер с таким же email
} elseif (empty($v->getErrors()) && $this->c->UserMapper->getUser($email, 'email') !== 0) {
} elseif (empty($v->getErrors()) && $user->load($email, 'email') !== 0) {
$error = __('Dupe email');
}
return [$email, $error];
@ -103,25 +88,30 @@ class Register extends Page
/**
* Дополнительная проверка username
*
* @param Validator $v
* @param string $username
*
* @return array
*/
public function vCheckUsername(Validator $v, $username)
{
$username = preg_replace('%\s+%su', ' ', $username);
$error = false;
$user = $this->c->ModelUser;
$user->__username = $username;
// username = Гость
if (preg_match('%^(guest|' . preg_quote(__('Guest'), '%') . ')$%iu', $username)) {
$error = __('Username guest');
// цензура
} elseif ($this->censor($username) !== $username) {
} elseif ($this->c->censorship->censor($username) !== $username) {
$error = __('Username censor');
// username забанен
} elseif ($this->c->CheckBans->isBanned($username) > 0) {
} elseif ($this->c->bans->isBanned($user) > 0) {
$error = __('Banned username');
// есть пользователь с похожим именем
} elseif (empty($v->getErrors()) && ! $this->c->UserMapper->isUnique($username)) {
} elseif (empty($v->getErrors()) && ! $user->isUnique()) {
$error = __('Username not unique');
}
return [$username, $error];
@ -129,40 +119,50 @@ class Register extends Page
/**
* Завершение регистрации
*
* @param array @data
*
* @return Page
*/
protected function regEnd(Validator $v)
{
if ($this->config['o_regs_verify'] == '1') {
if ($this->c->config->o_regs_verify == '1') {
$groupId = $this->c->GROUP_UNVERIFIED;
$key = 'w' . $this->c->Secury->randomPass(79);
} else {
$groupId = $this->config['o_default_user_group'];
$groupId = $this->c->config->o_default_user_group;
$key = null;
}
$newUserId = $this->c->UserMapper->newUser(new User([
'group_id' => $groupId,
'username' => $v->username,
'password' => password_hash($v->password, PASSWORD_DEFAULT),
'email' => $v->email,
'email_confirmed' => 0,
'activate_string' => $key,
'u_mark_all_read' => time(),
], $this->c));
$user = $this->c->ModelUser;
$user->username = $v->username;
$user->password = password_hash($v->password, PASSWORD_DEFAULT);
$user->group_id = $groupId;
$user->email = $v->email;
$user->email_confirmed = 0;
$user->activate_string = $key;
$user->u_mark_all_read = time();
$user->email_setting = $this->c->config->o_default_email_setting;
$user->timezone = $this->c->config->o_default_timezone;
$user->dst = $this->c->config->o_default_dst;
$user->language = $user->language;
$user->style = $user->style;
$user->registered = time();
$user->registration_ip = $this->c->user->ip;
$newUserId = $user->insert();
// обновление статистики по пользователям
if ($this->config['o_regs_verify'] != '1') {
if ($this->c->config->o_regs_verify != '1') {
$this->c->{'users_info update'};
}
// уведомление о регистрации
if ($this->config['o_regs_report'] == '1' && $this->config['o_mailing_list'] != '') {
if ($this->c->config->o_regs_report == '1' && $this->c->config->o_mailing_list != '') {
$tplData = [
'fTitle' => $this->config['o_board_title'],
'fTitle' => $this->c->config->o_board_title,
'fRootLink' => $this->c->Router->link('Index'),
'fMailer' => __('Mailer', $this->config['o_board_title']),
'fMailer' => __('Mailer', $this->c->config->o_board_title),
'username' => $v->username,
'userLink' => $this->c->Router->link('User', ['id' => $newUserId, 'name' => $v->username]),
];
@ -171,9 +171,9 @@ class Register extends Page
$this->c->Mail
->reset()
->setFolder($this->c->DIR_LANG)
->setLanguage($this->config['o_default_lang'])
->setTo($this->config['o_mailing_list'])
->setFrom($this->config['o_webmaster_email'], __('Mailer', $this->config['o_board_title']))
->setLanguage($this->c->config->o_default_lang)
->setTo($this->c->config->o_mailing_list)
->setFrom($this->c->config->o_webmaster_email, __('Mailer', $this->c->config->o_board_title))
->setTpl('new_user.tpl', $tplData)
->send();
} catch (MailException $e) {
@ -184,13 +184,13 @@ class Register extends Page
$this->c->Lang->load('register');
// отправка письма активации аккаунта
if ($this->config['o_regs_verify'] == '1') {
if ($this->c->config->o_regs_verify == '1') {
$hash = $this->c->Secury->hash($newUserId . $key);
$link = $this->c->Router->link('RegActivate', ['id' => $newUserId, 'key' => $key, 'hash' => $hash]);
$tplData = [
'fTitle' => $this->config['o_board_title'],
'fTitle' => $this->c->config->o_board_title,
'fRootLink' => $this->c->Router->link('Index'),
'fMailer' => __('Mailer', $this->config['o_board_title']),
'fMailer' => __('Mailer', $this->c->config->o_board_title),
'username' => $v->username,
'link' => $link,
];
@ -201,7 +201,7 @@ class Register extends Page
->setFolder($this->c->DIR_LANG)
->setLanguage($this->c->user->language)
->setTo($v->email)
->setFrom($this->config['o_webmaster_email'], __('Mailer', $this->config['o_board_title']))
->setFrom($this->c->config->o_webmaster_email, __('Mailer', $this->c->config->o_board_title))
->setTpl('welcome.tpl', $tplData)
->send();
} catch (MailException $e) {
@ -210,56 +210,49 @@ class Register extends Page
// письмо активации аккаунта отправлено
if ($isSent) {
return $this->c->Message->message(__('Reg email', $this->config['o_admin_email']), false, 200);
return $this->c->Message->message(__('Reg email', $this->c->config->o_admin_email), false, 200);
// форма сброса пароля
} else {
return $this->c->Auth->setIswev([
'w' => [
__('Error welcom mail', $this->config['o_admin_email']),
],
])->forget([
'_email' => $v->email,
]);
$auth = $this->c->Auth;
$auth->fIswev = ['w' => [__('Error welcom mail', $this->c->config->o_admin_email)]];
return $auth->forget(['_email' => $v->email]);
}
// форма логина
} else {
return $this->c->Auth->setIswev([
's' => [
__('Reg complete'),
],
])->login([
'_username' => $v->username,
]);
$auth = $this->c->Auth;
$auth->fIswev = ['s' => [__('Reg complete')]];
return $auth->login(['_username' => $v->username]);
}
}
/**
* Активация аккаунта
*
* @param array $args
*
* @return Page
*/
public function activate(array $args)
{
if (! hash_equals($args['hash'], $this->c->Secury->hash($args['id'] . $args['key']))
|| ! ($user = $this->c->UserMapper->getUser($args['id'])) instanceof User
|| empty($user->activateString)
|| $user->activateString{0} !== 'w'
|| ! hash_equals($user->activateString, $args['key'])
|| ! ($user = $this->c->ModelUser->load($args['id'])) instanceof User
|| empty($user->activate_string)
|| $user->activate_string{0} !== 'w'
|| ! hash_equals($user->activate_string, $args['key'])
) {
return $this->c->Message->message(__('Bad request'), false);
}
$this->c->UserMapper->updateUser($user->id, ['group_id' => $this->config['o_default_user_group'], 'email_confirmed' => 1, 'activate_string' => null]);
$user->group_id = $this->c->config->o_default_user_group;
$user->email_confirmed = 1;
$user->activate_string = null;
$user->update();
$this->c->{'users_info update'};
$this->c->Lang->load('register');
return $this->c->Auth->setIswev([
's' => [
__('Reg complete'),
],
])->login([
'_username' => $user->username,
]);
$auth = $this->c->Auth;
$auth->fIswev = ['s' => [__('Reg complete')]];
return $auth->login(['_username' => $v->username]);
}
}

View file

@ -2,64 +2,49 @@
namespace ForkBB\Models\Pages;
use ForkBB\Models\Page;
class Rules extends Page
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'rules';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = 'rules';
/**
* Указатель на активный пункт навигации
* @var string
*/
protected $index = 'rules';
/**
* Подготавливает данные для шаблона
*
* @return Page
*/
public function view()
{
$this->titles[] = __('Forum rules');
$this->data = [
'title' => __('Forum rules'),
'rules' => $this->config['o_rules_message'],
'formAction' => null,
];
$this->canonical = $this->c->Router->link('Rules');
$this->fIndex = 'rules';
$this->nameTpl = 'rules';
$this->onlinePos = 'rules';
$this->canonical = $this->c->Router->link('Rules');
$this->titles = __('Forum rules');
$this->title = __('Forum rules');
$this->rules = $this->c->config->o_rules_message;
$this->formAction = null;
return $this;
}
/**
* Подготавливает данные для шаблона
*
* @return Page
*/
public function confirmation()
{
$this->index = 'register';
$this->robots = 'noindex';
$this->c->Lang->load('register');
$this->titles[] = __('Forum rules');
$this->data = [
'title' => __('Forum rules'),
'rules' => $this->config['o_rules'] == '1' ?
$this->config['o_rules_message']
: __('If no rules'),
'formAction' => $this->c->Router->link('RegisterForm'),
'formToken' => $this->c->Csrf->create('RegisterForm'),
'formHash' => $this->c->Csrf->create('Register'),
];
$this->fIndex = 'register';
$this->nameTpl = 'rules';
$this->onlinePos = 'rules';
$this->robots = 'noindex';
$this->titles = __('Forum rules');
$this->title = __('Forum rules');
$this->rules = $this->c->config->o_rules == '1' ? $this->c->config->o_rules_message : __('If no rules');
$this->formAction = $this->c->Router->link('RegisterForm');
$this->formToken = $this->c->Csrf->create('RegisterForm');
$this->formHash = $this->c->Csrf->create('Register');
return $this;
}
}

View file

@ -2,6 +2,8 @@
namespace ForkBB\Models\Pages;
use ForkBB\Models\Page;
class Topic extends Page
{
use UsersTrait;
@ -9,60 +11,104 @@ class Topic extends Page
use CrumbTrait;
/**
* Имя шаблона
* @var string
* Данные по текущей теме
* @var array
*/
protected $nameTpl = 'topic';
protected $curTopic;
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = 'topic';
/**
* Тип обработки пользователей онлайн
* Если false, то идет обновление данных
* Если true, то идет возврат данных (смотрите $onlineFilter)
* @var bool
*/
protected $onlineType = true;
/**
* Тип возврата данных при onlineType === true
* Если true, то из online должны вернутся только пользователи находящиеся на этой же странице
* Если false, то все пользователи online
* @var bool
*/
protected $onlineFilter = true;
/**
* Подготовка данных для шаблона
* Переход к первому новому сообщению темы (или в конец)
*
* @param array $args
*
* @return Page
*/
public function viewNew(array $args)
{
public function viewNew(array $args)
{
$topic = $this->curTopic($args['id']);
if (false === $topic) {
return $this->c->Message->message('Bad request');
}
}
if (! $this->c->user->isGuest) {
$upper = max(
(int) $this->c->user->last_visit,
(int) $this->c->user->u_mark_all_read,
(int) $topic['mf_mark_all_read'],
(int) $topic['mt_last_visit']
);
if ($upper < $topic['last_post']) {
$vars = [
':tid' => $args['id'],
':visit' => $upper,
];
$sql = 'SELECT MIN(id) FROM ::posts WHERE topic_id=?i:tid AND posted>?i:visit';
$pid = $this->c->DB->query($sql, $vars)->fetchColumn();
if (! empty($pid)) {
return $this->c->Redirect->page('ViewPost', ['id' => $pid]);
}
}
}
return $this->viewLast(['id' => $topic['id']]);
}
/**
* Подготовка данных для шаблона
* Переход к первому непрочитанному сообщению (или в конец)
*
* @param array $args
*
* @return Page
*/
public function viewUnread(array $args)
{
public function viewUnread(array $args)
{
$topic = $this->curTopic($args['id']);
if (false === $topic) {
return $this->c->Message->message('Bad request');
}
}
if (! $this->c->user->isGuest) {
$lower = max(
(int) $this->c->user->u_mark_all_read,
(int) $topic['mf_mark_all_read'],
(int) $topic['mt_last_read']
);
if ($lower < $topic['last_post']) {
$vars = [
':tid' => $args['id'],
':visit' => $lower,
];
$sql = 'SELECT MIN(id) FROM ::posts WHERE topic_id=?i:tid AND posted>?i:visit';
$pid = $this->c->DB->query($sql, $vars)->fetchColumn();
if (! empty($pid)) {
return $this->c->Redirect->page('ViewPost', ['id' => $pid]);
}
}
}
return $this->viewLast(['id' => $topic['id']]);
}
/**
* Переход к последнему сообщению темы
*
* @param array $args
*
* @return Page
*/
public function viewLast(array $args)
{
public function viewLast(array $args)
{
$topic = $this->curTopic($args['id']);
if (false === $topic) {
return $this->c->Message->message('Bad request');
}
$vars = [
':tid' => $args['id'],
];
@ -74,122 +120,154 @@ class Topic extends Page
return $this->c->Message->message('Bad request');
}
return $this->c->Redirect->setPage('ViewPost', ['id' => $pid]);
return $this->c->Redirect->page('ViewPost', ['id' => $pid]);
}
/**
* Просмотр темы по номеру сообщения
* @param array $args
* @return Page
*/
public function viewPost(array $args)
{
$vars = [
':pid' => $args['id'],
':uid' => $this->c->user->id,
];
if ($this->c->user->isGuest) {
$sql = 'SELECT t.*, f.moderators, 0 AS is_subscribed, 0 AS mf_mark_all_read, 0 AS mt_last_visit, 0 AS mt_last_read
FROM ::topics AS t
INNER JOIN ::forums AS f ON f.id=t.forum_id
INNER JOIN ::posts AS p ON t.id=p.topic_id
WHERE p.id=?i:pid AND t.moved_to IS NULL';
} else {
$sql = 'SELECT t.*, f.moderators, s.user_id AS is_subscribed, mof.mf_mark_all_read, mot.mt_last_visit, mot.mt_last_read
FROM ::topics AS t
INNER JOIN ::forums AS f ON f.id=t.forum_id
INNER JOIN ::posts AS p ON t.id=p.topic_id
LEFT JOIN ::topic_subscriptions AS s ON (t.id=s.topic_id AND s.user_id=?i:uid)
LEFT JOIN ::mark_of_forum AS mof ON (mof.uid=?i:uid AND f.id=mof.fid)
LEFT JOIN ::mark_of_topic AS mot ON (mot.uid=?i:uid AND t.id=mot.tid)
WHERE p.id=?i:pid AND t.moved_to IS NULL';
}
return $this->view($sql, $vars, null);
}
/**
* Просмотр темы по ее номеру
* @param array $args
* @return Page
* Получение данных по текущей теме
*
* @param mixed $id
* @param mixed $pid
*
* @return bool|array
*/
public function viewTopic(array $args)
protected function curTopic($id, $pid = null)
{
$vars = [
':tid' => $args['id'],
':uid' => $this->c->user->id,
];
if ($this->c->user->isGuest) {
$sql = 'SELECT t.*, f.moderators, 0 AS is_subscribed, 0 AS mf_mark_all_read, 0 AS mt_last_visit, 0 AS mt_last_read
FROM ::topics AS t
INNER JOIN ::forums AS f ON f.id=t.forum_id
WHERE t.id=?i:tid AND t.moved_to IS NULL';
} else {
$sql = 'SELECT t.*, f.moderators, s.user_id AS is_subscribed, mof.mf_mark_all_read, mot.mt_last_visit, mot.mt_last_read
FROM ::topics AS t
INNER JOIN ::forums AS f ON f.id=t.forum_id
LEFT JOIN ::topic_subscriptions AS s ON (t.id=s.topic_id AND s.user_id=?i:uid)
LEFT JOIN ::mark_of_forum AS mof ON (mof.uid=?i:uid AND f.id=mof.fid)
LEFT JOIN ::mark_of_topic AS mot ON (mot.uid=?i:uid AND t.id=mot.tid)
WHERE t.id=?i:tid AND t.moved_to IS NULL';
if ($this->curTopic) {
return $this->curTopic;
}
$page = isset($args['page']) ? (int) $args['page'] : 1;
if (isset($pid)) {
$vars = [
':pid' => $pid,
':uid' => $this->c->user->id,
];
if ($this->c->user->isGuest) {
$sql = 'SELECT t.*, f.moderators, 0 AS is_subscribed, 0 AS mf_mark_all_read, 0 AS mt_last_visit, 0 AS mt_last_read
FROM ::topics AS t
INNER JOIN ::forums AS f ON f.id=t.forum_id
INNER JOIN ::posts AS p ON t.id=p.topic_id
WHERE p.id=?i:pid AND t.moved_to IS NULL';
return $this->view($sql, $vars, $page);
}
} else {
$sql = 'SELECT t.*, f.moderators, s.user_id AS is_subscribed, mof.mf_mark_all_read, mot.mt_last_visit, mot.mt_last_read
FROM ::topics AS t
INNER JOIN ::forums AS f ON f.id=t.forum_id
INNER JOIN ::posts AS p ON t.id=p.topic_id
LEFT JOIN ::topic_subscriptions AS s ON (t.id=s.topic_id AND s.user_id=?i:uid)
LEFT JOIN ::mark_of_forum AS mof ON (mof.uid=?i:uid AND f.id=mof.fid)
LEFT JOIN ::mark_of_topic AS mot ON (mot.uid=?i:uid AND t.id=mot.tid)
WHERE p.id=?i:pid AND t.moved_to IS NULL';
}
} else {
$vars = [
':tid' => $id,
':uid' => $this->c->user->id,
];
if ($this->c->user->isGuest) {
$sql = 'SELECT t.*, f.moderators, 0 AS is_subscribed, 0 AS mf_mark_all_read, 0 AS mt_last_visit, 0 AS mt_last_read
FROM ::topics AS t
INNER JOIN ::forums AS f ON f.id=t.forum_id
WHERE t.id=?i:tid AND t.moved_to IS NULL';
/**
* Подготовка данных для шаблона
* @param string $sql
* @param array $vars
* @param int|null $page
* @return Page
*/
protected function view($sql, array $vars, $page)
{
$user = $this->c->user;
$vars[':uid'] = $user->id;
} else {
$sql = 'SELECT t.*, f.moderators, s.user_id AS is_subscribed, mof.mf_mark_all_read, mot.mt_last_visit, mot.mt_last_read
FROM ::topics AS t
INNER JOIN ::forums AS f ON f.id=t.forum_id
LEFT JOIN ::topic_subscriptions AS s ON (t.id=s.topic_id AND s.user_id=?i:uid)
LEFT JOIN ::mark_of_forum AS mof ON (mof.uid=?i:uid AND f.id=mof.fid)
LEFT JOIN ::mark_of_topic AS mot ON (mot.uid=?i:uid AND t.id=mot.tid)
WHERE t.id=?i:tid AND t.moved_to IS NULL';
}
}
$topic = $this->c->DB->query($sql, $vars)->fetch();
// тема отсутствует или недоступна
if (empty($topic)) {
return $this->c->Message->message('Bad request');
return false;
}
list($fTree, $fDesc, $fAsc) = $this->c->forums;
// раздел отсутствует в доступных
if (empty($fDesc[$topic['forum_id']])) {
return $this->c->Message->message('Bad request');
return false;
}
$this->curTopic = $topic;
return $topic;
}
/**
* Просмотр темы по номеру сообщения
*
* @param array $args
*
* @return Page
*/
public function viewPost(array $args)
{
$topic = $this->curTopic(null, $args['id']);
if (false === $topic) {
return $this->c->Message->message('Bad request');
}
return $this->view($topic, $args['id']);
}
/**
* Просмотр темы по ее номеру
*
* @param array $args
*
* @return Page
*/
public function viewTopic(array $args)
{
$topic = $this->curTopic($args['id']);
if (false === $topic) {
return $this->c->Message->message('Bad request');
}
$page = isset($args['page']) ? (int) $args['page'] : 1;
return $this->view($topic, null, $page);
}
/**
* Подготовка данных для шаблона
*
* @param array $topic
* @param int|null $pid
* @param int|null $page
*
* @return Page
*/
protected function view(array $topic, $pid, $page = null)
{
$user = $this->c->user;
if (null === $page) {
$vars[':tid'] = $topic['id'];
$vars = [
':tid' => $topic['id'],
':pid' => $pid,
];
$sql = 'SELECT COUNT(id) FROM ::posts WHERE topic_id=?i:tid AND id<?i:pid';
$num = 1 + $this->c->DB->query($sql, $vars)->fetchColumn();
$page = ceil($num / $user->dispPosts);
$page = ceil($num / $user->disp_posts);
}
$this->c->Lang->load('topic');
$pages = ceil(($topic['num_replies'] + 1) / $user->dispPosts);
$pages = ceil(($topic['num_replies'] + 1) / $user->disp_posts);
// попытка открыть страницу которой нет
if ($page < 1 || $page > $pages) {
return $this->c->Message->message('Bad request');
}
$offset = ($page - 1) * $user->dispPosts;
$offset = ($page - 1) * $user->disp_posts;
$vars = [
':tid' => $topic['id'],
':offset' => $offset,
':rows' => $user->dispPosts,
':rows' => $user->disp_posts,
];
$sql = 'SELECT id
FROM ::posts
@ -200,9 +278,13 @@ class Topic extends Page
// нарушена синхронизация количества сообщений в темах
if (empty($ids)) {
return $this->viewLast($topic['id']);
return $this->viewLast(['id' => $topic['id']]);
}
$this->c->Lang->load('topic');
list($fTree, $fDesc, $fAsc) = $this->c->forums;
$moders = empty($topic['moderators']) ? [] : array_flip(unserialize($topic['moderators']));
$parent = isset($fDesc[$topic['forum_id']][0]) ? $fDesc[$topic['forum_id']][0] : 0;
$perm = $fTree[$parent][$topic['forum_id']];
@ -217,7 +299,7 @@ class Topic extends Page
} elseif ($topic['closed'] == '1') {
$newOn = false;
} elseif ($perm['post_replies'] === 1
|| (null === $perm['post_replies'] && $user->gPostReplies == '1')
|| (null === $perm['post_replies'] && $user->g_post_replies == '1')
|| ($user->isAdmMod && isset($moders[$user->id]))
) {
$newOn = true;
@ -255,20 +337,20 @@ class Topic extends Page
// парсер и его настройка для сообщений
$bbcodes = include $this->c->DIR_CONFIG . '/defaultBBCode.php';
$smilies = $this->c->smilies;
$smilies = $this->c->smilies->list; //????
foreach ($smilies as &$cur) {
$cur = $this->c->PUBLIC_URL . '/img/sm/' . $cur;
}
unset($cur);
$bbInfo = $this->c->BBCODE_INFO;
$bbWList = $this->config['p_message_bbcode'] == '1' ? null : [];
$bbBList = $this->config['p_message_img_tag'] == '1' ? [] : ['img'];
$bbWList = $this->c->config->p_message_bbcode == '1' ? null : [];
$bbBList = $this->c->config->p_message_img_tag == '1' ? [] : ['img'];
$parser = $this->c->Parser;
$parser->setBBCodes($bbcodes)
->setAttr('isSign', false)
->setWhiteList($bbWList)
->setBlackList($bbBList);
if ($user->showSmilies == '1') {
if ($user->show_smilies == '1') {
$parser->setSmilies($smilies)
->setSmTpl($bbInfo['smTpl'], $bbInfo['smTplTag'], $bbInfo['smTplBl']);
}
@ -287,7 +369,7 @@ class Topic extends Page
$post = [
'poster' => $cur['username'],
'poster_id' => $cur['poster_id'],
'poster_title' => $this->censor($this->userGetTitle($cur)),
'poster_title' => $this->c->censorship->censor($this->userGetTitle($cur)),
'poster_avatar' => null,
'poster_registered' => null,
'poster_location' => null,
@ -299,13 +381,13 @@ class Topic extends Page
];
if ($cur['poster_id'] > 1) {
if ($user->gViewUsers == '1') {
if ($user->g_view_users == '1') {
$post['poster_link'] = $this->c->Router->link('User', ['id' => $cur['poster_id'], 'name' => $cur['username']]);
}
if ($this->config['o_avatars'] == '1' && $user->showAvatars == '1') {
if ($this->c->config->o_avatars == '1' && $user->show_avatars == '1') {
$post['poster_avatar'] = $this->userGetAvatarLink($cur['poster_id']);
}
if ($this->config['o_show_user_info'] == '1') {
if ($this->c->config->o_show_user_info == '1') {
$post['poster_info_add'] = true;
$post['poster_registered'] = $this->time($cur['registered'], true);
@ -314,7 +396,7 @@ class Topic extends Page
$post['poster_num_posts'] = $cur['num_posts'];
if ($cur['location'] != '') {
$post['poster_location'] = $this->censor($cur['location']);
$post['poster_location'] = $this->c->censorship->censor($cur['location']);
}
if (isset($genders[$cur['gender']])) {
$post['poster_gender'] = $genders[$cur['gender']];
@ -324,9 +406,9 @@ class Topic extends Page
$posters[$cur['poster_id']] = $post;
if ($this->config['o_signatures'] == '1'
if ($this->c->config->o_signatures == '1'
&& $cur['signature'] != ''
&& $user->showSig == '1'
&& $user->show_sig == '1'
&& ! isset($signs[$cur['poster_id']])
) {
$signs[$cur['poster_id']] = $cur['signature'];
@ -342,8 +424,8 @@ class Topic extends Page
$timeMax = max($timeMax, $cur['posted']);
$parser->parse($this->censor($cur['message']));
if ($this->config['o_smilies'] == '1' && $user->showSmilies == '1' && $cur['hide_smilies'] == '0') {
$parser->parse($this->c->censorship->censor($cur['message']));
if ($this->c->config->o_smilies == '1' && $user->show_smilies == '1' && $cur['hide_smilies'] == '0') {
$parser->detectSmilies();
}
$post['message'] = $parser->getHtml();
@ -363,18 +445,18 @@ class Topic extends Page
$controls['report'] = [$this->c->Router->link('ReportPost', $vars), 'Report'];
}
if ($user->isAdmin
|| ($user->isAdmMod && isset($moders[$user->id]) && ! in_array($cur['poster_id'], $this->c->admins))
|| ($user->isAdmMod && isset($moders[$user->id]) && ! in_array($cur['poster_id'], $this->c->admins->list)) //????
) {
$controls['delete'] = [$this->c->Router->link('DeletePost', $vars), 'Delete'];
$controls['edit'] = [$this->c->Router->link('EditPost', $vars), 'Edit'];
} elseif ($topic['closed'] != '1'
&& $cur['poster_id'] == $user->id
&& ($user->gDeleditInterval == '0' || $cur['edit_post'] == '1' || time() - $cur['posted'] < $user->gDeleditInterval)
&& ($user->g_deledit_interval == '0' || $cur['edit_post'] == '1' || time() - $cur['posted'] < $user->g_deledit_interval)
) {
if (($cur['id'] == $topic['first_post_id'] && $user->gDeleteTopics == '1') || ($cur['id'] != $topic['first_post_id'] && $user->gDeletePosts == '1')) {
if (($cur['id'] == $topic['first_post_id'] && $user->g_delete_topics == '1') || ($cur['id'] != $topic['first_post_id'] && $user->g_delete_posts == '1')) {
$controls['delete'] = [$this->c->Router->link('DeletePost', $vars), 'Delete'];
}
if ($user->gEditPosts == '1') {
if ($user->g_edit_posts == '1') {
$controls['edit'] = [$this->c->Router->link('EditPost', $vars), 'Edit'];
}
}
@ -389,15 +471,15 @@ class Topic extends Page
if ($signs) {
// настройка парсера для подписей
$bbWList = $this->config['p_sig_bbcode'] == '1' ? $bbInfo['forSign'] : [];
$bbBList = $this->config['p_sig_img_tag'] == '1' ? [] : ['img'];
$bbWList = $this->c->config->p_sig_bbcode == '1' ? $bbInfo['forSign'] : [];
$bbBList = $this->c->config->p_sig_img_tag == '1' ? [] : ['img'];
$parser->setAttr('isSign', true)
->setWhiteList($bbWList)
->setBlackList($bbBList);
foreach ($signs as &$cur) {
$parser->parse($this->censor($cur));
if ($this->config['o_smilies_sig'] == '1' && $user->showSmilies == '1') {
$parser->parse($this->c->censorship->censor($cur));
if ($this->c->config->o_smilies_sig == '1' && $user->show_smilies == '1') {
$parser->detectSmilies();
}
$cur = $parser->getHtml();
@ -405,13 +487,12 @@ class Topic extends Page
unset($cur);
}
$topic['subject'] = $this->censor($topic['subject']);
$topic['subject'] = $this->c->censorship->censor($topic['subject']);
$this->onlinePos = 'topic-' . $topic['id'];
// данные для формы быстрого ответа
$form = null;
if ($newOn && $this->config['o_quickpost'] == '1') {
if ($newOn && $this->c->config->o_quickpost == '1') {
$form = [
'action' => $this->c->Router->link('NewReply', ['id' => $topic['id']]),
'hidden' => [
@ -439,7 +520,7 @@ class Topic extends Page
'type' => 'text',
'maxlength' => 80,
'title' => __('Email'),
'required' => $this->config['p_force_guest_email'] == '1',
'required' => $this->c->config->p_force_guest_email == '1',
'pattern' => '.+@.+',
];
}
@ -449,10 +530,10 @@ class Topic extends Page
'title' => __('Message'),
'required' => true,
'bb' => [
['link', __('BBCode'), __($this->config['p_message_bbcode'] == '1' ? 'on' : 'off')],
['link', __('url tag'), __($this->config['p_message_bbcode'] == '1' && $user->gPostLinks == '1' ? 'on' : 'off')],
['link', __('img tag'), __($this->config['p_message_bbcode'] == '1' && $this->config['p_message_img_tag'] == '1' ? 'on' : 'off')],
['link', __('Smilies'), __($this->config['o_smilies'] == '1' ? 'on' : 'off')],
['link', __('BBCode'), __($this->c->config->p_message_bbcode == '1' ? 'on' : 'off')],
['link', __('url tag'), __($this->c->config->p_message_bbcode == '1' && $user->g_post_links == '1' ? 'on' : 'off')],
['link', __('img tag'), __($this->c->config->p_message_bbcode == '1' && $this->c->config->p_message_img_tag == '1' ? 'on' : 'off')],
['link', __('Smilies'), __($this->c->config->o_smilies == '1' ? 'on' : 'off')],
],
];
$form['sets'][] = [
@ -476,26 +557,26 @@ class Topic extends Page
}
}
$this->data = [
'topic' => $topic,
'posts' => $posts,
'signs' => $signs,
'warnings' => $warnings,
'crumbs' => $this->getCrumbs(
['Topic', ['id' => $topic['id'], 'name' => $topic['subject']]],
[$fDesc, $topic['forum_id']]
),
'NewReply' => $newOn ? $this->c->Router->link('NewReply', ['id' => $topic['id']]) : $newOn,
'stickFP' => $stickFP,
'pages' => $this->c->Func->paginate($pages, $page, 'Topic', ['id' => $topic['id'], 'name' => $topic['subject']]),
'online' => $this->getUsersOnlineInfo(),
'stats' => null,
'form' => $form,
];
$this->nameTpl = 'topic';
$this->onlinePos = 'topic-' . $topic['id'];
$this->onlineType = true;
$this->canonical = $this->c->Router->link('Topic', ['id' => $topic['id'], 'name' => $topic['subject'], 'page' => $page]);
$this->topic = $topic;
$this->posts = $posts;
$this->signs = $signs;
$this->warnings = $warnings;
$this->crumbs = $this->crumbs(
['Topic', ['id' => $topic['id'], 'name' => $topic['subject']]],
[$fDesc, $topic['forum_id']]
);
$this->NewReply = $newOn ? $this->c->Router->link('NewReply', ['id' => $topic['id']]) : $newOn;
$this->stickFP = $stickFP;
$this->pages = $this->c->Func->paginate($pages, $page, 'Topic', ['id' => $topic['id'], 'name' => $topic['subject']]);
$this->online = $this->usersOnlineInfo();
$this->stats = null;
$this->form = $form;
$this->canonical = $this->c->Router->link('Topic', ['id' => $topic['id'], 'name' => $topic['subject'], 'page' => $page]);
if ($this->config['o_topic_views'] == '1') {
if ($this->c->config->o_topic_views == '1') {
$vars = [
':tid' => $topic['id'],
];
@ -512,12 +593,12 @@ class Topic extends Page
':visit' => $topic['mt_last_visit'],
];
$flag = false;
$lower = max((int) $user->uMarkAllRead, (int) $topic['mf_mark_all_read'], (int) $topic['mt_last_read']); //????
$lower = max((int) $user->u_mark_all_read, (int) $topic['mf_mark_all_read'], (int) $topic['mt_last_read']); //????
if ($timeMax > $lower) {
$vars[':read'] = $timeMax;
$flag = true;
}
$upper = max($lower, (int) $topic['mt_last_visit'], (int) $user->lastVisit); //????
$upper = max($lower, (int) $topic['mt_last_visit'], (int) $user->last_visit); //????
if ($topic['last_post'] > $upper) {
$vars[':visit'] = $topic['last_post'];
$flag = true;
@ -533,8 +614,8 @@ class Topic extends Page
LIMIT 1', $vars);
} else {
$this->c->DB->exec('UPDATE ::mark_of_topic
SET mt_last_visit=?i:visit, mt_last_read=?i:read
WHERE uid=?i:uid AND tid=?i:tid', $vars);
SET mt_last_visit=?i:visit, mt_last_read=?i:read
WHERE uid=?i:uid AND tid=?i:tid', $vars);
}
}
}

View file

@ -6,25 +6,25 @@ trait UsersTrait
{
/**
* Имена забаненных пользователей
*
* @var array
*/
protected $userBanNames;
/**
* Определение титула для пользователя
*
* @param array $data
*
* @return string
*/
protected function userGetTitle(array $data)
{
if (! isset($this->userBanNames)) {
$this->userBanNames = [];
foreach($this->c->bans as $cur) {
$this->userBanNames[mb_strtolower($cur['username'])] = true;
}
$this->userBanNames = $this->c->bans->userList; //????
}
if(isset($this->userBanNames[$data['username']])) {
if (isset($this->userBanNames[mb_strtolower($data['username'])])) { //????
return __('Banned');
} elseif ($data['title'] != '') {
return $data['title'];
@ -39,7 +39,9 @@ trait UsersTrait
/**
* Определение ссылки на аватарку
*
* @param int $id
*
* @return string|null
*/
protected function userGetAvatarLink($id)
@ -47,10 +49,10 @@ trait UsersTrait
$filetypes = array('jpg', 'gif', 'png');
foreach ($filetypes as $type) {
$path = $this->c->DIR_PUBLIC . "/{$this->config['o_avatars_dir']}/{$id}.{$type}";
$path = $this->c->DIR_PUBLIC . "/{$this->c->config->o_avatars_dir}/{$id}.{$type}";
if (file_exists($path) && getimagesize($path)) {
return $this->c->PUBLIC_URL . "/{$this->config['o_avatars_dir']}/{$id}.{$type}";
return $this->c->PUBLIC_URL . "/{$this->c->config->o_avatars_dir}/{$id}.{$type}";
}
}

23
app/Models/SmileyList.php Normal file
View file

@ -0,0 +1,23 @@
<?php
namespace ForkBB\Models;
use ForkBB\Models\Model;
class SmileyList extends Model
{
/**
* Загружает список смайлов из кеша/БД
*
* @return SmileyList
*/
public function init()
{
if ($this->c->Cache->has('smilies')) {
$this->list = $this->c->Cache->get('smilies');
} else {
$this->load();
}
return $this;
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace ForkBB\Models\SmileyList;
use ForkBB\Models\MethodModel;
class Load extends MethodModel
{
/**
* Заполняет модель данными из БД
* Создает кеш
*
* @return SmileyList
*/
public function load()
{
$list = $this->c->DB->query('SELECT text, image FROM ::smilies ORDER BY disp_position')->fetchAll(\PDO::FETCH_KEY_PAIR); //???? text уникальное?
$this->model->list = $list;
$this->c->Cache->set('smilies', $list);
return $this->model;
}
}

30
app/Models/Stats.php Normal file
View file

@ -0,0 +1,30 @@
<?php
namespace ForkBB\Models;
use ForkBB\Models\Model;
class Stats extends Model
{
/**
* Загружает статистику из кеша/БД
*
* @return Stats
*/
public function init()
{
if ($this->c->Cache->has('stats')) {
$list = $this->c->Cache->get('stats');
$this->userTotal = $list['total'];
$this->userLast = $list['last'];
} else {
$this->load();
}
list($topics, $posts) = $this->c->DB->query('SELECT SUM(num_topics), SUM(num_posts) FROM ::forums')->fetch(\PDO::FETCH_NUM);
$this->postTotal = $posts;
$this->topicTotal = $topics;
return $this;
}
}

27
app/Models/Stats/Load.php Normal file
View file

@ -0,0 +1,27 @@
<?php
namespace ForkBB\Models\Stats;
use ForkBB\Models\MethodModel;
class Load extends MethodModel
{
/**
* Заполняет модель данными из БД
* Создает кеш
*
* @return Stats
*/
public function load()
{
$total = $this->c->DB->query('SELECT COUNT(id)-1 FROM ::users WHERE group_id!=?i', [$this->c->GROUP_UNVERIFIED])->fetchColumn();
$last = $this->c->DB->query('SELECT id, username FROM ::users WHERE group_id!=?i ORDER BY registered DESC LIMIT 1', [$this->c->GROUP_UNVERIFIED])->fetch();
$this->model->userTotal = $total;
$this->model->userLast = $last;
$this->c->Cache->set('stats', [
'total' => $total,
'last' => $last,
]);
return $this->model;
}
}

82
app/Models/Stopwords.php Normal file
View file

@ -0,0 +1,82 @@
<?php
namespace ForkBB\Models;
use ForkBB\Models\Model;
class Stopwords extends Model
{
/**
* Загружает список игнорируемых при индексации слов из кеша/БД
*
* @return Stopwords
*/
public function init()
{
$data = $this->c->Cache->get('stopwords');
if (isset($data['id'])
&& isset($data['stopwords'])
&& $data['id'] === $this->generateId()
) {
$this->list = $data['stopwords'];
} else {
$this->load();
}
return $this;
}
/**
* Генерирует id кэша на основе найденных файлов stopwords.txt
*
* @return string
*/
protected function generateId()
{
if (! empty($this->id)) {
return $this->id;
}
$files = glob($this->c->DIR_LANG . '/*/stopwords.txt');
if ($files === false) {
return 'cache_id_error';
}
$this->files = $files;
$hash = [];
foreach ($files as $file) {
$hash[] = $file;
$hash[] = filemtime($file);
}
return $this->id = sha1(implode('|', $hash));
}
/**
* Регенерация кэша массива слов с возвращением результата
*
* @return Stopwords
*/
protected function load()
{
$id = $this->generateId();
if (! is_array($this->files)) {
$this->list = [];
return $this;
}
$stopwords = [];
foreach ($this->files as $file) {
$stopwords = array_merge($stopwords, file($file));
}
// Tidy up and filter the stopwords
$stopwords = array_map('trim', $stopwords);
$stopwords = array_filter($stopwords);
$this->c->Cache->set('stopwords', ['id' => $id, 'stopwords' => $stopwords]);
$this->list = $stopwords;
return $this;
}
}

View file

@ -2,22 +2,11 @@
namespace ForkBB\Models;
use ForkBB\Core\AbstractModel;
use ForkBB\Models\DataModel;
use ForkBB\Core\Container;
class User extends AbstractModel
class User extends DataModel
{
/**
* Контейнер
* @var Container
*/
protected $c;
/**
* @var array
*/
protected $config;
/**
* Время
* @var int
@ -26,63 +15,56 @@ class User extends AbstractModel
/**
* Конструктор
*
* @param array $data
* @param Container $container
*/
public function __construct(array $data, Container $container)
public function __construct(array $data = [], Container $container)
{
$this->now = time();
$this->c = $container;
$this->config = $container->config;
parent::__construct($data);
}
/**
* Выполняется до конструктора родителя
*/
protected function beforeConstruct(array $data)
{
return $data;
parent::__construct($data, $container);
}
protected function getIsUnverified()
{
return $this->groupId == $this->c->GROUP_UNVERIFIED;
return $this->group_id == $this->c->GROUP_UNVERIFIED;
}
protected function getIsGuest()
{
return $this->groupId == $this->c->GROUP_GUEST
return $this->group_id == $this->c->GROUP_GUEST
|| $this->id < 2
|| $this->groupId == $this->c->GROUP_UNVERIFIED;
|| $this->group_id == $this->c->GROUP_UNVERIFIED;
}
protected function getIsAdmin()
{
return $this->groupId == $this->c->GROUP_ADMIN;
return $this->group_id == $this->c->GROUP_ADMIN;
}
protected function getIsAdmMod()
{
return $this->groupId == $this->c->GROUP_ADMIN
|| $this->gModerator == '1';
return $this->group_id == $this->c->GROUP_ADMIN
|| $this->g_moderator == '1';
}
protected function getLogged()
{
return empty($this->data['logged']) ? $this->now : $this->data['logged'];
return empty($this->a['logged']) ? $this->now : $this->a['logged'];
}
protected function getIsLogged()
{
return ! empty($this->data['logged']);
return ! empty($this->a['logged']);
}
protected function getLanguage()
{
$langs = $this->c->Func->getLangs();
$lang = $this->isGuest || empty($this->data['language']) || ! in_array($this->data['language'], $langs)
? $this->config['o_default_lang']
: $this->data['language'];
$lang = $this->isGuest || empty($this->a['language']) || ! in_array($this->a['language'], $langs)
? $this->c->config->o_default_lang
: $this->a['language'];
if (in_array($lang, $langs)) {
return $lang;
@ -95,9 +77,9 @@ class User extends AbstractModel
{
$styles = $this->c->Func->getStyles();
$style = $this->isGuest || empty($this->data['style']) || ! in_array($this->data['style'], $styles)
? $this->config['o_default_style']
: $this->data['style'];
$style = $this->isGuest || empty($this->a['style']) || ! in_array($this->a['style'], $styles)
? $this->c->config->o_default_style
: $this->a['style'];
if (in_array($style, $styles)) {
return $style;

View file

@ -0,0 +1,26 @@
<?php
namespace ForkBB\Models\User;
use ForkBB\Models\MethodModel;
class IsUnique extends MethodModel
{
/**
* Проверка на уникальность имени пользователя
* @param string $username
* @return bool
*/
public function isUnique($username = null)
{
if (null === $username) {
$username = $this->model->username;
}
$vars = [
':name' => $username,
':other' => preg_replace('%[^\p{L}\p{N}]%u', '', $username),
];
$result = $this->c->DB->query('SELECT username FROM ::users WHERE UPPER(username)=UPPER(?s:name) OR UPPER(username)=UPPER(?s:other)', $vars)->fetchAll();
return ! count($result);
}
}

46
app/Models/User/Load.php Normal file
View file

@ -0,0 +1,46 @@
<?php
namespace ForkBB\Models\User;
use ForkBB\Models\MethodModel;
use InvalidArgumentException;
class Load extends MethodModel
{
/**
* Получение пользователя по условию
* @param mixed $value
* @param string $field
* @throws InvalidArgumentException
* @return int|User
*/
public function load($value, $field = 'id')
{
switch ($field) {
case 'id':
$where = 'u.id= ?i';
break;
case 'username':
$where = 'u.username= ?s';
break;
case 'email':
$where = 'u.email= ?s';
break;
default:
throw new InvalidArgumentException('Field not supported');
}
$data = $this->c->DB->query('SELECT u.*, g.* FROM ::users AS u LEFT JOIN ::groups AS g ON u.group_id=g.g_id WHERE ' . $where, [$value])
->fetchAll();
// число найденных пользователей отлично от одного
if (count($data) !== 1) {
return count($data);
}
// найден гость
if ($data[0]['id'] < 2) {
return 1;
}
return $this->model->setAttrs($data[0]);
}
}

View file

@ -1,63 +1,44 @@
<?php
namespace ForkBB\Models\Actions;
namespace ForkBB\Models\User;
use ForkBB\Models\UserCookie;
use ForkBB\Models\UserMapper;
use ForkBB\Models\MethodModel;
use RuntimeException;
class LoadUserFromCookie
class LoadUserFromCookie extends MethodModel
{
protected $mapper;
protected $cookie;
protected $config;
/**
* Конструктор
*
* @param UserMapper $mapper
* @param UserCookie $cookie
* @param array $config
*/
public function __construct(UserMapper $mapper, UserCookie $cookie, array $config)
{
$this->mapper = $mapper;
$this->cookie = $cookie;
$this->config = $config;
}
/**
* Получение юзера на основе куки авторизации
* Обновление куки аутентификации
*
* @return User
*/
public function load()
public function loadCurrent()
{
$id = $this->cookie->id() ?: 1;
$user = $this->mapper->getCurrent($id);
$cookie = $this->c->Cookie;
$this->loadUser((int) $cookie->uId);
if (! $user->isGuest) {
if (! $this->cookie->verifyHash($user->id, $user->password)) {
$user = $this->mapper->getCurrent(1);
} elseif ($this->config['o_check_ip'] == '1'
&& $user->isAdmMod
&& $user->registrationIp != $user->ip
if (! $this->model->isGuest) {
if (! $cookie->verifyUser($this->model)) {
$this->model = $this->loadUser(1);
} elseif ($this->c->config->o_check_ip == '1'
&& $this->model->isAdmMod
&& $this->model->registration_ip != $this->model->ip
) {
$user = $this->mapper->getCurrent(1);
$this->model = $this->loadUser(1);
}
}
$this->cookie->setUserCookie($user->id, $user->password);
$cookie->setUser($this->model);
if ($user->isGuest) {
$user->isBot = $this->isBot();
$user->dispTopics = $this->config['o_disp_topics_default'];
$user->dispPosts = $this->config['o_disp_posts_default'];
$user->timezone = $this->config['o_default_timezone'];
$user->dst = $this->config['o_default_dst'];
$user->language = $this->config['o_default_lang'];
$user->style = $this->config['o_default_style'];
if ($this->model->isGuest) {
$this->model->__isBot = $this->isBot();
$this->model->__disp_topics = $this->c->config->o_disp_topics_default;
$this->model->__disp_posts = $this->c->config->o_disp_posts_default;
$this->model->__timezone = $this->c->config->o_default_timezone;
$this->model->__dst = $this->c->config->o_default_dst;
# $this->model->language = $this->c->config->o_default_lang;
# $this->model->style = $this->c->config->o_default_style;
// быстрое переключение языка - Visman
/* $language = $this->cookie->get('glang');
@ -65,30 +46,64 @@ class LoadUserFromCookie
$language = preg_replace('%[^a-zA-Z0-9_]%', '', $language);
$languages = forum_list_langs();
if (in_array($language, $languages)) {
$user->language = $language;
$this->model->language = $language;
}
} */
} else {
$user->isBot = false;
if (! $user->dispTopics) {
$user->dispTopics = $this->config['o_disp_topics_default'];
$this->model->__isBot = false;
if (! $this->model->disp_topics) {
$this->model->__disp_topics = $this->c->config->o_disp_topics_default;
}
if (! $user->dispPosts) {
$user->dispPosts = $this->config['o_disp_posts_default'];
if (! $this->model->disp_posts) {
$this->model->__disp_posts = $this->c->config->o_disp_posts_default;
}
// Special case: We've timed out, but no other user has browsed the forums since we timed out
if ($user->isLogged && $user->logged < time() - $this->config['o_timeout_visit']) {
$this->mapper->updateLastVisit($user);
$user->lastVisit = $user->logged;
if ($this->model->isLogged && $this->model->logged < time() - $this->c->config->o_timeout_visit) {
$this->model->updateLastVisit();
}
}
return $user;
return $this->model;
}
/**
* Загрузка данных в модель пользователя из базы
*
* @param int $id
*
* @throws RuntimeException
*/
public function loadUser($id)
{
$data = null;
$ip = $this->getIp();
if ($id > 1) {
$data = $this->c->DB->query('SELECT u.*, g.*, o.logged, o.idle FROM ::users AS u INNER JOIN ::groups AS g ON u.group_id=g.g_id LEFT JOIN ::online AS o ON o.user_id=u.id WHERE u.id=?i:id', [':id' => $id])->fetch();
}
if (empty($data['id'])) {
$data = $this->c->DB->query('SELECT u.*, g.*, o.logged, o.last_post, o.last_search FROM ::users AS u INNER JOIN ::groups AS g ON u.group_id=g.g_id LEFT JOIN ::online AS o ON (o.user_id=1 AND o.ident=?s:ip) WHERE u.id=1', [':ip' => $ip])->fetch();
}
if (empty($data['id'])) {
throw new RuntimeException('Unable to fetch guest information. Your database must contain both a guest user and a guest user group.');
}
$this->model->setAttrs($data);
$this->model->__ip = $ip;
}
/**
* Возврат ip пользователя
*
* @return string
*/
protected function getIp()
{
return filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP) ?: 'unknow';
}
/**
* Проверка на робота
* Если робот, то возврат имени
*
* @return false|string
*/
protected function isBot()
@ -125,9 +140,11 @@ class LoadUserFromCookie
/**
* Выделяет имя робота из юзерагента
*
* @param string $agent
* @param string $agentL
* @retrun string
*
* @return string
*/
protected function nameBot($agent, $agentL)
{

71
app/Models/User/Save.php Normal file
View file

@ -0,0 +1,71 @@
<?php
namespace ForkBB\Models\User;
use ForkBB\Models\MethodModel;
use RuntimeException;
class Save extends MethodModel
{
/**
* Обновляет данные пользователя
*
* @throws RuntimeException
*/
public function save()
{
if (empty($this->model->id)) {
throw new RuntimeException('The model does not have ID');
}
$modified = $this->model->getModified();
if (empty($modified)) {
return;
}
$values = $this->model->getAttrs();
$fileds = $this->c->dbMap->users;
$set = $vars = [];
foreach ($modified as $name) {
if (! isset($fileds[$name])) {
continue;
}
$vars[] = $values[$name];
$set[] = $name . '=?' . $fileds[$name];
}
if (empty($set)) {
return;
}
$vars[] = $this->model->id;
$this->c->DB->query('UPDATE ::users SET ' . implode(', ', $set) . ' WHERE id=?i', $vars);
$this->model->resModified();
}
/**
* Добавляет новую запись в таблицу пользователей
*
* @throws RuntimeException
*/
public function insert()
{
$modified = $this->model->getModified();
if (null !== $this->model->id || in_array('id', $modified)) {
throw new RuntimeException('The model has ID');
}
$values = $this->model->getAttrs();
$fileds = $this->c->dbMap->users;
$set = $set2 = $vars = [];
foreach ($modified as $name) {
if (! isset($fileds[$name])) {
continue;
}
$vars[] = $values[$name];
$set[] = $name;
$set2[] = '?' . $fileds[$name];
}
if (empty($set)) {
return;
}
$this->c->DB->query('INSERT INTO ::users (' . implode(', ', $set) . ') VALUES (' . implode(', ', $set2) . ')', $vars);
$this->model->resModified();
return $this->c->DB->lastInsertId();
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace ForkBB\Models\User;
use ForkBB\Models\MethodModel;
class UpdateLastVisit extends MethodModel
{
/**
* Обновляет время последнего визита для конкретного пользователя
*/
public function updateLastVisit()
{
if ($this->model->isLogged) {
$this->c->DB->exec('UPDATE ::users SET last_visit=?i:loggid WHERE id=?i:id', [':loggid' => $this->model->logged, ':id' => $this->model->id]);
$this->model->__last_visit = $this->model->logged;
}
}
}

View file

@ -1,157 +0,0 @@
<?php
namespace ForkBB\Models;
use ForkBB\Core\Cookie;
use ForkBB\Core\Secury;
class UserCookie extends Cookie
{
const NAME = 'user';
const KEY1 = 'key1';
const KEY2 = 'key2';
/**
* Флаг указывающий на режим "запомнить меня"
* @var bool
*/
protected $remember;
/**
* Номер юзера из куки аутентификации
* @var int
*/
protected $uId;
/**
* Время "протухания" куки аутентификации
* @var int
*/
protected $expTime;
/**
* Хэш хэша пароля юзера из куки аутентификации
* @var string
*/
protected $passHash;
/**
* Время жизни куки без запоминания
* @var int
*/
protected $min;
/**
* Время жизни куки с запоминанием
* @var int
*/
protected $max;
/**
* Конструктор
* @param Secury $secury
* @param array $options
* @param int $min
* @param int $max
*/
public function __construct(Secury $secury, array $options, $min, $max)
{
parent::__construct($secury, $options);
$this->min = (int) $min;
$this->max = (int) $max;
$this->init();
}
/**
* Выделение данных из куки аутентификации
*/
protected function init()
{
$ckUser = $this->get(self::NAME);
if (null === $ckUser
|| ! preg_match('%^(\-)?(\d{1,10})_(\d{10})_([a-f\d]{32,})_([a-f\d]{32,})$%Di', $ckUser, $ms)
) {
return;
}
if (2 > $ms[2]
|| time() > $ms[3]
|| ! hash_equals($this->secury->hmac($ms[1] . $ms[2] . $ms[3] . $ms[4], self::KEY1), $ms[5])
) {
return;
}
$this->remember = empty($ms[1]);
$this->uId = (int) $ms[2];
$this->expTime = (int) $ms[3];
$this->passHash = $ms[4];
}
/**
* Возвращает id юзера из куки
* @return int|false
*/
public function id()
{
return $this->uId ?: false;
}
/**
* Проверка хэша пароля
* @param int $id
* @param string $hash
* @return bool
*/
public function verifyHash($id, $hash)
{
return $this->uId === (int) $id
&& hash_equals($this->passHash, $this->secury->hmac($hash . $this->expTime, self::KEY2));
}
/**
* Установка куки аутентификации юзера
* @param int $id
* @param string $hash
* @param bool $remember
* @return bool
*/
public function setUserCookie($id, $hash, $remember = null)
{
if ($id < 2) {
return $this->deleteUserCookie();
}
if ($remember
|| (null === $remember
&& $this->uId === (int) $id
&& $this->remember
)
) {
$expTime = time() + $this->max;
$expire = $expTime;
$pfx = '';
} else {
$expTime = time() + $this->min;
$expire = 0;
$pfx = '-';
}
$passHash = $this->secury->hmac($hash . $expTime, self::KEY2);
$ckHash = $this->secury->hmac($pfx . $id . $expTime . $passHash, self::KEY1);
return $this->set(self::NAME, $pfx . $id . '_' . $expTime . '_' . $passHash . '_' . $ckHash, $expire);
}
/**
* Удаление куки аутентификации юзера
* @return bool
*/
public function deleteUserCookie()
{
if (null === $this->get(self::NAME)) {
return true;
} else {
return $this->delete(self::NAME);
}
}
}

View file

@ -1,177 +0,0 @@
<?php
namespace ForkBB\Models;
use ForkBB\Core\Container;
use ForkBB\Models\User;
use RuntimeException;
use InvalidArgumentException;
class UserMapper
{
/**
* Контейнер
* @var Container
*/
protected $c;
/**
* @var array
*/
protected $config;
/**
* Конструктор
* @param Container $container
*/
public function __construct(Container $container)
{
$this->c = $container;
$this->config = $container->config;
}
/**
* Возврат адреса пользователя
* @return string
*/
protected function getIpAddress()
{
return filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP) ?: 'unknow';
}
/**
* Получение данных для текущего пользователя/гостя
* @param int $id
* @return User
* @throws \RuntimeException
*/
public function getCurrent($id = 1)
{
$ip = $this->getIpAddress();
$user = null;
if ($id > 1) {
$user = $this->c->DB->query('SELECT u.*, g.*, o.logged, o.idle FROM ::users AS u INNER JOIN ::groups AS g ON u.group_id=g.g_id LEFT JOIN ::online AS o ON o.user_id=u.id WHERE u.id=?i:id', [':id' => $id])->fetch();
}
if (empty($user['id'])) {
$user = $this->c->DB->query('SELECT u.*, g.*, o.logged, o.last_post, o.last_search FROM ::users AS u INNER JOIN ::groups AS g ON u.group_id=g.g_id LEFT JOIN ::online AS o ON (o.user_id=1 AND o.ident=?s:ip) WHERE u.id=1', [':ip' => $ip])->fetch();
}
if (empty($user['id'])) {
throw new RuntimeException('Unable to fetch guest information. Your database must contain both a guest user and a guest user group.');
}
$user['ip'] = $ip;
return new User($user, $this->c);
}
/**
* Обновляет время последнего визита для конкретного пользователя
* @param User $user
*/
public function updateLastVisit(User $user)
{
if ($user->isLogged) {
$this->c->DB->exec('UPDATE ::users SET last_visit=?i:loggid WHERE id=?i:id', [':loggid' => $user->logged, ':id' => $user->id]);
}
}
/**
* Получение пользователя по условию
* @param int|string
* @param string $field
* @return int|User
* @throws \InvalidArgumentException
*/
public function getUser($value, $field = 'id')
{
switch ($field) {
case 'id':
$where = 'u.id= ?i';
break;
case 'username':
$where = 'u.username= ?s';
break;
case 'email':
$where = 'u.email= ?s';
break;
default:
throw new InvalidArgumentException('Field not supported');
}
$result = $this->c->DB->query('SELECT u.*, g.* FROM ::users AS u LEFT JOIN ::groups AS g ON u.group_id=g.g_id WHERE ' . $where, [$value])->fetchAll();
// найдено несколько пользователей
if (count($result) !== 1) {
return count($result);
}
// найден гость
if ($result[0]['id'] == 1) {
return 1;
}
return new User($result[0], $this->c);
}
/**
* Проверка на уникальность имени пользователя
* @param string $username
* @return bool
*/
public function isUnique($username)
{
$vars = [
':name' => $username,
':other' => preg_replace('%[^\p{L}\p{N}]%u', '', $username),
];
$result = $this->c->DB->query('SELECT username FROM ::users WHERE UPPER(username)=UPPER(?s:name) OR UPPER(username)=UPPER(?s:other)', $vars)->fetchAll();
return ! count($result);
}
/**
* Обновить данные пользователя
* @param int $id
* @param array $update
*/
public function updateUser($id, array $update)
{
$id = (int) $id;
if ($id < 2 || empty($update)) {
return;
}
$set = $vars = [];
foreach ($update as $field => $value) {
$vars[] = $value;
if (is_int($value)) {
$set[] = $field . ' = ?i';
} else {
$set[] = $field . ' = ?s';
}
}
$vars[] = $id;
$this->c->DB->query('UPDATE ::users SET ' . implode(', ', $set) . ' WHERE id=?i', $vars); //????
}
/**
* Создание нового пользователя
* @param User $user
* @throws
* @return int
*/
public function newUser(User $user)
{
$vars = [
':name' => $user->username,
':group' => $user->groupId,
':password' => $user->password,
':email' => $user->email,
':confirmed' => $user->emailConfirmed,
':setting' => $this->config['o_default_email_setting'],
':timezone' => $this->config['o_default_timezone'],
':dst' => $this->config['o_default_dst'],
':language' => $user->language,
':style' => $user->style,
':registered' => time(),
':ip' => $this->getIpAddress(),
':activate' => $user->activateString,
':mark' => $user->uMarkAllRead,
];
$this->c->DB->query('INSERT INTO ::users (username, group_id, password, email, email_confirmed, email_setting, timezone, dst, language, style, registered, registration_ip, activate_string, u_mark_all_read) VALUES(?s:name, ?i:group, ?s:password, ?s:email, ?i:confirmed, ?i:setting, ?s:timezone, ?i:dst, ?s:language, ?s:style, ?i:registered, ?s:ip, ?s:activate, ?i:mark)', $vars);
return $this->c->DB->lastInsertId();
}
}

View file

@ -3,7 +3,7 @@
namespace ForkBB;
use ForkBB\Core\Container;
use ForkBB\Models\Pages\Page;
use ForkBB\Models\Page;
use RuntimeException;
// боевой
@ -47,8 +47,8 @@ $c->DIR_CONFIG = __DIR__ . '/config';
$c->DIR_CACHE = __DIR__ . '/cache';
$c->DIR_VIEWS = __DIR__ . '/templates';
$c->DIR_LANG = __DIR__ . '/lang';
$c->DATE_FORMATS = [$c->config['o_date_format'], 'Y-m-d', 'Y-d-m', 'd-m-Y', 'm-d-Y', 'M j Y', 'jS M Y'];
$c->TIME_FORMATS = [$c->config['o_time_format'], 'H:i:s', 'H:i', 'g:i:s a', 'g:i a'];
$c->DATE_FORMATS = [$c->config->o_date_format, 'Y-m-d', 'Y-d-m', 'd-m-Y', 'm-d-Y', 'M j Y', 'jS M Y'];
$c->TIME_FORMATS = [$c->config->o_time_format, 'H:i:s', 'H:i', 'g:i:s a', 'g:i a'];
$controllers = ['Routing', 'Primary'];
$page = null;
@ -56,13 +56,12 @@ while (! $page instanceof Page && $cur = array_pop($controllers)) {
$page = $c->$cur;
}
if ($page->getDataForOnline(true)) {
$c->Online->handle($page);
if (null !== $page->onlinePos) {
$c->Online->calc($page);
}
$tpl = $c->View->rendering($page);
if ($tpl !== null && $c->DEBUG > 0) {
$debug = $c->Debug->debug();
$debug = $c->View->rendering($debug);
$debug = $c->View->rendering($c->Debug->debug());
$tpl = str_replace('<!-- debuginfo -->', $debug, $tpl);
}
exit($tpl);

View file

@ -79,13 +79,13 @@ msgid "Ban message"
msgstr "You are banned from this forum."
msgid "Ban message 2"
msgstr "The ban expires at the end of"
msgstr "The ban expires at the end of %s"
msgid "Ban message 3"
msgstr "The administrator or moderator that banned you left the following message:"
msgid "Ban message 4"
msgstr "Please direct any inquiries to the forum administrator at"
msgstr "Please direct any inquiries to the forum administrator at <a href=\"mailto:%1$s\">%1$s</a>."
msgid "Never"
msgstr "Never"

View file

@ -79,13 +79,13 @@ msgid "Ban message"
msgstr "Ваша учетная запись заблокирована."
msgid "Ban message 2"
msgstr "Блокировка заканчивается"
msgstr "Блокировка заканчивается %s"
msgid "Ban message 3"
msgstr "Причина блокирования:"
msgstr "Администратор или модератор, установивший блокировку, оставил следующее сообщение:"
msgid "Ban message 4"
msgstr "Все возникшие вопросы отправляйте администратору форума по адресу"
msgstr "Все возникшие вопросы отправляйте администратору форума по адресу <a href=\"mailto:%1$s\">%1$s</a>."
msgid "Never"
msgstr "Нет"

View file

@ -2,18 +2,18 @@
<section class="f-admin">
<h2>{!! __('Group settings head') !!}</h2>
<div class="f-fdiv">
<form class="f-form" method="post" action="{!! $formAction !!}">
<input type="hidden" name="token" value="{!! $formToken !!}">
<form class="f-form" method="post" action="{!! $p->formAction !!}">
<input type="hidden" name="token" value="{!! $p->formToken !!}">
<dl>
@foreach($form as $key => $cur)
@foreach($p->form as $key => $cur)
<dt>{!! $cur['title'] !!}</dt>
<dd>
@if($cur['type'] == 'text')
<input class="f-ctrl" @if(isset($cur['required'])){!! 'required' !!}@endif type="text" name="{{ $key }}" maxlength="{!! $cur['maxlength'] !!}" value="{{ $cur['value'] }}" tabindex="{!! ++$tabindex !!}">
<input class="f-ctrl" @if(isset($cur['required'])){!! 'required' !!}@endif type="text" name="{{ $key }}" maxlength="{!! $cur['maxlength'] !!}" value="{{ $cur['value'] }}" tabindex="{!! ++$p->tabindex !!}">
@elseif($cur['type'] == 'number')
<input class="f-ctrl" type="number" name="{{ $key }}" min="{!! $cur['min'] !!}" max="{!! $cur['max'] !!}" value="{{ $cur['value'] }}" tabindex="{!! ++$tabindex !!}">
<input class="f-ctrl" type="number" name="{{ $key }}" min="{!! $cur['min'] !!}" max="{!! $cur['max'] !!}" value="{{ $cur['value'] }}" tabindex="{!! ++$p->tabindex !!}">
@elseif($cur['type'] == 'select')
<select class="f-ctrl" name="{{ $key }}" tabindex="{!! ++$tabindex !!}">
<select class="f-ctrl" name="{{ $key }}" tabindex="{!! ++$p->tabindex !!}">
@foreach($cur['options'] as $v => $n)
@if($v == $cur['value'])
<option value="{{ $v }}" selected>{{ $n }}</option>
@ -25,9 +25,9 @@
@elseif($cur['type'] == 'radio')
@foreach($cur['values'] as $v => $n)
@if($v == $cur['value'])
<label class="f-label"><input type="radio" name="{{ $key }}" value="{{ $v }}" checked tabindex="{!! ++$tabindex !!}">{{ $n }}</label>
<label class="f-label"><input type="radio" name="{{ $key }}" value="{{ $v }}" checked tabindex="{!! ++$p->tabindex !!}">{{ $n }}</label>
@else
<label class="f-label"><input type="radio" name="{{ $key }}" value="{{ $v }}" tabindex="{!! ++$tabindex !!}">{{ $n }}</label>
<label class="f-label"><input type="radio" name="{{ $key }}" value="{{ $v }}" tabindex="{!! ++$p->tabindex !!}">{{ $n }}</label>
@endif
@endforeach
@endif
@ -37,11 +37,11 @@
</dd>
@endforeach
</dl>
@if($warn)
<p class="f-finfo">{!! $warn !!}</p>
@if($p->warn)
<p class="f-finfo">{!! $p->warn !!}</p>
@endif
<div>
<input class="f-btn" type="submit" name="submit" value="{!! __('Save') !!}" tabindex="{!! ++$tabindex !!}">
<input class="f-btn" type="submit" name="submit" value="{!! __('Save') !!}" tabindex="{!! ++$p->tabindex !!}">
</div>
</form>
</div>

View file

@ -2,14 +2,14 @@
<section class="f-admin">
<h2>{!! __('Add group subhead') !!}</h2>
<div class="f-fdiv">
<form class="f-form" method="post" action="{!! $formActionNew !!}">
<input type="hidden" name="token" value="{!! $formTokenNew !!}">
<form class="f-form" method="post" action="{!! $p->formActionNew !!}">
<input type="hidden" name="token" value="{!! $p->formTokenNew !!}">
<dl>
<dt>{!! __('New group label') !!}</dt>
<dd>
<select class="f-ctrl" id="id-basegroup" name="basegroup" tabindex="{!! ++$tabindex !!}">
@foreach($groupsNew as $cur)
@if ($cur[0] == $defaultGroup)
<select class="f-ctrl" id="id-basegroup" name="basegroup" tabindex="{!! ++$p->tabindex !!}">
@foreach($p->groupsNew as $cur)
@if ($cur[0] == $p->defaultGroup)
<option value="{!! $cur[0] !!}" selected>{{ $cur[1] }}</option>
@else
<option value="{!! $cur[0] !!}">{{ $cur[1] }}</option>
@ -20,7 +20,7 @@
</dd>
</dl>
<div>
<input class="f-btn" type="submit" name="submit" value="{!! __('Add') !!}" tabindex="{!! ++$tabindex !!}">
<input class="f-btn" type="submit" name="submit" value="{!! __('Add') !!}" tabindex="{!! ++$p->tabindex !!}">
</div>
</form>
</div>
@ -28,14 +28,14 @@
<section class="f-admin">
<h2>{!! __('Default group subhead') !!}</h2>
<div class="f-fdiv">
<form class="f-form" method="post" action="{!! $formActionDefault !!}">
<input type="hidden" name="token" value="{!! $formTokenDefault !!}">
<form class="f-form" method="post" action="{!! $p->formActionDefault !!}">
<input type="hidden" name="token" value="{!! $p->formTokenDefault !!}">
<dl>
<dt>{!! __('Default group label') !!}</dt>
<dd>
<select class="f-ctrl" id="id-defaultgroup" name="defaultgroup" tabindex="{!! ++$tabindex !!}">
@foreach($groupsDefault as $cur)
@if ($cur[0] == $defaultGroup)
<select class="f-ctrl" id="id-defaultgroup" name="defaultgroup" tabindex="{!! ++$p->tabindex !!}">
@foreach($p->groupsDefault as $cur)
@if ($cur[0] == $p->defaultGroup)
<option value="{!! $cur[0] !!}" selected>{{ $cur[1] }}</option>
@else
<option value="{!! $cur[0] !!}">{{ $cur[1] }}</option>
@ -46,7 +46,7 @@
</dd>
</dl>
<div>
<input class="f-btn" type="submit" name="submit" value="{!! __('Save') !!}" tabindex="{!! ++$tabindex !!}">
<input class="f-btn" type="submit" name="submit" value="{!! __('Save') !!}" tabindex="{!! ++$p->tabindex !!}">
</div>
</form>
</div>
@ -56,11 +56,11 @@
<div>
<p>{!! __('Edit groups info') !!}</p>
<ol class="f-grlist">
@foreach($groupsList as $cur)
@foreach($p->groupsList as $cur)
<li>
<a href="{!! $cur[0] !!}" tabindex="{!! ++$tabindex !!}">{{ $cur[1] }}</a>
<a href="{!! $cur[0] !!}" tabindex="{!! ++$p->tabindex !!}">{{ $cur[1] }}</a>
@if($cur[2])
<a class="f-btn" href="{!! $cur[2] !!}" tabindex="{!! ++$tabindex !!}">{!! __('Delete link') !!}</a>
<a class="f-btn" href="{!! $cur[2] !!}" tabindex="{!! ++$p->tabindex !!}">{!! __('Delete link') !!}</a>
@endif
</li>
@endforeach

View file

@ -19,9 +19,9 @@
<div>
<dl>
<dt>{!! __('ForkBB version label') !!}</dt>
<dd>{!! __('ForkBB version data', $revision) !!}</dd>
<dd>{!! __('ForkBB version data', $p->revision) !!}</dd>
<dt>{!! __('Server statistics label') !!}</dt>
<dd><a href="{!! $linkStat !!}">{!! __('View server statistics') !!}</a></dd>
<dd><a href="{!! $p->linkStat !!}">{!! __('View server statistics') !!}</a></dd>
<dt>{!! __('Support label') !!}</dt>
<dd><a href="https://github.com/forkbb/forkbb">GitHub</a></dd>
</dl>

View file

@ -4,24 +4,24 @@
<div>
<dl>
<dt>{!! __('Server load label') !!}</dt>
<dd>{!! __('Server load data', $serverLoad, $numOnline) !!}</dd>
@if($isAdmin)
<dd>{!! __('Server load data', $p->serverLoad, $p->numOnline) !!}</dd>
@if($p->isAdmin)
<dt>{!! __('Environment label') !!}</dt>
<dd>
{!! __('Environment data OS', PHP_OS) !!}<br>
{!! __('Environment data version', phpversion(), '<a href="' . $linkInfo . '">'.__('Show info').'</a>') !!}<br>
{!! __('Environment data acc', $accelerator) !!}
{!! __('Environment data version', phpversion(), '<a href="' . $p->linkInfo . '">'.__('Show info').'</a>') !!}<br>
{!! __('Environment data acc', $p->accelerator) !!}
</dd>
<dt>{!! __('Database label') !!}</dt>
<dd>
{{ $dbVersion }}
@if($tRecords && $tSize)
<br>{!! __('Database data rows', $tRecords) !!}
<br>{!! __('Database data size', $tSize) !!}
{{ $p->dbVersion }}
@if($p->tRecords && $p->tSize)
<br>{!! __('Database data rows', $p->tRecords) !!}
<br>{!! __('Database data size', $p->tSize) !!}
@endif
@if($tOther)
@if($p->tOther)
<br><br>{!! __('Other')!!}
@foreach($tOther as $key => $value)
@foreach($p->tOther as $key => $value)
<br>{{ $key }} = {{ $value }}
@endforeach
@endif

View file

@ -2,12 +2,12 @@
<section class="f-main f-message">
<h2>{{ __('Info') }}</h2>
<p>{!! __('Ban message') !!}</p>
@if(! empty($banned['expire']))
<p>{!! __('Ban message 2') !!} {{ $banned['expire'] }}</p>
@if(! empty($p->ban['expire']))
<p>{!! __('Ban message 2', $p->ban['expire']) !!}</p>
@endif
@if(! empty($banned['message']))
@if(! empty($p->ban['message']))
<p>{!! __('Ban message 3') !!}</p>
<p><strong>{{ $banned['message'] }}</strong></p>
<p><strong>{{ $p->ban['message'] }}</strong></p>
@endif
<p>{!! __('Ban message 4'] !!) <a href="mailto:{{ $adminEmail }}">{{ $adminEmail }}</a>.</p>
<p>{!! __('Ban message 4', $p->adminEmail, $p->adminEmail) !!}</p>
</section>

View file

@ -2,8 +2,8 @@
<section class="f-main f-login">
<div class="f-fdiv f-lrdiv">
<h2>{!! __('Change pass') !!}</h2>
<form class="f-form" method="post" action="{!! $formAction !!}">
<input type="hidden" name="token" value="{!! $formToken !!}">
<form class="f-form" method="post" action="{!! $p->formAction !!}">
<input type="hidden" name="token" value="{!! $p->formToken !!}">
<fieldset>
<dl>
<dt><label class="f-child1 f-req" for="id-password">{!! __('New pass') !!}</label></dt>

View file

@ -1,6 +1,6 @@
@section('crumbs')
<ul class="f-crumbs">
@foreach($crumbs as $cur)
@foreach($p->crumbs as $cur)
@if($cur[2])
<li class="f-crumb"><a href="{!! $cur[0] !!}" class="active">{{ $cur[1] }}</a></li>
@else
@ -10,15 +10,15 @@
</ul>
@endsection
@section('linkpost')
@if($newTopic)
@if($p->newTopic)
<div class="f-link-post">
<a class="f-btn" href="{!! $newTopic !!}">{!! __('Post topic') !!}</a>
<a class="f-btn" href="{!! $p->newTopic !!}">{!! __('Post topic') !!}</a>
</div>
@endif
@endsection
@section('pages')
<nav class="f-pages">
@foreach($pages as $cur)
@foreach($p->pages as $cur)
@if($cur[2])
<span class="f-page active">{{ $cur[1] }}</span>
@elseif($cur[1] === 'space')
@ -34,13 +34,13 @@
</nav>
@endsection
@extends('layouts/main')
@if($forums)
@if($p->forums)
<div class="f-nav-links">
@yield('crumbs')
</div>
<section class="f-subforums">
<ol class="f-ftlist">
@foreach($forums as $id => $cat)
@foreach($p->forums as $id => $cat)
<li id="id-subforums{!! $id !!}" class="f-category">
<h2>{{ __('Sub forum', 2) }}</h2>
<ol class="f-table">
@ -58,20 +58,20 @@
@endif
<div class="f-nav-links">
@yield('crumbs')
@if($newTopic || $pages)
@if($p->newTopic || $p->pages)
<div class="f-links-b clearfix">
@yield('pages')
@yield('linkpost')
</div>
@endif
</div>
@if(empty($topics))
@if(!$p->topics)
<section class="f-main f-message">
<h2>{!! __('Empty forum') !!}</h2>
</section>
@else
<section class="f-main f-forum">
<h2>{{ $forumName }}</h2>
<h2>{{ $p->forumName }}</h2>
<div class="f-ftlist">
<ol class="f-table">
<li class="f-row f-thead" value="0">
@ -79,7 +79,7 @@
<div class="f-hcell f-cstats">{!! __('Stats') !!}</div>
<div class="f-hcell f-clast">{!! __('Last post') !!}</div>
</li>
@foreach($topics as $topic)
@foreach($p->topics as $topic)
@if($topic['moved_to'])
<li id="topic-{!! $topic['id']!!}" class="f-row f-fredir">
<div class="f-cell f-cmain">
@ -160,7 +160,7 @@
</div>
</section>
<div class="f-nav-links">
@if($newTopic || $pages)
@if($p->newTopic || $p->pages)
<div class="f-links-a clearfix">
@yield('linkpost')
@yield('pages')

View file

@ -1,8 +1,8 @@
@extends('layouts/main')
@if($forums)
@if($p->forums)
<section class="f-main">
<ol class="f-ftlist">
@foreach($forums as $id => $cat)
@foreach($p->forums as $id => $cat)
<li id="cat-{!! $id !!}" class="f-category">
<h2>{{ $cat['name'] }}</h2>
<ol class="f-table">

View file

@ -1,15 +1,15 @@
@extends('layouts/main')
<div class="f-main clearfix">
<aside class="f-admin-menu">
@if(!empty($aNavigation))
@if($p->aNavigation)
<nav class="admin-nav f-menu">
<input id="admin-nav-checkbox" style="display: none;" type="checkbox">
<label class="f-menu-toggle" for="admin-nav-checkbox"></label>
@foreach($aNavigation as $aNameSub => $aNavigationSub)
@foreach($p->aNavigation as $aNameSub => $aNavigationSub)
<h2 class="f-menu-items">{!! __($aNameSub) !!}</h2>
<ul class="f-menu-items">
@foreach($aNavigationSub as $key => $val)
@if($key == $aIndex)
@if($key == $p->aIndex)
<li><a id="anav-{{ $key }}" class="active" href="{!! $val[0] !!}">{!! $val[1] !!}</a></li>
@else
<li><a id="anav-{{ $key }}" href="{!! $val[0] !!}">{!! $val[1] !!}</a></li>

View file

@ -1,7 +1,7 @@
<section class="f-debug">
<h2>{!! __('Debug table') !!}</h2>
<p class="f-debugtime">[ {!! __('Querytime', $time, $numQueries) !!} - {!! __('Memory usage', $memory) !!} {!! __('Peak usage', $peak) !!} ]</p>
@if($queries)
<p class="f-debugtime">[ {!! __('Querytime', $p->time, $p->numQueries) !!} - {!! __('Memory usage', $p->memory) !!} {!! __('Peak usage', $p->peak) !!} ]</p>
@if($p->queries)
<table>
<thead>
<tr>
@ -10,14 +10,14 @@
</tr>
</thead>
<tbody>
@foreach($queries as $cur)
@foreach($p->queries as $cur)
<tr>
<td class="tcl">{{ $cur[1] }}</td>
<td class="tcr">{{ $cur[0] }}</td>
</tr>
@endforeach
<tr>
<td class="tcl">{{ $total }}</td>
<td class="tcl">{{ $p->total }}</td>
<td class="tcr"></td>
</tr>
</tbody>

View file

@ -24,11 +24,11 @@
@if($cur['type'] === 'textarea')
<textarea{!! empty($cur['required']) ? '' : ' required' !!} class="f-ctrl" id="id-{{ $key }}" name="{{ $key }}">{{ $cur['value'] or '' }}</textarea>
@if(isset($cur['bb']))
<ul class="f-child5">
<ul class="f-child5">
@foreach($cur['bb'] as $val)
<li><span><a href="{!! $val[0] !!}">{!! $val[1] !!}</a> {!! $val[2] !!}</span></li>
<li><span><a href="{!! $val[0] !!}">{!! $val[1] !!}</a> {!! $val[2] !!}</span></li>
@endforeach
</ul>
</ul>
@endif
@elseif($cur['type'] === 'text')
<input{!! empty($cur['required']) ? '' : ' required' !!} class="f-ctrl" id="id-{{ $key }}" name="{{ $key }}" type="text" maxlength="{{ $cur['maxlength'] or '' }}" pattern="{{ $cur['pattern'] or '' }}" value="{{ $cur['value'] or '' }}">

View file

@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{!! __('ForkBB Installation') !!}</title>
@foreach($pageHeads as $cur)
@foreach($p->pageHeads as $cur)
<{!! $cur !!}>
@endforeach
</head>
@ -16,18 +16,18 @@
<p class="f-description">{!! __('Welcome') !!}</p>
</div>
</header>
@if($fIswev)
@if($p->fIswev)
@include('layouts/iswev')
@endif
@if(is_array($installLangs))
@if(is_array($p->installLangs))
<section class="f-install">
<div class="f-fdiv">
<h2>{!! __('Choose install language') !!}</h2>
<form class="f-form" method="post" action="{!! $formAction !!}">
<form class="f-form" method="post" action="{!! $p->formAction !!}">
<div>
<label class="f-child1">{!! __('Install language') !!}</label>
<select class="f-ctrl" id="id-installlang" name="installlang">
@foreach($installLangs as $cur)
@foreach($p->installLangs as $cur)
@if(isset($cur[1]))
<option value="{{ $cur[0] }}" selected>{{ $cur[0] }}</option>
@else
@ -44,12 +44,12 @@
</div>
</section>
@endif
@if(empty($fIswev['e']))
@if(empty($p->fIswev['e']))
<section class="f-main f-install">
<div class="f-fdiv">
<h2>{!! __('Install', $rev) !!}</h2>
<form class="f-form" method="post" action="{!! $formAction !!}" autocomplete="off">
<input type="hidden" name="installlang" value="{!! $installLang !!}">
<h2>{!! __('Install', $p->rev) !!}</h2>
<form class="f-form" method="post" action="{!! $p->formAction !!}" autocomplete="off">
<input type="hidden" name="installlang" value="{!! $p->installLang !!}">
<div class="f-finfo">
<h3>{!! __('Database setup') !!}</h3>
<p>{!! __('Info 1') !!}</p>
@ -57,7 +57,7 @@
<div>
<label class="f-child1 f-req">{!! __('Database type') !!}</label>
<select class="f-ctrl" id="id-dbtype" name="dbtype">
@foreach($dbTypes as $key => $cur)
@foreach($p->dbTypes as $key => $cur)
@if(empty($cur[1]))
<option value="{{ $key }}">{{ $cur[0] }}</option>
@else
@ -69,17 +69,17 @@
</div>
<div>
<label class="f-child1 f-req" for="id-dbhost">{!! __('Database server hostname') !!}</label>
<input required class="f-ctrl" id="id-dbhost" type="text" name="dbhost" value="{{ $dbhost }}">
<input required class="f-ctrl" id="id-dbhost" type="text" name="dbhost" value="{{ $p->dbhost }}">
<label class="f-child4">{!! __('Info 3') !!}</label>
</div>
<div>
<label class="f-child1 f-req" for="id-dbname">{!! __('Database name') !!}</label>
<input required class="f-ctrl" id="id-dbname" type="text" name="dbname" value="{{ $dbname }}">
<input required class="f-ctrl" id="id-dbname" type="text" name="dbname" value="{{ $p->dbname }}">
<label class="f-child4">{!! __('Info 4') !!}</label>
</div>
<div>
<label class="f-child1" for="id-dbuser">{!! __('Database username') !!}</label>
<input class="f-ctrl" id="id-dbuser" type="text" name="dbuser" value="{{ $dbuser }}">
<input class="f-ctrl" id="id-dbuser" type="text" name="dbuser" value="{{ $p->dbuser }}">
</div>
<div>
<label class="f-child1" for="id-dbpass">{!! __('Database password') !!}</label>
@ -88,7 +88,7 @@
</div>
<div>
<label class="f-child1" for="id-dbprefix">{!! __('Table prefix') !!}</label>
<input class="f-ctrl" id="id-dbprefix" type="text" name="dbprefix" value="{{ $dbprefix }}" maxlength="40" pattern="^[a-zA-Z][a-zA-Z\d_]*$">
<input class="f-ctrl" id="id-dbprefix" type="text" name="dbprefix" value="{{ $p->dbprefix }}" maxlength="40" pattern="^[a-zA-Z][a-zA-Z\d_]*$">
<label class="f-child4">{!! __('Info 6') !!}</label>
</div>
<div class="f-finfo">
@ -97,7 +97,7 @@
</div>
<div>
<label class="f-child1 f-req" for="id-username">{!! __('Administrator username') !!}</label>
<input required class="f-ctrl" id="id-username" type="text" name="username" value="{{ $username }}" maxlength="25" pattern="^.{2,25}$">
<input required class="f-ctrl" id="id-username" type="text" name="username" value="{{ $p->username }}" maxlength="25" pattern="^.{2,25}$">
<label class="f-child4">{!! __('Info 8') !!}</label>
</div>
<div>
@ -107,7 +107,7 @@
</div>
<div>
<label class="f-child1 f-req" for="id-email">{!! __('Administrator email') !!}</label>
<input required class="f-ctrl" id="id-email" type="text" name="email" value="{{ $email }}" maxlength="80" pattern=".+@.+">
<input required class="f-ctrl" id="id-email" type="text" name="email" value="{{ $p->email }}" maxlength="80" pattern=".+@.+">
<label class="f-child4">{!! __('Info 10') !!}</label>
</div>
<div class="f-finfo">
@ -116,21 +116,21 @@
</div>
<div>
<label class="f-child1 f-req" for="id-title">{!! __('Board title') !!}</label>
<input required class="f-ctrl" id="id-title" type="text" name="title" value="{{ $title }}">
<input required class="f-ctrl" id="id-title" type="text" name="title" value="{{ $p->title }}">
</div>
<div>
<label class="f-child1 f-req" for="id-descr">{!! __('Board description') !!}</label>
<input required class="f-ctrl" id="id-descr" type="text" name="descr" value="{{ $descr }}">
<input required class="f-ctrl" id="id-descr" type="text" name="descr" value="{{ $p->descr }}">
</div>
<div>
<label class="f-child1 f-req" for="id-baseurl">{!! __('Base URL') !!}</label>
<input required class="f-ctrl" id="id-baseurl" type="text" name="baseurl" value="{{ $baseurl }}">
<input required class="f-ctrl" id="id-baseurl" type="text" name="baseurl" value="{{ $p->baseurl }}">
</div>
@if(is_array($defaultLangs))
@if(is_array($p->defaultLangs))
<div>
<label class="f-child1 f-req">{!! __('Default language') !!}</label>
<select class="f-ctrl" id="id-defaultlang" name="defaultlang">
@foreach($defaultLangs as $cur)
@foreach($p->defaultLangs as $cur)
@if(isset($cur[1]))
<option value="{{ $cur[0] }}" selected>{{ $cur[0] }}</option>
@else
@ -140,12 +140,12 @@
</select>
</div>
@else
<input type="hidden" name="defaultlang" value="{!! $defaultLangs !!}">
<input type="hidden" name="defaultlang" value="{!! $p->defaultLangs !!}">
@endif
<div>
<label class="f-child1 f-req">{!! __('Default style') !!}</label>
<select class="f-ctrl" id="id-defaultstyle" name="defaultstyle">
@foreach($defaultStyles as $cur)
@foreach($p->defaultStyles as $cur)
@if(isset($cur[1]))
<option value="{{ $cur[0] }}" selected>{{ $cur[0] }}</option>
@else

View file

@ -1,48 +1,48 @@
@if(isset($fIswev['i']))
@if(isset($p->fIswev['i']))
<section class="f-iswev f-info">
<h2>Info message</h2>
<ul>
@foreach($fIswev['i'] as $cur)
@foreach($p->fIswev['i'] as $cur)
<li class="f-icontent">{!! $cur !!}</li>
@endforeach
</ul>
</section>
@endif
@if(isset($fIswev['s']))
@if(isset($p->fIswev['s']))
<section class="f-iswev f-success">
<h2>Successful operation message</h2>
<ul>
@foreach($fIswev['s'] as $cur)
@foreach($p->fIswev['s'] as $cur)
<li class="f-scontent">{!! $cur !!}</li>
@endforeach
</ul>
</section>
@endif
@if(isset($fIswev['w']))
@if(isset($p->fIswev['w']))
<section class="f-iswev f-warning">
<h2>Warning message</h2>
<ul>
@foreach($fIswev['w'] as $cur)
@foreach($p->fIswev['w'] as $cur)
<li class="f-wcontent">{!! $cur !!}</li>
@endforeach
</ul>
</section>
@endif
@if(isset($fIswev['e']))
@if(isset($p->fIswev['e']))
<section class="f-iswev f-error">
<h2>Error message</h2>
<ul>
@foreach($fIswev['e'] as $cur)
@foreach($p->fIswev['e'] as $cur)
<li class="f-econtent">{!! $cur !!}</li>
@endforeach
</ul>
</section>
@endif
@if(isset($fIswev['v']))
@if(isset($p->fIswev['v']))
<section class="f-iswev f-validation">
<h2>Validation message</h2>
<ul>
@foreach($fIswev['v'] as $cur)
@foreach($p->fIswev['v'] as $cur)
<li class="f-vcontent">{!! $cur !!}</li>
@endforeach
</ul>

View file

@ -3,8 +3,8 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $pageTitle }}</title>
@foreach($pageHeaders as $cur)
<title>{{ $p->pageTitle }}</title>
@foreach($p->pageHeaders as $cur)
<{!! $cur !!}>
@endforeach
</head>
@ -12,16 +12,16 @@
<div class="f-wrap">
<header class="f-header">
<div class="f-title">
<h1><a href="{!! $fRootLink !!}">{{ $fTitle }}</a></h1>
<p class="f-description">{!! $fDescription !!}</p>
<h1><a href="{!! $p->fRootLink !!}">{{ $p->fTitle }}</a></h1>
<p class="f-description">{!! $p->fDescription !!}</p>
</div>
@if(!empty($fNavigation))
@if($p->fNavigation)
<nav class="main-nav f-menu">
<input id="main-nav-checkbox" style="display: none;" type="checkbox">
<label class="f-menu-toggle" for="main-nav-checkbox"></label>
<ul class="f-menu-items">
@foreach($fNavigation as $key => $val)
@if($key == $fIndex)
@foreach($p->fNavigation as $key => $val)
@if($key == $p->fIndex)
<li><a id="nav-{{ $key }}" class="active" href="{!! $val[0] !!}">{!! $val[1] !!}</a></li>
@else
<li><a id="nav-{{ $key }}" href="{!! $val[0] !!}">{!! $val[1] !!}</a></li>
@ -31,13 +31,13 @@
</nav>
@endif
</header>
@if($fAnnounce)
@if($p->fAnnounce)
<section class="f-announce">
<h2>{!! __('Announcement') !!}</h2>
<p class="f-ancontent">{!! $fAnnounce !!}</p>
<p class="f-ancontent">{!! $p->fAnnounce !!}</p>
</section>
@endif
@if($fIswev)
@if($p->fIswev)
@include('layouts/iswev')
@endif
@yield('content')

View file

@ -3,9 +3,9 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="refresh" content="{!! $timeout !!};URL={{ $link }}">
<title>{{ $pageTitle }}</title>
@foreach($pageHeaders as $cur)
<meta http-equiv="refresh" content="{!! $p->timeout !!};URL={{ $p->link }}">
<title>{{ $p->pageTitle }}</title>
@foreach($p->pageHeaders as $cur)
<{!! $cur !!}>
@endforeach
</head>
@ -13,8 +13,8 @@
<div class="f-wrap">
<section class="f-main f-redirect">
<h2>{!! __('Redirecting') !!}</h2>
<p>{!! $message !!}</p>
<p><a href="{{ $link }}">{!! __('Click redirect') !!}</a></p>
<p>{!! $p->message !!}</p>
<p><a href="{{ $p->link }}">{!! __('Click redirect') !!}</a></p>
</section>
<!-- debuginfo -->
</div>

View file

@ -1,32 +1,32 @@
<section class="f-stats">
<h2>{!! __('Stats info') !!}</h2>
<div class="clearfix">
@if($stats)
@if($p->stats)
<dl class="right">
<dt>{!! __('Board stats') !!}</dt>
<dd>{!! __('No of users') !!} <strong>{!! $stats['total_users'] !!}</strong></dd>
<dd>{!! __('No of topics') !!} <strong>{!! $stats['total_topics'] !!}</strong></dd>
<dd>{!! __('No of posts') !!} <strong>{!! $stats['total_posts'] !!}</strong></dd>
<dd>{!! __('No of users') !!} <strong>{!! $p->stats['total_users'] !!}</strong></dd>
<dd>{!! __('No of topics') !!} <strong>{!! $p->stats['total_topics'] !!}</strong></dd>
<dd>{!! __('No of posts') !!} <strong>{!! $p->stats['total_posts'] !!}</strong></dd>
</dl>
@endif
<dl class="left">
<dt>{!! __('User info') !!}</dt>
@if($stats && is_string($stats['newest_user']))
<dd>{!! __('Newest user') !!} {{ $stats['newest_user'] }}</dd>
@elseif($stats)
<dd>{!! __('Newest user') !!} <a href="{!! $stats['newest_user'][0] !!}">{{ $stats['newest_user'][1] }}</a></dd>
@if($p->stats && is_string($p->stats['newest_user']))
<dd>{!! __('Newest user') !!} {{ $p->stats['newest_user'] }}</dd>
@elseif($p->stats)
<dd>{!! __('Newest user') !!} <a href="{!! $p->stats['newest_user'][0] !!}">{{ $p->stats['newest_user'][1] }}</a></dd>
@endif
@if($online)
<dd>{!! __('Visitors online', $online['number_of_users'], $online['number_of_guests']) !!}</dd>
@if($p->online)
<dd>{!! __('Visitors online', $p->online['number_of_users'], $p->online['number_of_guests']) !!}</dd>
@endif
@if($stats)
<dd>{!! __('Most online', $online['max'], $online['max_time']) !!}</dd>
@if($p->stats)
<dd>{!! __('Most online', $p->online['max'], $p->online['max_time']) !!}</dd>
@endif
</dl>
@if($online && $online['list'])
@if($p->online && $p->online['list'])
<dl class="f-inline f-onlinelist"><!-- inline -->
<dt>{!! __('Online users') !!}</dt>
@foreach($online['list'] as $cur)
@foreach($p->online['list'] as $cur)
@if(is_string($cur))
<dd>{{ $cur }}</dd>
@else

View file

@ -2,25 +2,25 @@
<section class="f-main f-login">
<div class="f-fdiv f-lrdiv">
<h2>{!! __('Login') !!}</h2>
<form class="f-form" method="post" action="{!! $formAction !!}">
<input type="hidden" name="token" value="{!! $formToken !!}">
<input type="hidden" name="redirect" value="{{ $redirect }}">
<form class="f-form" method="post" action="{!! $p->formAction !!}">
<input type="hidden" name="token" value="{!! $p->formToken !!}">
<input type="hidden" name="redirect" value="{{ $p->redirect }}">
<fieldset>
<dl>
<dt><label class="f-child1 f-req" for="id-username">{!! __('Username') !!}</label></dt>
<dd>
<input required class="f-ctrl" id="id-username" type="text" name="username" value="{{ $username }}" maxlength="25" autofocus spellcheck="false" tabindex="1">
<input required class="f-ctrl" id="id-username" type="text" name="username" value="{{ $p->username }}" maxlength="25" autofocus spellcheck="false" tabindex="1">
</dd>
</dl>
<dl>
<dt><label class="f-child1 f-req" for="id-password">{!! __('Passphrase') !!}<a class="f-forgetlink" href="{!! $forgetLink !!}" tabindex="5">{!! __('Forgotten pass') !!}</a></label></dt>
<dt><label class="f-child1 f-req" for="id-password">{!! __('Passphrase') !!}<a class="f-forgetlink" href="{!! $p->forgetLink !!}" tabindex="5">{!! __('Forgotten pass') !!}</a></label></dt>
<dd>
<input required class="f-ctrl" id="id-password" type="password" name="password" tabindex="2">
</dd>
</dl>
<dl>
<dt></dt>
@if($save)
@if($p->save)
<dd><label class="f-child2"><input type="checkbox" name="save" value="1" tabindex="3" checked>{!! __('Remember me') !!}</label></dd>
@else
<dd><label class="f-child2"><input type="checkbox" name="save" value="1" tabindex="3">{!! __('Remember me') !!}</label></dd>
@ -32,9 +32,9 @@
</p>
</form>
</div>
@if($regLink)
@if($p->regLink)
<div class="f-fdiv f-lrdiv">
<p class="f-child3"><a href="{!! $regLink !!}" tabindex="6">{!! __('Not registered') !!}</a></p>
<p class="f-child3"><a href="{!! $p->regLink !!}" tabindex="6">{!! __('Not registered') !!}</a></p>
</div>
@endif
</section>

View file

@ -1,5 +1,5 @@
@extends('layouts/main')
<section class="f-main f-maintenance">
<h2>{{ __('Maintenance') }}</h2>
<p>{!! $maintenanceMessage !!}</p>
<p>{!! $p->maintenanceMessage !!}</p>
</section>

View file

@ -1,8 +1,8 @@
@extends('layouts/main')
<section class="f-main f-message">
<h2>{!! __('Info') !!}</h2>
<p>{!! $message !!}</p>
@if($back)
<p>{!! $p->message !!}</p>
@if($p->back)
<p><a href="javascript: history.go(-1)">{!! __('Go back') !!}</a></p>
@endif
</section>

Some files were not shown because too many files have changed in this diff Show more