Mail, Auth, Register, UserMapper, Validator
This commit is contained in:
parent
841694800d
commit
a1f5f61a50
43 changed files with 1621 additions and 444 deletions
|
@ -45,7 +45,9 @@ class Routing
|
|||
|
||||
// регистрация
|
||||
if ($config['o_regs_allow'] == '1') {
|
||||
$r->add('GET', '/registration', 'Registration:reg', 'Registration'); //????
|
||||
$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');
|
||||
}
|
||||
} else {
|
||||
// выход
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* based on code Container https://github.com/artoodetoo/container
|
||||
* based on Container https://github.com/artoodetoo/container
|
||||
* by artoodetoo
|
||||
*/
|
||||
namespace ForkBB\Core;
|
||||
|
|
|
@ -1520,6 +1520,11 @@ foreach ($styles as $temp)
|
|||
'allow_null' => false,
|
||||
'default' => '\'\''
|
||||
),
|
||||
'email_confirmed' => array(
|
||||
'datatype' => 'TINYINT(1)',
|
||||
'allow_null' => false,
|
||||
'default' => '0'
|
||||
),
|
||||
'title' => array(
|
||||
'datatype' => 'VARCHAR(50)',
|
||||
'allow_null' => true
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace ForkBB\Core;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class Mail
|
||||
{
|
||||
/**
|
||||
|
@ -14,6 +16,68 @@ class Mail
|
|||
*/
|
||||
protected $language;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $to = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $headers = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $message;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $smtp;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $EOL;
|
||||
|
||||
/**
|
||||
* @var Resource
|
||||
*/
|
||||
protected $connect;
|
||||
|
||||
/**
|
||||
* var int
|
||||
*/
|
||||
protected $auth = 0;
|
||||
|
||||
/**
|
||||
* Конструктор
|
||||
* @param mixed $host
|
||||
* @param mixed $user
|
||||
* @param mixed $pass
|
||||
* @param mixed $ssl
|
||||
* @param mixed $eol
|
||||
*/
|
||||
public function __construct($host, $user, $pass, $ssl, $eol)
|
||||
{
|
||||
if (is_string($host) && strlen(trim($host)) > 0 ) {
|
||||
list ($host, $port) = explode(':', $host);
|
||||
if (empty($port) || $port < 1 || $port > 65535) {
|
||||
$port = 25;
|
||||
}
|
||||
$this->smtp = [
|
||||
'host' => ($ssl ? 'ssl://' : '') . $host,
|
||||
'port' => (int) $port,
|
||||
'user' => (string) $user,
|
||||
'pass' => (string) $pass,
|
||||
];
|
||||
$this->EOL = "\r\n";
|
||||
} else {
|
||||
$this->EOL = in_array($eol, ["\r\n", "\n", "\r"]) ? $eol : PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Валидация email
|
||||
* @param mixed $email
|
||||
|
@ -23,9 +87,152 @@ class Mail
|
|||
{
|
||||
return is_string($email)
|
||||
&& strlen($email) <= 80
|
||||
&& trim($email) === $email
|
||||
&& preg_match('%^.+@.+$%D', $email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Сброс
|
||||
* @return Mail
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->to = [];
|
||||
$this->headers = [];
|
||||
$this->message = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Задает тему письма
|
||||
* @param string $subject
|
||||
* @return Mail
|
||||
*/
|
||||
public function setSubject($subject)
|
||||
{
|
||||
$this->headers['Subject'] = $this->encodeText(preg_replace('%[\x00-\x1F]%', '', trim($subject)));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет заголовок To
|
||||
* @param string|array $email
|
||||
* @param string $name
|
||||
* @return Mail
|
||||
*/
|
||||
public function addTo($email, $name = null)
|
||||
{
|
||||
if (is_array($email)) {
|
||||
} else {
|
||||
$email = preg_split('%[,\n\r]%', (string) $email, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
foreach($email as $cur) {
|
||||
$cur = trim((string) $cur);
|
||||
if ($this->valid($cur)) {
|
||||
$this->to[] = $this->formatAddress($cur, $name);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Задает заголовок To
|
||||
* @param string|array $email
|
||||
* @param string $name
|
||||
* @return Mail
|
||||
*/
|
||||
public function setTo($email, $name = null)
|
||||
{
|
||||
$this->to = [];
|
||||
return $this->addTo($email, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Задает заголовок From
|
||||
* @param string $email
|
||||
* @param string $name
|
||||
* @return Mail
|
||||
*/
|
||||
public function setFrom($email, $name = null)
|
||||
{
|
||||
if ($this->valid($email)) {
|
||||
$this->headers['From'] = $this->formatAddress($email, $name);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Задает заголовок Reply-To
|
||||
* @param string $email
|
||||
* @param string $name
|
||||
* @return Mail
|
||||
*/
|
||||
public function setReplyTo($email, $name = null)
|
||||
{
|
||||
if ($this->valid($email)) {
|
||||
$this->headers['Reply-To'] = $this->formatAddress($email, $name);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Форматирование адреса
|
||||
* @param string|array $email
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
protected function formatAddress($email, $name = null)
|
||||
{
|
||||
$email = $this->filterEmail($email);
|
||||
if (null === $name || ! is_string($name) || strlen(trim($name)) == 0) {
|
||||
return $email;
|
||||
} else {
|
||||
$name = $this->encodeText($this->filterName($name));
|
||||
return sprintf('"%s" <%s>', $name, $email);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Кодирование заголовка/имени
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeText($str)
|
||||
{
|
||||
if (preg_match('%[^\x20-\x7F]%', $str)) {
|
||||
return '=?UTF-8?B?' . base64_encode($str) . '?=';
|
||||
} else {
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Фильтрация email
|
||||
* @param string $email
|
||||
* @return string
|
||||
*/
|
||||
protected function filterEmail($email)
|
||||
{
|
||||
return preg_replace('%[\x00-\x1F",<>]%', '', $email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Фильтрация имени
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
protected function filterName($name)
|
||||
{
|
||||
return strtr(trim($name), [
|
||||
"\r" => '',
|
||||
"\n" => '',
|
||||
"\t" => '',
|
||||
'"' => '\'',
|
||||
'<' => '[',
|
||||
'>' => ']',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Установка папки для поиска шаблонов писем
|
||||
* @param string $folder
|
||||
|
@ -49,15 +256,229 @@ class Mail
|
|||
}
|
||||
|
||||
/**
|
||||
* Отправка письма
|
||||
* @param string $email
|
||||
* Задает сообщение по шаблону
|
||||
* @param string $tpl
|
||||
* @param array $data
|
||||
* @throws \RuntimeException
|
||||
* @return Mail
|
||||
*/
|
||||
public function setTpl($tpl, array $data)
|
||||
{
|
||||
$file = rtrim($this->folder, '\\/') . '/' . $this->language . '/mail/' . $tpl;
|
||||
if (! file_exists($file)) {
|
||||
throw new RuntimeException('Tpl not found');
|
||||
}
|
||||
$tpl = trim(file_get_contents($file));
|
||||
foreach ($data as $key => $val) {
|
||||
$tpl = str_replace('<' . $key . '>', (string) $val, $tpl);
|
||||
}
|
||||
list($subject, $tpl) = explode("\n", $tpl, 2);
|
||||
if (! isset($tpl)) {
|
||||
throw new RuntimeException('Tpl empty');
|
||||
}
|
||||
$this->setSubject(substr($subject, 8));
|
||||
return $this->setMessage($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Задает сообщение
|
||||
* @param string $message
|
||||
* @throws \RuntimeException
|
||||
* @return Mail
|
||||
*/
|
||||
public function setMessage($message)
|
||||
{
|
||||
$this->message = str_replace("\0", $this->EOL,
|
||||
str_replace(["\r\n", "\n", "\r"], "\0",
|
||||
str_replace("\0", '', trim($message))));
|
||||
// $this->message = wordwrap ($this->message, 75, $this->EOL, false);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправляет письмо
|
||||
* @return bool
|
||||
*/
|
||||
public function send($email, $tpl, array $data)
|
||||
public function send()
|
||||
{
|
||||
var_dump($data);
|
||||
if (empty($this->to)) {
|
||||
throw new RuntimeException('No recipient(s)');
|
||||
}
|
||||
if (empty($this->headers['From'])) {
|
||||
throw new RuntimeException('No sender');
|
||||
}
|
||||
if (! isset($this->headers['Subject'])) {
|
||||
throw new RuntimeException('Subject empty');
|
||||
}
|
||||
if (trim($this->message) == '') {
|
||||
throw new RuntimeException('Message empty');
|
||||
}
|
||||
|
||||
$this->headers = array_replace($this->headers, [
|
||||
'Date' => gmdate('r'),
|
||||
'MIME-Version' => '1.0',
|
||||
'Content-transfer-encoding' => '8bit',
|
||||
'Content-type' => 'text/plain; charset=utf-8',
|
||||
'X-Mailer' => 'ForkBB Mailer',
|
||||
]);
|
||||
|
||||
if (is_array($this->smtp)) {
|
||||
return $this->smtp();
|
||||
} else {
|
||||
return $this->mail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправка письма через функцию mail
|
||||
* @return bool
|
||||
*/
|
||||
protected function mail()
|
||||
{
|
||||
$to = implode(', ', $this->to);
|
||||
$subject = $this->headers['Subject'];
|
||||
$headers = $this->headers;
|
||||
unset($headers['Subject']);
|
||||
$headers = $this->strHeaders($headers);
|
||||
return @mail($to, $subject, $this->message, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Переводит заголовки из массива в строку
|
||||
* @param array $headers
|
||||
* @return string
|
||||
*/
|
||||
protected function strHeaders(array $headers)
|
||||
{
|
||||
foreach ($headers as $key => &$value) {
|
||||
$value = $key . ': ' . $value;
|
||||
}
|
||||
unset($value);
|
||||
return join($this->EOL, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправка письма через smtp
|
||||
* @throws \RuntimeException
|
||||
* @return bool
|
||||
*/
|
||||
protected function smtp()
|
||||
{
|
||||
// подлючение
|
||||
if (! is_resource($this->connect)) {
|
||||
if (($connect = @fsockopen($this->smtp['host'], $this->smtp['port'], $errno, $errstr, 5)) === false) {
|
||||
throw new RuntimeException('Could not connect to smtp host "' . $this->smtp['host'] . '" (' . $errno . ') (' . $errstr . ')');
|
||||
}
|
||||
stream_set_timeout($connect, 5);
|
||||
$this->connect = $connect;
|
||||
$this->smtpData(null, '220');
|
||||
}
|
||||
|
||||
$message = $this->EOL . str_replace("\n.", "\n..", $this->EOL . $this->message) . $this->EOL . '.';
|
||||
$headers = $this->strHeaders($this->headers);
|
||||
|
||||
// цикл по получателям
|
||||
foreach ($this->to as $to) {
|
||||
$this->smtpHello();
|
||||
$this->smtpData('MAIL FROM: <' . $this->getEmailFrom($this->headers['From']). '>', '250');
|
||||
$this->smtpData('RCPT TO: <' . $this->getEmailFrom($to) . '>', ['250', '251']);
|
||||
$this->smtpData('DATA', '354');
|
||||
$this->smtpData('To: ' . $to . $this->EOL . $headers . $message, '250');
|
||||
$this->smtpData('NOOP', '250');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
// завершение сеанса smtp
|
||||
if (is_resource($this->connect)) {
|
||||
$this->smtpData('QUIT', null);
|
||||
@fclose($this->connect);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hello SMTP server
|
||||
*/
|
||||
protected function smtpHello()
|
||||
{
|
||||
switch ($this->auth) {
|
||||
case 1:
|
||||
$this->smtpData('EHLO ' . $this->hostname(), '250');
|
||||
return;
|
||||
case 0:
|
||||
if ($this->smtp['user'] != '' && $this->smtp['pass'] != '') {
|
||||
$code = $this->smtpData('EHLO ' . $this->hostname(), ['250', '500', '501', '502', '550']);
|
||||
if ($code === '250') {
|
||||
$this->smtpData('AUTH LOGIN', '334');
|
||||
$this->smtpData(base64_encode($this->smtp['user']), '334');
|
||||
$this->smtpData(base64_encode($this->smtp['pass']), '235');
|
||||
$this->auth = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
default:
|
||||
$this->auth = -1;
|
||||
$this->smtpData('HELO ' . $this->hostname(), '250');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param mixed $code
|
||||
* @throws \RuntimeException
|
||||
* @return string
|
||||
*/
|
||||
protected function smtpData($data, $code)
|
||||
{
|
||||
//var_dump($data);
|
||||
if (is_string($data)) {
|
||||
@fwrite($this->connect, $data . $this->EOL);
|
||||
}
|
||||
|
||||
$response = '';
|
||||
// while (! isset($get{3}) || $get{3} !== ' ') {
|
||||
while (is_resource($this->connect) && !feof($this->connect)) {
|
||||
if (($get = @fgets($this->connect, 512)) === false) {
|
||||
throw new RuntimeException('Couldn\'t get mail server response codes');
|
||||
}
|
||||
$response .= $get;
|
||||
if (isset($get{3}) && $get{3} === ' ') {
|
||||
$return = substr($get, 0, 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//var_dump($response);
|
||||
if ($code !== null && ! in_array($return, (array) $code)) {
|
||||
throw new RuntimeException('Unable to send email. Response of the SMTP server: "'.$get.'"');
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Выделяет email из заголовка
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
protected function getEmailFrom($str)
|
||||
{
|
||||
$match = explode('" <', $str);
|
||||
if (count($match) == 2 && substr($match[1], -1) == '>') {
|
||||
return rtrim($match[1], '>');
|
||||
} else {
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает имя сервера или его ip
|
||||
* @return string
|
||||
*/
|
||||
protected function hostname()
|
||||
{
|
||||
return empty($_SERVER['SERVER_NAME'])
|
||||
? (isset($_SERVER['SERVER_ADDR']) ? '[' . $_SERVER['SERVER_ADDR'] . ']' : '[127.0.0.1]')
|
||||
: $_SERVER['SERVER_NAME'];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,14 +71,15 @@ class Router
|
|||
|
||||
/**
|
||||
* Проверка url на принадлежность форуму
|
||||
* @param string $url
|
||||
* @param mixed $url
|
||||
* @param string $defMarker
|
||||
* @param array $defArgs
|
||||
* @return string
|
||||
*/
|
||||
public function validate($url, $defMarker, array $defArgs = [])
|
||||
{
|
||||
if (parse_url($url, PHP_URL_HOST) === $this->host
|
||||
if (is_string($url)
|
||||
&& parse_url($url, PHP_URL_HOST) === $this->host
|
||||
&& ($route = $this->route('GET', rawurldecode(parse_url($url, PHP_URL_PATH))))
|
||||
&& $route[0] === self::OK
|
||||
) {
|
||||
|
|
|
@ -65,14 +65,11 @@ class CacheGenerator
|
|||
$search_for = $replace_with = [];
|
||||
for ($i = 0; $i < $num_words; $i++) {
|
||||
list($search_for[$i], $replace_with[$i]) = $this->db->fetch_row($result);
|
||||
$search_for[$i] = '%(?<=[^\p{L}\p{N}])('.str_replace('\*', '[\p{L}\p{N}]*?', preg_quote($search_for[$i], '%')).')(?=[^\p{L}\p{N}])%iu';
|
||||
$search_for[$i] = '%(?<![\p{L}\p{N}])('.str_replace('\*', '[\p{L}\p{N}]*?', preg_quote($search_for[$i], '%')).')(?![\p{L}\p{N}])%iu';
|
||||
}
|
||||
$this->db->free_result($result);
|
||||
|
||||
return [
|
||||
'search_for' => $search_for,
|
||||
'replace_with' => $replace_with
|
||||
];
|
||||
return [$search_for, $replace_with];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,6 +12,11 @@ class CheckBans
|
|||
*/
|
||||
protected $c;
|
||||
|
||||
/**
|
||||
* Содержит массив с описание бана для проверяемого юзера
|
||||
*/
|
||||
protected $ban;
|
||||
|
||||
/**
|
||||
* Конструктор
|
||||
* @param Container $container
|
||||
|
@ -27,54 +32,72 @@ class CheckBans
|
|||
*/
|
||||
public function check()
|
||||
{
|
||||
$bans = $this->c->bans;
|
||||
$user = $this->c->user;
|
||||
|
||||
// Для админов и при отсутствии банов прекращаем проверку
|
||||
if ($user->isAdmin || empty($bans)) {
|
||||
return null;
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
$userIp = $user->ip;
|
||||
$add = strpos($userIp, '.') !== false ? '.' : ':';
|
||||
$userIp .= $add;
|
||||
if ($banned) {
|
||||
$this->c->Online->delete($user); //???? а зачем это надо?
|
||||
return $this->ban;
|
||||
}
|
||||
|
||||
$username = mb_strtolower($user->username);
|
||||
return null;
|
||||
}
|
||||
|
||||
$banned = false;
|
||||
/**
|
||||
* Проверяет наличие бана на основании имени юзера, 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)
|
||||
{
|
||||
// Has this ban expired?
|
||||
if ($cur['expire'] != '' && $cur['expire'] <= time())
|
||||
{
|
||||
foreach ($bans as $cur) {
|
||||
if ($cur['expire'] != '' && $cur['expire'] < $now) {
|
||||
$remove[] = $cur['id'];
|
||||
continue;
|
||||
} elseif ($banned) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $user->isGuest) {
|
||||
if ($cur['username'] != '' && $username == mb_strtolower($cur['username'])) {
|
||||
$banned = $cur;
|
||||
continue;
|
||||
} elseif ($cur['email'] != '' && $user->email == $cur['email']) {
|
||||
$banned = $cur;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($cur['ip'] != '')
|
||||
{
|
||||
$ips = explode(' ', $cur['ip']);
|
||||
foreach ($ips as $ip) {
|
||||
} 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) {
|
||||
$banned = $cur;
|
||||
break;
|
||||
$this->ban = $cur;
|
||||
$banned = 3;
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,14 +110,6 @@ class CheckBans
|
|||
$db->query('DELETE FROM '.$db->prefix.'bans WHERE id IN (' . implode(',', $remove) . ')') or error('Unable to delete expired ban', __FILE__, __LINE__, $db->error());
|
||||
$this->c->{'bans update'};
|
||||
}
|
||||
|
||||
if ($banned)
|
||||
{
|
||||
//???? а зачем это надо?
|
||||
$this->c->Online->delete($user);
|
||||
return $banned;
|
||||
}
|
||||
|
||||
return null;
|
||||
return $banned;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace ForkBB\Models\Pages;
|
||||
|
||||
use ForkBB\Models\Validator;
|
||||
use ForkBB\Models\User;
|
||||
|
||||
class Auth extends Page
|
||||
{
|
||||
/**
|
||||
|
@ -22,6 +25,12 @@ class Auth extends Page
|
|||
*/
|
||||
protected $index = 'login';
|
||||
|
||||
/**
|
||||
* Для передачи User из vCheckEmail() в forgetPost()
|
||||
* @var User
|
||||
*/
|
||||
protected $tmpUser;
|
||||
|
||||
/**
|
||||
* Выход пользователя
|
||||
* @param array $args
|
||||
|
@ -37,7 +46,7 @@ class Auth extends Page
|
|||
$this->c->Online->delete($this->c->user);
|
||||
$this->c->UserMapper->updateLastVisit($this->c->user);
|
||||
|
||||
$this->c->Lang->load('login');
|
||||
$this->c->Lang->load('auth');
|
||||
return $this->c->Redirect->setPage('Index')->setMessage(__('Logout redirect'));
|
||||
}
|
||||
|
||||
|
@ -48,7 +57,7 @@ class Auth extends Page
|
|||
*/
|
||||
public function login(array $args)
|
||||
{
|
||||
$this->c->Lang->load('login');
|
||||
$this->c->Lang->load('auth');
|
||||
|
||||
if (! isset($args['_username'])) {
|
||||
$args['_username'] = '';
|
||||
|
@ -62,15 +71,15 @@ class Auth extends Page
|
|||
__('Login'),
|
||||
];
|
||||
$this->data = [
|
||||
'username' => $args['_username'],
|
||||
'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('Registration')
|
||||
? $this->c->Router->link('Register')
|
||||
: null,
|
||||
'formRedirect' => $args['_redirect'],
|
||||
'formSave' => ! empty($args['_save'])
|
||||
'username' => $args['_username'],
|
||||
'redirect' => $args['_redirect'],
|
||||
'save' => ! empty($args['_save'])
|
||||
];
|
||||
|
||||
return $this;
|
||||
|
@ -82,93 +91,78 @@ class Auth extends Page
|
|||
*/
|
||||
public function loginPost()
|
||||
{
|
||||
$this->c->Lang->load('login');
|
||||
$this->c->Lang->load('auth');
|
||||
|
||||
$v = $this->c->Validator;
|
||||
$v->setRules([
|
||||
$v = $this->c->Validator->addValidators([
|
||||
'login_process' => [$this, 'vLoginProcess'],
|
||||
])->setRules([
|
||||
'token' => 'token:Login',
|
||||
'redirect' => 'referer:Index',
|
||||
'username' => ['required|string|min:2|max:25', __('Username')],
|
||||
'password' => ['required|string', __('Password')],
|
||||
'username' => ['required|string', __('Username')],
|
||||
'password' => ['required|string|login_process', __('Password')],
|
||||
'save' => 'checkbox',
|
||||
]);
|
||||
|
||||
$ok = $v->validation($_POST);
|
||||
$data = $v->getData();
|
||||
$this->iswev = $v->getErrors();
|
||||
|
||||
if ($ok && ! $this->loginProcess($data['username'], $data['password'], $data['save'])) {
|
||||
$this->iswev['v'][] = __('Wrong user/pass');
|
||||
$ok = false;
|
||||
}
|
||||
|
||||
if ($ok) {
|
||||
return $this->c->Redirect->setUrl($data['redirect'])->setMessage(__('Login redirect'));
|
||||
if ($v->validation($_POST)) {
|
||||
return $this->c->Redirect->setUrl($v->redirect)->setMessage(__('Login redirect'));
|
||||
} else {
|
||||
$this->iswev = $v->getErrors();
|
||||
return $this->login([
|
||||
'_username' => $data['username'],
|
||||
'_redirect' => $data['redirect'],
|
||||
'_save' => $data['save'],
|
||||
'_username' => $v->username,
|
||||
'_redirect' => $v->redirect,
|
||||
'_save' => $v->save,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Вход на форум
|
||||
* @param string $username
|
||||
* Проверка по базе и вход на форум
|
||||
* @param Validator $v
|
||||
* @param string $password
|
||||
* @param bool $save
|
||||
* @return bool
|
||||
* @param int $type
|
||||
* @return array
|
||||
*/
|
||||
protected function loginProcess($username, $password, $save)
|
||||
public function vLoginProcess(Validator $v, $password, $type)
|
||||
{
|
||||
$user = $this->c->UserMapper->getUser($username, 'username');
|
||||
if (null == $user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$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;
|
||||
$authorized = true;
|
||||
}
|
||||
$error = false;
|
||||
if (! empty($v->getErrors())) {
|
||||
} elseif (! ($user = $this->c->UserMapper->getUser($v->username, 'username')) instanceof User) {
|
||||
$error = __('Wrong user/pass');
|
||||
} elseif ($user->isUnverified) {
|
||||
$error = [__('Account is not activated'), 'w'];
|
||||
} else {
|
||||
$authorized = password_verify($password, $hash);
|
||||
}
|
||||
$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;
|
||||
$authorized = true;
|
||||
}
|
||||
} else {
|
||||
$authorized = password_verify($password, $hash);
|
||||
}
|
||||
// ошибка в пароле
|
||||
if (! $authorized) {
|
||||
$error = __('Wrong user/pass');
|
||||
} else {
|
||||
// перезаписываем ip админа и модератора - Visman
|
||||
if ($user->isAdmMod
|
||||
&& $this->config['o_check_ip']
|
||||
&& $user->registrationIp != $this->c->user->ip
|
||||
) {
|
||||
$update['registration_ip'] = $this->c->user->ip;
|
||||
}
|
||||
// изменения юзера в базе
|
||||
$this->c->UserMapper->updateUser($user->id, $update);
|
||||
|
||||
if (! $authorized) {
|
||||
return false;
|
||||
$this->c->Online->delete($this->c->user);
|
||||
$this->c->UserCookie->setUserCookie($user->id, $hash, $v->save);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the status if this is the first time the user logged in
|
||||
if ($user->isUnverified) {
|
||||
$update['group_id'] = (int) $this->config['o_default_user_group'];
|
||||
}
|
||||
|
||||
// перезаписываем ip админа и модератора - Visman
|
||||
if ($user->isAdmMod
|
||||
&& $this->config['o_check_ip']
|
||||
&& $user->registrationIp != $this->c->user->ip
|
||||
) {
|
||||
$update['registration_ip'] = $this->c->user->ip;
|
||||
}
|
||||
|
||||
// изменения юзера в базе
|
||||
$this->c->UserMapper->updateUser($user->id, $update);
|
||||
// обновления кэша
|
||||
if (isset($update['group_id'])) {
|
||||
$this->c->{'users_info update'};
|
||||
}
|
||||
$this->c->Online->delete($this->c->user);
|
||||
$this->c->UserCookie->setUserCookie($user->id, $hash, $save);
|
||||
|
||||
return true;
|
||||
return [$password, $type, $error];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,8 +172,6 @@ class Auth extends Page
|
|||
*/
|
||||
public function forget(array $args)
|
||||
{
|
||||
$this->c->Lang->load('login');
|
||||
|
||||
$this->nameTpl = 'password_reset';
|
||||
$this->onlinePos = 'password_reset';
|
||||
|
||||
|
@ -187,13 +179,15 @@ class Auth extends Page
|
|||
$args['_email'] = '';
|
||||
}
|
||||
|
||||
$this->c->Lang->load('auth');
|
||||
|
||||
$this->titles = [
|
||||
__('Password reset'),
|
||||
];
|
||||
$this->data = [
|
||||
'email' => $args['_email'],
|
||||
'formAction' => $this->c->Router->link('Forget'),
|
||||
'formToken' => $this->c->Csrf->create('Forget'),
|
||||
'email' => $args['_email'],
|
||||
];
|
||||
|
||||
return $this;
|
||||
|
@ -205,52 +199,75 @@ class Auth extends Page
|
|||
*/
|
||||
public function forgetPost()
|
||||
{
|
||||
$this->c->Lang->load('login');
|
||||
$this->c->Lang->load('auth');
|
||||
|
||||
$v = $this->c->Validator;
|
||||
$v->setRules([
|
||||
$v = $this->c->Validator->addValidators([
|
||||
'check_email' => [$this, 'vCheckEmail'],
|
||||
])->setRules([
|
||||
'token' => 'token:Forget',
|
||||
'email' => 'required|email',
|
||||
'email' => 'required|string:trim,lower|email|check_email',
|
||||
])->setMessages([
|
||||
'email' => __('Invalid email'),
|
||||
'email.email' => __('Invalid email'),
|
||||
]);
|
||||
|
||||
$ok = $v->validation($_POST);
|
||||
$data = $v->getData();
|
||||
$this->iswev = $v->getErrors();
|
||||
|
||||
if ($ok && ($user = $this->c->UserMapper->getUser($data['email'], 'email')) === null) {
|
||||
$this->iswev['v'][] = __('Invalid email');
|
||||
$ok = false;
|
||||
}
|
||||
if ($ok && ! empty($user->lastEmailSent) && time() - $user->lastEmailSent < 3600) {
|
||||
$this->iswev['e'][] = __('Email flood', (int) (($user->lastEmailSent + 3600 - time()) / 60));
|
||||
$ok = false;
|
||||
}
|
||||
|
||||
if (! $ok) {
|
||||
if (! $v->validation($_POST)) {
|
||||
$this->iswev = $v->getErrors();
|
||||
return $this->forget([
|
||||
'_email' => $data['email'],
|
||||
'_email' => $v->email,
|
||||
]);
|
||||
}
|
||||
|
||||
$mail = $this->c->Mail;
|
||||
$mail->setFolder($this->c->DIR_LANG)
|
||||
->setLanguage($user->language);
|
||||
$key = 'p' . $this->c->Secury->randomPass(79);
|
||||
$hash = $this->c->Secury->hash($v->email . $key);
|
||||
$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']),
|
||||
'username' => $this->tmpUser->username,
|
||||
'link' => $link,
|
||||
];
|
||||
$mail = $this->c->Mail->reset()
|
||||
->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']))
|
||||
->setTpl('password_reset.tpl', $tplData);
|
||||
|
||||
$key = 'p' . $this->c->Secury->randomPass(75);
|
||||
$hash = $this->c->Secury->hash($data['email'] . $key);
|
||||
$link = $this->c->Router->link('ChangePassword', ['email' => $data['email'], 'key' => $key, 'hash' => $hash]);
|
||||
$tplData = ['link' => $link];
|
||||
|
||||
if ($mail->send($data['email'], 'password_reset.tpl', $tplData)) {
|
||||
$this->c->UserMapper->updateUser($user->id, ['activate_string' => $key, 'last_email_sent' => time()]);
|
||||
if ($mail->send()) {
|
||||
$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);
|
||||
} else {
|
||||
return $this->c->Message->message(__('Error mail', $this->config['o_admin_email']), true, 200);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Дополнительная проверка email
|
||||
* @param Validator $v
|
||||
* @param string $username
|
||||
* @param int $type
|
||||
* @return array
|
||||
*/
|
||||
public function vCheckEmail(Validator $v, $email, $type)
|
||||
{
|
||||
$error = false;
|
||||
// есть ошибки
|
||||
if (! empty($v->getErrors())) {
|
||||
// email забанен
|
||||
} elseif ($this->c->CheckBans->isBanned(null, $email) > 0) {
|
||||
$error = __('Banned email');
|
||||
// нет пользователя с таким email
|
||||
} elseif (! ($user = $this->c->UserMapper->getUser($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'];
|
||||
} else {
|
||||
$this->tmpUser = $user;
|
||||
}
|
||||
return [$email, $type, $error];
|
||||
}
|
||||
|
||||
/**
|
||||
* Подготовка данных для формы изменения пароля
|
||||
* @param array $args
|
||||
|
@ -267,7 +284,7 @@ class Auth extends Page
|
|||
// что-то пошло не так
|
||||
if (! hash_equals($args['hash'], $this->c->Secury->hash($args['email'] . $args['key']))
|
||||
|| ! $this->c->Mail->valid($args['email'])
|
||||
|| ($user = $this->c->UserMapper->getUser($args['email'], 'email')) === null
|
||||
|| ! ($user = $this->c->UserMapper->getUser($args['email'], 'email')) instanceof User
|
||||
|| empty($user->activateString)
|
||||
|| $user->activateString{0} !== 'p'
|
||||
|| ! hash_equals($user->activateString, $args['key'])
|
||||
|
@ -276,8 +293,7 @@ class Auth extends Page
|
|||
}
|
||||
}
|
||||
|
||||
$this->c->Lang->load('login');
|
||||
$this->c->Lang->load('profile');
|
||||
$this->c->Lang->load('auth');
|
||||
|
||||
$this->titles = [
|
||||
__('Change pass'),
|
||||
|
@ -300,7 +316,7 @@ class Auth extends Page
|
|||
// что-то пошло не так
|
||||
if (! hash_equals($args['hash'], $this->c->Secury->hash($args['email'] . $args['key']))
|
||||
|| ! $this->c->Mail->valid($args['email'])
|
||||
|| ($user = $this->c->UserMapper->getUser($args['email'], 'email')) === null
|
||||
|| ! ($user = $this->c->UserMapper->getUser($args['email'], 'email')) instanceof User
|
||||
|| empty($user->activateString)
|
||||
|| $user->activateString{0} !== 'p'
|
||||
|| ! hash_equals($user->activateString, $args['key'])
|
||||
|
@ -308,18 +324,18 @@ class Auth extends Page
|
|||
return $this->c->Message->message(__('Bad request'), false);
|
||||
}
|
||||
|
||||
$this->c->Lang->load('login');
|
||||
$this->c->Lang->load('profile');
|
||||
$this->c->Lang->load('auth');
|
||||
|
||||
$v = $this->c->Validator;
|
||||
$v->setRules([
|
||||
'token' => 'token:ChangePassword',
|
||||
'password' => ['required|string|min:8', __('New pass')],
|
||||
'password2' => 'required|same:password',
|
||||
'password' => ['required|string|min:8|password', __('New pass')],
|
||||
'password2' => ['required|same:password', __('Confirm new pass')],
|
||||
])->setArguments([
|
||||
'token' => $args,
|
||||
])->setMessages([
|
||||
'password2' => __('Pass not match'),
|
||||
'password.password' => __('Pass format'),
|
||||
'password2.same' => __('Pass not match'),
|
||||
]);
|
||||
|
||||
if (! $v->validation($_POST)) {
|
||||
|
@ -329,7 +345,7 @@ class Auth extends Page
|
|||
}
|
||||
$data = $v->getData();
|
||||
|
||||
$this->c->UserMapper->updateUser($user->id, ['password' => password_hash($data['password'], PASSWORD_DEFAULT), 'activate_string' => null]);
|
||||
$this->c->UserMapper->updateUser($user->id, ['password' => password_hash($data['password'], PASSWORD_DEFAULT), 'email_confirmed' => 1, 'activate_string' => null]);
|
||||
|
||||
$this->iswev['s'][] = __('Pass updated');
|
||||
return $this->login(['_redirect' => $this->c->Router->link('Index')]);
|
||||
|
|
|
@ -165,6 +165,8 @@ abstract class Page
|
|||
return $this->data + [
|
||||
'pageTitle' => $this->pageTitle(),
|
||||
'pageHeads' => $this->pageHeads(),
|
||||
'fLang' => __('lang_identifier'),
|
||||
'fDirection' => __('lang_direction'),
|
||||
'fTitle' => $this->config['o_board_title'],
|
||||
'fDescription' => $this->config['o_board_desc'],
|
||||
'fNavigation' => $this->fNavigation(),
|
||||
|
@ -182,14 +184,24 @@ abstract class Page
|
|||
protected function getIswev()
|
||||
{
|
||||
if ($this->config['o_maintenance'] == '1') {
|
||||
$user = $this->c->user;
|
||||
if ($user->isAdmMod) {
|
||||
$this->iswev['w'][] = '<a href="' . $this->c->Router->link('AdminOptions', ['#' => 'maintenance']). '">' . __('Maintenance mode enabled') . '</a>';
|
||||
if ($this->c->user->isAdmin) {
|
||||
$this->iswev['w'][] = __('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 страницы
|
||||
* @return string
|
||||
|
@ -207,7 +219,7 @@ abstract class Page
|
|||
*/
|
||||
protected function pageHeads()
|
||||
{
|
||||
return [];
|
||||
return []; //????
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -245,7 +257,7 @@ abstract class Page
|
|||
}
|
||||
|
||||
if ($user->isGuest) {
|
||||
$nav['register'] = ['register.php', __('Register')];
|
||||
$nav['register'] = [$r->link('Register'), __('Register')];
|
||||
$nav['login'] = [$r->link('Login'), __('Login')];
|
||||
} else {
|
||||
$nav['profile'] = [$r->link('User', [
|
||||
|
@ -294,11 +306,11 @@ abstract class Page
|
|||
* Заглушка
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return Page
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function __call($name, array $arguments)
|
||||
{
|
||||
return $this;
|
||||
throw new RuntimeException("'{$name}' method is not");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -308,7 +320,7 @@ abstract class Page
|
|||
*/
|
||||
protected function size($size)
|
||||
{
|
||||
$units = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB');
|
||||
$units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB'];
|
||||
|
||||
for ($i = 0; $size > 1024; $i++) {
|
||||
$size /= 1024;
|
||||
|
|
251
app/Models/Pages/Register.php
Normal file
251
app/Models/Pages/Register.php
Normal file
|
@ -0,0 +1,251 @@
|
|||
<?php
|
||||
|
||||
namespace ForkBB\Models\Pages;
|
||||
|
||||
use ForkBB\Models\Validator;
|
||||
use ForkBB\Models\User;
|
||||
|
||||
class Register extends Page
|
||||
{
|
||||
/**
|
||||
* Имя шаблона
|
||||
* @var string
|
||||
*/
|
||||
protected $nameTpl = 'register';
|
||||
|
||||
/**
|
||||
* Позиция для таблицы онлайн текущего пользователя
|
||||
* @var null|string
|
||||
*/
|
||||
protected $onlinePos = 'register';
|
||||
|
||||
/**
|
||||
* Указатель на активный пункт навигации
|
||||
* @var string
|
||||
*/
|
||||
protected $index = 'register';
|
||||
|
||||
/**
|
||||
* Обработчик регистрации
|
||||
* @retrun Page
|
||||
*/
|
||||
public function reg()
|
||||
{
|
||||
$this->c->Lang->load('register');
|
||||
|
||||
$v = $this->c->Validator->addValidators([
|
||||
'check_email' => [$this, 'vCheckEmail'],
|
||||
'check_username' => [$this, 'vCheckUsername'],
|
||||
])->setRules([
|
||||
'token' => 'token:RegisterForm',
|
||||
'agree' => 'required|token:Register',
|
||||
'on' => 'integer',
|
||||
'email' => ['required_with:on|string:trim,lower|email|check_email', __('Email')],
|
||||
'username' => ['required_with:on|string:trim|min:2|max:25|login|check_username', __('Username')],
|
||||
'password' => ['required_with:on|string|min:8|password', __('Password')],
|
||||
])->setMessages([
|
||||
'agree.required' => ['cancel', 'cancel'],
|
||||
'agree.token' => [__('Bad agree', $this->c->Router->link('Register')), 'w'],
|
||||
'password.password' => __('Pass format'),
|
||||
'username.login' => __('Login format'),
|
||||
]);
|
||||
|
||||
// завершение регистрации
|
||||
if ($v->validation($_POST) && $v->on === 1) {
|
||||
return $this->regEnd($v);
|
||||
}
|
||||
|
||||
$this->iswev = $v->getErrors();
|
||||
|
||||
// нет согласия с правилами
|
||||
if (isset($this->iswev['cancel'])) {
|
||||
return $this->c->Redirect->setPage('Index')->setMessage(__('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,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Дополнительная проверка email
|
||||
* @param Validator $v
|
||||
* @param string $username
|
||||
* @param int $type
|
||||
* @return array
|
||||
*/
|
||||
public function vCheckEmail(Validator $v, $email, $type)
|
||||
{
|
||||
$error = false;
|
||||
// email забанен
|
||||
if ($this->c->CheckBans->isBanned(null, $email) > 0) {
|
||||
$error = __('Banned email');
|
||||
// найден хотя бы 1 юзер с таким же email
|
||||
} elseif (empty($v->getErrors()) && $this->c->UserMapper->getUser($email, 'email') !== 0) {
|
||||
$error = __('Dupe email');
|
||||
}
|
||||
return [$email, $type, $error];
|
||||
}
|
||||
|
||||
/**
|
||||
* Дополнительная проверка username
|
||||
* @param Validator $v
|
||||
* @param string $username
|
||||
* @param int $type
|
||||
* @return array
|
||||
*/
|
||||
public function vCheckUsername(Validator $v, $username, $type)
|
||||
{
|
||||
$username = preg_replace('%\s+%su', ' ', $username);
|
||||
$error = false;
|
||||
// username = Гость
|
||||
if (preg_match('%^(guest|' . preg_quote(__('Guest'), '%') . ')$%iu', $username)) {
|
||||
$error = __('Username guest');
|
||||
// цензура
|
||||
} elseif ($this->config['o_censoring'] == '1' && censor_words($username) !== $username) {
|
||||
$error = __('Username censor');
|
||||
// username забанен
|
||||
} elseif ($this->c->CheckBans->isBanned($username) > 0) {
|
||||
$error = __('Banned username');
|
||||
// есть пользователь с похожим именем
|
||||
} elseif (empty($v->getErrors()) && ! $this->c->UserMapper->isUnique($username)) {
|
||||
$error = __('Username not unique');
|
||||
}
|
||||
return [$username, $type, $error];
|
||||
}
|
||||
|
||||
/**
|
||||
* Завершение регистрации
|
||||
* @param array @data
|
||||
* @return Page
|
||||
*/
|
||||
protected function regEnd(Validator $v)
|
||||
{
|
||||
if ($this->config['o_regs_verify'] == '1') {
|
||||
$groupId = PUN_UNVERIFIED;
|
||||
$key = 'w' . $this->c->Secury->randomPass(79);
|
||||
$visit = 0;
|
||||
} else {
|
||||
$groupId = $this->config['o_default_user_group'];
|
||||
$key = null;
|
||||
$visit = time(); //????
|
||||
}
|
||||
|
||||
$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,
|
||||
'last_visit' => $visit,
|
||||
'activate_string' => $key,
|
||||
], $this->c));
|
||||
|
||||
// обновление статистики по пользователям
|
||||
if ($this->config['o_regs_verify'] != '1') {
|
||||
$this->c->{'users_info update'};
|
||||
}
|
||||
|
||||
// уведомление о регистрации
|
||||
if ($this->config['o_mailing_list'] != '' && $this->config['o_regs_report'] == '1') {
|
||||
$tplData = [
|
||||
'fTitle' => $this->config['o_board_title'],
|
||||
'fRootLink' => $this->c->Router->link('Index'),
|
||||
'fMailer' => __('Mailer', $this->config['o_board_title']),
|
||||
'username' => $v->username,
|
||||
'userLink' => $this->c->Router->link('User', ['id' => $newUserId, 'name' => $v->username]),
|
||||
];
|
||||
$mail = $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']))
|
||||
->setTpl('new_user.tpl', $tplData)
|
||||
->send();
|
||||
}
|
||||
|
||||
$this->c->Lang->load('register');
|
||||
|
||||
// отправка письма активации аккаунта
|
||||
if ($this->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'],
|
||||
'fRootLink' => $this->c->Router->link('Index'),
|
||||
'fMailer' => __('Mailer', $this->config['o_board_title']),
|
||||
'username' => $v->username,
|
||||
'link' => $link,
|
||||
];
|
||||
$mail = $this->c->Mail->reset()
|
||||
->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']))
|
||||
->setTpl('welcome.tpl', $tplData);
|
||||
|
||||
// письмо активации аккаунта отправлено
|
||||
if ($mail->send()) {
|
||||
return $this->c->Message->message(__('Reg email', $this->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,
|
||||
]);
|
||||
}
|
||||
// форма логина
|
||||
} else {
|
||||
return $this->c->Auth->setIswev([
|
||||
's' => [
|
||||
__('Reg complete'),
|
||||
],
|
||||
])->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'])
|
||||
) {
|
||||
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]);
|
||||
$this->c->{'users_info update'};
|
||||
|
||||
$this->c->Lang->load('register');
|
||||
|
||||
return $this->c->Auth->setIswev([
|
||||
's' => [
|
||||
__('Reg complete'),
|
||||
],
|
||||
])->login([
|
||||
'_username' => $user->username,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -32,7 +32,33 @@ class Rules extends Page
|
|||
__('Forum rules'),
|
||||
];
|
||||
$this->data = [
|
||||
'Rules' => $this->config['o_rules_message'],
|
||||
'title' => __('Forum rules'),
|
||||
'rules' => $this->config['o_rules_message'],
|
||||
'formAction' => null,
|
||||
];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Подготавливает данные для шаблона
|
||||
* @return Page
|
||||
*/
|
||||
public function confirmation()
|
||||
{
|
||||
$this->index = 'register';
|
||||
$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'),
|
||||
];
|
||||
return $this;
|
||||
}
|
||||
|
|
|
@ -19,16 +19,6 @@ class User extends AbstractModel
|
|||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var UserCookie
|
||||
*/
|
||||
protected $userCookie;
|
||||
|
||||
/**
|
||||
* @var DB
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Время
|
||||
* @var int
|
||||
|
@ -43,8 +33,6 @@ class User extends AbstractModel
|
|||
$this->now = time();
|
||||
$this->c = $container;
|
||||
$this->config = $container->config;
|
||||
$this->userCookie = $container->UserCookie;
|
||||
$this->db = $container->DB;
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,8 @@ class UserMapper
|
|||
* Получение пользователя по условию
|
||||
* @param int|string
|
||||
* @param string $field
|
||||
* @return null|User
|
||||
* @return int|User
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getUser($value, $field = 'id')
|
||||
{
|
||||
|
@ -105,13 +106,13 @@ class UserMapper
|
|||
$where = 'u.email=\'' . $this->db->escape($value) . '\'';
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
throw new InvalidArgumentException('Field not supported');
|
||||
}
|
||||
$result = $this->db->query('SELECT u.*, g.* FROM '.$this->db->prefix.'users AS u LEFT JOIN '.$this->db->prefix.'groups AS g ON u.group_id=g.g_id WHERE '.$where) or error('Unable to fetch user information', __FILE__, __LINE__, $this->db->error());
|
||||
|
||||
// найдено несколько пользователей
|
||||
if ($this->db->num_rows($result) !== 1) {
|
||||
return null;
|
||||
return $this->db->num_rows($result);
|
||||
}
|
||||
|
||||
$user = $this->db->fetch_assoc($result);
|
||||
|
@ -119,14 +120,25 @@ class UserMapper
|
|||
|
||||
// найден гость
|
||||
if ($user['id'] == 1) {
|
||||
return null;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return new User($user, $this->c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновить данные юзера
|
||||
* Проверка на уникальность имени пользователя
|
||||
* @param string $username
|
||||
* @return bool
|
||||
*/
|
||||
public function isUnique($username)
|
||||
{
|
||||
$result = $this->db->query('SELECT username FROM '.$this->db->prefix.'users WHERE (UPPER(username)=UPPER(\''.$this->db->escape($username).'\') OR UPPER(username)=UPPER(\''.$this->db->escape(preg_replace('%[^\p{L}\p{N}]%u', '', $username)).'\'))') or error('Unable to fetch user info', __FILE__, __LINE__, $this->db->error());
|
||||
return ! $this->db->num_rows($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновить данные пользователя
|
||||
* @param int $id
|
||||
* @param array $update
|
||||
*/
|
||||
|
@ -152,4 +164,16 @@ class UserMapper
|
|||
$this->db->query('UPDATE '.$this->db->prefix.'users SET '.implode(', ', $set).' WHERE id='.$id) or error('Unable to update user data', __FILE__, __LINE__, $this->db->error());
|
||||
}
|
||||
|
||||
/**
|
||||
* Создание нового пользователя
|
||||
* @param User $user
|
||||
* @throws
|
||||
* @return int
|
||||
*/
|
||||
public function newUser(User $user)
|
||||
{
|
||||
$this->db->query('INSERT INTO '.$this->db->prefix.'users (username, group_id, password, email, email_confirmed, email_setting, timezone, dst, language, style, registered, registration_ip, last_visit, activate_string) VALUES(\''.$this->db->escape($user->username).'\', '.$user->groupId.', \''.$this->db->escape($user->password).'\', \''.$this->db->escape($user->email).'\', '.$user->emailConfirmed.', '.$this->config['o_default_email_setting'].', '.$this->config['o_default_timezone'].' , '.$this->config['o_default_dst'].', \''.$this->db->escape($user->language).'\', \''.$user->style.'\', '.time().', \''.$this->db->escape($this->getIpAddress()).'\', '.$user->lastVisit.', \''.$this->db->escape($user->activateString).'\')') or error('Unable to create user', __FILE__, __LINE__, $this->db->error());
|
||||
$new_uid = $this->db->insert_id(); //????
|
||||
return $new_uid;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ class Validator
|
|||
const T_NUMERIC = 2;
|
||||
const T_INT = 3;
|
||||
const T_ARRAY = 4;
|
||||
const T_BOOLEAN = 5;
|
||||
|
||||
/**
|
||||
* Контейнер
|
||||
|
@ -19,6 +20,11 @@ class Validator
|
|||
*/
|
||||
protected $c;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $validators;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
|
@ -27,7 +33,7 @@ class Validator
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $data;
|
||||
protected $result;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
|
@ -49,11 +55,9 @@ class Validator
|
|||
*/
|
||||
protected $errors;
|
||||
|
||||
/**
|
||||
* Тип текущего поля при валидации
|
||||
* @var int
|
||||
*/
|
||||
protected $curType;
|
||||
protected $fields;
|
||||
protected $status;
|
||||
protected $raw;
|
||||
|
||||
/**
|
||||
* Конструктор
|
||||
|
@ -62,6 +66,35 @@ class Validator
|
|||
public function __construct(Container $container)
|
||||
{
|
||||
$this->c = $container;
|
||||
$this->validators = [
|
||||
'array' => [$this, 'vArray'],
|
||||
'checkbox' => [$this, 'vCheckbox'],
|
||||
'email' => [$this, 'vEmail'],
|
||||
'integer' => [$this, 'vInteger'],
|
||||
'login' => [$this, 'vLogin'],
|
||||
'max' => [$this, 'vMax'],
|
||||
'min' => [$this, 'vMin'],
|
||||
'numeric' => [$this, 'vNumeric'],
|
||||
'password' => [$this, 'vPassword'],
|
||||
'referer' => [$this, 'vReferer'],
|
||||
'regex' => [$this, 'vRegex'],
|
||||
'required' => [$this, 'vRequired'],
|
||||
'required_with' => [$this, 'vRequiredWith'],
|
||||
'same' => [$this, 'vSame'],
|
||||
'string' => [$this, 'vString'],
|
||||
'token' => [$this, 'vToken'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавление новых валидаторов
|
||||
* @param array $validators
|
||||
* @param Validator
|
||||
*/
|
||||
public function addValidators(array $validators)
|
||||
{
|
||||
$this->validators = array_replace($this->validators, $validators);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,27 +106,27 @@ class Validator
|
|||
public function setRules(array $list)
|
||||
{
|
||||
$this->rules = [];
|
||||
$this->data = [];
|
||||
$this->result = [];
|
||||
$this->alias = [];
|
||||
$this->errors = [];
|
||||
$this->arguments = [];
|
||||
$this->fields = [];
|
||||
foreach ($list as $field => $raw) {
|
||||
$rules = [];
|
||||
// псевдоним содержится в списке правил
|
||||
if (is_array($raw)) {
|
||||
$this->aliases[$field] = $raw[1];
|
||||
$raw = $raw[0];
|
||||
list($raw, $this->aliases[$field]) = $raw;
|
||||
}
|
||||
// перебор правил для текущего поля
|
||||
$rawRules = explode('|', $raw);
|
||||
foreach ($rawRules as $rule) {
|
||||
foreach (explode('|', $raw) as $rule) {
|
||||
$tmp = explode(':', $rule, 2);
|
||||
if (! method_exists($this, $tmp[0] . 'Rule')) {
|
||||
throw new RuntimeException('Rule not found');
|
||||
if (empty($this->validators[$tmp[0]])) {
|
||||
throw new RuntimeException($tmp[0] . ' validator not found');
|
||||
}
|
||||
$rules[$tmp[0]] = isset($tmp[1]) ? $tmp[1] : '';
|
||||
}
|
||||
$this->rules[$field] = $rules;
|
||||
$this->fields[$field] = $field;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
@ -127,7 +160,7 @@ class Validator
|
|||
*/
|
||||
public function setAliases(array $aliases)
|
||||
{
|
||||
$this->aliases = $aliases;
|
||||
$this->aliases = array_replace($this->aliases, $aliases);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -143,38 +176,62 @@ class Validator
|
|||
if (empty($this->rules)) {
|
||||
throw new RuntimeException('Rules not found');
|
||||
}
|
||||
$ok = true;
|
||||
$this->errors = [];
|
||||
// перебор всех полей
|
||||
foreach ($this->rules as $field => $rules) {
|
||||
$error = false;
|
||||
$this->curType = self::T_UNKNOWN;
|
||||
// обязательное поле отсутствует
|
||||
if (! isset($raw[$field]) && isset($rules['required'])) {
|
||||
$rule = 'required';
|
||||
$attr = $rules['required'];
|
||||
$args = $this->getArguments($field, $rule);
|
||||
list($value, $error) = $this->requiredRule('', $attr, $args);
|
||||
} else {
|
||||
$value = isset($raw[$field])
|
||||
? $this->c->Secury->replInvalidChars($raw[$field])
|
||||
: null;
|
||||
// перебор правил для текущего поля
|
||||
foreach ($rules as $rule => $attr) {
|
||||
$args = $this->getArguments($field, $rule);
|
||||
$method = $rule . 'Rule';
|
||||
list($value, $error) = $this->$method($value, $attr, $args);
|
||||
// ошибок нет
|
||||
if (false === $error) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
$ok = $this->error($error, $field, $rule, $attr, $ok);
|
||||
$this->data[$field] = $value;
|
||||
$this->status = [];
|
||||
$this->raw = $raw;
|
||||
foreach ($this->fields as $field) {
|
||||
$this->$field;
|
||||
}
|
||||
return $ok;
|
||||
$this->raw = null;
|
||||
return empty($this->errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет поле согласно заданным правилам
|
||||
* Возвращает значение запрашиваемого поля
|
||||
* @param string
|
||||
* @return mixed
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function __get($field)
|
||||
{
|
||||
if (isset($this->status[$field])) {
|
||||
return $this->result[$field];
|
||||
} elseif (empty($this->rules[$field])) {
|
||||
throw new RuntimeException("No rules for '{$field}' field");
|
||||
}
|
||||
|
||||
$value = null;
|
||||
if (! isset($this->raw[$field]) && isset($this->rules[$field]['required'])) {
|
||||
$rules = ['required' => ''];
|
||||
} else {
|
||||
$rules = $this->rules[$field];
|
||||
if (isset($this->raw[$field])) {
|
||||
$value = $this->c->Secury->replInvalidChars($this->raw[$field]);
|
||||
}
|
||||
}
|
||||
|
||||
$error = false;
|
||||
$type = self::T_UNKNOWN;
|
||||
foreach ($rules as $validator => $attr) {
|
||||
$args = $this->getArguments($field, $validator);
|
||||
list($value, $type, $error) = $this->validators[$validator]($this, $value, $type, $attr, $args);
|
||||
// ошибок нет
|
||||
if (false === $error) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (! is_bool($error)) {
|
||||
$this->error($error, $field, $validator, $attr);
|
||||
$this->status[$field] = false;
|
||||
} else {
|
||||
$this->status[$field] = true;
|
||||
}
|
||||
|
||||
$this->result[$field] = $value;
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,8 +242,8 @@ class Validator
|
|||
*/
|
||||
protected function getArguments($field, $rule)
|
||||
{
|
||||
if (isset($this->arguments[$field . '.'. $rule])) {
|
||||
return $this->arguments[$field . '.'. $rule];
|
||||
if (isset($this->arguments[$field . '.' . $rule])) {
|
||||
return $this->arguments[$field . '.' . $rule];
|
||||
} elseif (isset($this->arguments[$field])) {
|
||||
return $this->arguments[$field];
|
||||
} else {
|
||||
|
@ -200,14 +257,9 @@ class Validator
|
|||
* @param string $field
|
||||
* @param string $rule
|
||||
* @param string $attr
|
||||
* @param bool $ok
|
||||
* return bool
|
||||
*/
|
||||
protected function error($error, $field, $rule, $attr, $ok)
|
||||
protected function error($error, $field, $rule, $attr)
|
||||
{
|
||||
if (is_bool($error)) {
|
||||
return $ok;
|
||||
}
|
||||
// псевдоним имени поля
|
||||
$alias = isset($this->aliases[$field]) ? $this->aliases[$field] : $field;
|
||||
// текст ошибки
|
||||
|
@ -223,7 +275,19 @@ class Validator
|
|||
$error = $error[0];
|
||||
}
|
||||
$this->errors[$type][] = __($error, [':alias' => $alias, ':attr' => $attr]);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает статус проверки поля
|
||||
* @param string $field
|
||||
* @return bool
|
||||
*/
|
||||
public function getStatus($field)
|
||||
{
|
||||
if (! isset($this->status[$field])) {
|
||||
$this->$field;
|
||||
}
|
||||
return $this->status[$field];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -234,10 +298,10 @@ class Validator
|
|||
*/
|
||||
public function getData()
|
||||
{
|
||||
if (empty($this->data)) {
|
||||
if (empty($this->result)) {
|
||||
throw new RuntimeException('Data not found');
|
||||
}
|
||||
return $this->data;
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,175 +313,221 @@ class Validator
|
|||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Правило "required"
|
||||
* @param mixed $value
|
||||
* @param string $attrs
|
||||
* @param mixed $args
|
||||
* @return array
|
||||
*/
|
||||
protected function requiredRule($value, $attr, $args)
|
||||
{
|
||||
$f = function () use ($value) {
|
||||
if (is_string($value)) {
|
||||
$this->curType = self::T_STRING;
|
||||
return isset($value{0});
|
||||
} elseif (is_array($value)) {
|
||||
$this->curType = self::T_ARRAY;
|
||||
return ! empty($value);
|
||||
} else {
|
||||
return null !== $value;
|
||||
}
|
||||
};
|
||||
if ($f()) {
|
||||
if (is_numeric($value)) {
|
||||
if (is_int(0 + $value)) {
|
||||
$this->curType = self::T_INT;
|
||||
} else {
|
||||
$this->curType = self::T_NUMERIC;
|
||||
}
|
||||
}
|
||||
return [$value, false];
|
||||
} else {
|
||||
return [$attr, 'The :alias is required'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function stringRule($value, $attr)
|
||||
protected function vRequired($v, $value, $type)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$this->curType = self::T_STRING;
|
||||
return [$value, false];
|
||||
if (strlen(trim($value)) > 0) {
|
||||
return [$value, $v::T_STRING, false];
|
||||
}
|
||||
} elseif (is_array($value)) {
|
||||
if (! empty($value)) {
|
||||
return [$value, $v::T_ARRAY, false];
|
||||
}
|
||||
} elseif (null !== $value) {
|
||||
if (is_int($value)) {
|
||||
$type = $v::T_INT;
|
||||
} elseif (is_numeric($value)) {
|
||||
$type = $v::T_NUMERIC;
|
||||
}
|
||||
return [$value, $type, false];
|
||||
}
|
||||
return [null, $type, 'The :alias is required'];
|
||||
}
|
||||
|
||||
protected function vRequiredWith($v, $value, $type, $attr)
|
||||
{
|
||||
foreach (explode(',', $attr) as $field) {
|
||||
if (null !== $v->$field) {
|
||||
return $this->vRequired($v, $value, $type);
|
||||
}
|
||||
}
|
||||
list(, , $error) = $this->vRequired($v, $value, $type);
|
||||
if (false === $error) {
|
||||
return [null, $type, 'The :alias is not required'];
|
||||
} else {
|
||||
return [$attr, 'The :alias must be string'];
|
||||
return [$value, $type, false];
|
||||
}
|
||||
}
|
||||
|
||||
protected function numericRule($value, $attr)
|
||||
protected function vString($v, $value, $type, $attr)
|
||||
{
|
||||
if (is_numeric($value)) {
|
||||
$this->curType = self::T_NUMERIC;
|
||||
return [0 + $value, false];
|
||||
if (null === $value) {
|
||||
return [null, $type, false];
|
||||
} elseif (is_string($value)) {
|
||||
foreach(explode(',', $attr) as $action) {
|
||||
switch ($action) {
|
||||
case 'trim':
|
||||
$value = trim($value);
|
||||
break;
|
||||
case 'lower':
|
||||
$value = mb_strtolower($value, 'UTF-8');
|
||||
break;
|
||||
}
|
||||
}
|
||||
return [$value, $v::T_STRING, false];
|
||||
} else {
|
||||
return [$attr, 'The :alias must be numeric'];
|
||||
return [null, $type, 'The :alias must be string'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function intRule($value, $attr)
|
||||
protected function vNumeric($v, $value, $type)
|
||||
{
|
||||
if (is_numeric($value) && is_int(0 + $value)) {
|
||||
$this->curType = self::T_INT;
|
||||
return [(int) $value, false];
|
||||
if (null === $value) {
|
||||
return [null, $type, false];
|
||||
} elseif (is_numeric($value)) {
|
||||
return [0 + $value, $v::T_NUMERIC, false];
|
||||
} else {
|
||||
return [$attr, 'The :alias must be integer'];
|
||||
return [null, $type, 'The :alias must be numeric'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function arrayRule($value, $attr)
|
||||
protected function vInteger($v, $value, $type)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$this->curType = self::T_ARRAY;
|
||||
return [$value, false];
|
||||
if (null === $value) {
|
||||
return [null, $type, false];
|
||||
} elseif (is_numeric($value) && is_int(0 + $value)) {
|
||||
return [(int) $value, $v::T_INT, false];
|
||||
} else {
|
||||
return [$attr, 'The :alias must be array'];
|
||||
return [null, $type, 'The :alias must be integer'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function minRule($value, $attr)
|
||||
protected function vArray($v, $value, $type)
|
||||
{
|
||||
switch ($this->curType) {
|
||||
if (null === $value) {
|
||||
return [null, $type, false];
|
||||
} elseif (is_array($value)) {
|
||||
return [$value, $v::T_ARRAY, false];
|
||||
} else {
|
||||
return [null, $type, 'The :alias must be array'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function vMin($v, $value, $type, $attr)
|
||||
{
|
||||
if (null === $value) {
|
||||
return [null, $type, false];
|
||||
}
|
||||
switch ($type) {
|
||||
case self::T_STRING:
|
||||
if (mb_strlen($value) < $attr) {
|
||||
return [$value, 'The :alias minimum is :attr characters'];
|
||||
if (mb_strlen($value, 'UTF-8') < $attr) {
|
||||
return [$value, $type, 'The :alias minimum is :attr characters'];
|
||||
}
|
||||
break;
|
||||
case self::T_NUMERIC:
|
||||
case self::T_INT:
|
||||
if ($value < $attr) {
|
||||
return [$value, 'The :alias minimum is :attr'];
|
||||
return [$value, $type, 'The :alias minimum is :attr'];
|
||||
}
|
||||
break;
|
||||
case self::T_ARRAY:
|
||||
if (count($value) < $attr) {
|
||||
return [$value, 'The :alias minimum is :attr elements'];
|
||||
return [$value, $type, 'The :alias minimum is :attr elements'];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ['', 'The :alias minimum is :attr'];
|
||||
return [null, $type, 'The :alias minimum is :attr'];
|
||||
break;
|
||||
}
|
||||
return [$value, false];
|
||||
return [$value, $type, false];
|
||||
}
|
||||
|
||||
protected function maxRule($value, $attr)
|
||||
protected function vMax($v, $value, $type, $attr)
|
||||
{
|
||||
switch ($this->curType) {
|
||||
if (null === $value) {
|
||||
return [null, $type, false];
|
||||
}
|
||||
switch ($type) {
|
||||
case self::T_STRING:
|
||||
if (mb_strlen($value) > $attr) {
|
||||
return [$value, 'The :alias maximum is :attr characters'];
|
||||
if (mb_strlen($value, 'UTF-8') > $attr) {
|
||||
return [$value, $type, 'The :alias maximum is :attr characters'];
|
||||
}
|
||||
break;
|
||||
case self::T_NUMERIC:
|
||||
case self::T_INT:
|
||||
if ($value > $attr) {
|
||||
return [$value, 'The :alias maximum is :attr'];
|
||||
return [$value, $type, 'The :alias maximum is :attr'];
|
||||
}
|
||||
break;
|
||||
case self::T_ARRAY:
|
||||
if (count($value) > $attr) {
|
||||
return [$value, 'The :alias maximum is :attr elements'];
|
||||
return [$value, $type, 'The :alias maximum is :attr elements'];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ['', 'The :alias maximum is :attr'];
|
||||
return [null, $type, 'The :alias maximum is :attr'];
|
||||
break;
|
||||
}
|
||||
return [$value, false];
|
||||
return [$value, $type, false];
|
||||
}
|
||||
|
||||
protected function tokenRule($value, $attr, $args)
|
||||
protected function vToken($v, $value, $type, $attr, $args)
|
||||
{
|
||||
if (! is_array($args)) {
|
||||
$args = [];
|
||||
}
|
||||
if (is_string($value) && $this->c->Csrf->verify($value, $attr, $args)) {
|
||||
return [$value, false];
|
||||
$value = (string) $value;
|
||||
if ($this->c->Csrf->verify($value, $attr, $args)) {
|
||||
return [$value, $type, false];
|
||||
} else {
|
||||
return ['', ['Bad token', 'e']];
|
||||
return [$value, $type, ['Bad token', 'e']];
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkboxRule($value, $attr)
|
||||
protected function vCheckbox($v, $value)
|
||||
{
|
||||
return [! empty($value), false]; //????
|
||||
return [! empty($value), $v::T_BOOLEAN, false];
|
||||
}
|
||||
|
||||
protected function refererRule($value, $attr, $args)
|
||||
protected function vReferer($v, $value, $type, $attr, $args)
|
||||
{
|
||||
if (! is_array($args)) {
|
||||
$args = [];
|
||||
}
|
||||
return [$this->c->Router->validate($value, $attr), false];
|
||||
return [$this->c->Router->validate($value, $attr, $args), $type, false];
|
||||
}
|
||||
|
||||
protected function emailRule($value, $attr)
|
||||
protected function vEmail($v, $value, $type)
|
||||
{
|
||||
if ($this->c->Mail->valid($value)) {
|
||||
return [$value, false];
|
||||
if (null === $value) {
|
||||
return [$value, $type, false];
|
||||
} elseif ($this->c->Mail->valid($value)) {
|
||||
return [$value, $type, false];
|
||||
} else {
|
||||
if (! is_string($value)) {
|
||||
$value = (string) $value;
|
||||
}
|
||||
return [$value, 'The :alias is not valid email'];
|
||||
return [$value, $type, 'The :alias is not valid email'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function sameRule($value, $attr)
|
||||
protected function vSame($v, $value, $type, $attr)
|
||||
{
|
||||
if (isset($this->data[$attr]) && $value === $this->data[$attr]) {
|
||||
return [$value, false];
|
||||
if (! $v->getStatus($attr) || $value === $v->$attr) {
|
||||
return [$value, $type, false];
|
||||
} else {
|
||||
return [$value, 'The :alias must be same with original'];
|
||||
return [null, $type, 'The :alias must be same with original'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function vRegex($v, $value, $type, $attr)
|
||||
{
|
||||
if (null === $value) {
|
||||
return [$value, $type, false];
|
||||
} elseif ($type === $v::T_STRING && preg_match($attr, $value)) {
|
||||
return [$value, $type, false];
|
||||
} else {
|
||||
return [null, $type, 'The :alias is not valid format'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function vPassword($v, $value, $type)
|
||||
{
|
||||
return $this->vRegex($v, $value, $type, '%^(?=.*\p{N})(?=.*\p{Lu})(?=.*\p{Ll})(?=.*[^\p{N}\p{L}])%u');
|
||||
}
|
||||
|
||||
protected function vLogin($v, $value, $type)
|
||||
{
|
||||
return $this->vRegex($v, $value, $type, '%^\p{L}[\p{L}\p{N}\x20\._-]+$%uD');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,8 +34,9 @@ if (!defined('PUN_SEARCH_MAX_WORD'))
|
|||
if (!defined('FORUM_MAX_COOKIE_SIZE'))
|
||||
define('FORUM_MAX_COOKIE_SIZE', 4048);
|
||||
|
||||
$loader = require __DIR__ . '/../vendor/autoload.php';
|
||||
$loader->setPsr4('ForkBB\\', __DIR__ . '/');
|
||||
//$loader =
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
//$loader->setPsr4('ForkBB\\', __DIR__ . '/');
|
||||
|
||||
if (file_exists(__DIR__ . '/config/main.php')) {
|
||||
$container = new Container(include __DIR__ . '/config/main.php');
|
||||
|
@ -64,15 +65,13 @@ while (! $page instanceof Page && $cur = array_pop($controllers)) {
|
|||
$page = $container->$cur;
|
||||
}
|
||||
|
||||
if ($page instanceof Page) { //????
|
||||
if ($page->getDataForOnline(true)) {
|
||||
$container->Online->handle($page);
|
||||
}
|
||||
$tpl = $container->View->setPage($page)->outputPage();
|
||||
if (defined('PUN_DEBUG')) {
|
||||
$debug = $container->Debug->debug();
|
||||
$debug = $container->View->setPage($debug)->outputPage();
|
||||
$tpl = str_replace('<!-- debuginfo -->', $debug, $tpl);
|
||||
}
|
||||
exit($tpl);
|
||||
if ($page->getDataForOnline(true)) {
|
||||
$container->Online->handle($page);
|
||||
}
|
||||
$tpl = $container->View->setPage($page)->outputPage();
|
||||
if (defined('PUN_DEBUG')) {
|
||||
$debug = $container->Debug->debug();
|
||||
$debug = $container->View->setPage($debug)->outputPage();
|
||||
$tpl = str_replace('<!-- debuginfo -->', $debug, $tpl);
|
||||
}
|
||||
exit($tpl);
|
||||
|
|
|
@ -12,6 +12,15 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: en\n"
|
||||
|
||||
msgid "Sign in"
|
||||
msgstr "Sign in"
|
||||
|
||||
msgid "Banned email"
|
||||
msgstr "The email address you entered is banned in this forum."
|
||||
|
||||
msgid "Account is not activated"
|
||||
msgstr "Account is not activated."
|
||||
|
||||
msgid "Wrong user/pass"
|
||||
msgstr "Wrong username and/or password."
|
||||
|
||||
|
@ -39,11 +48,29 @@ msgstr "Remember me"
|
|||
msgid "Forget mail"
|
||||
msgstr "An email has been sent to the specified address with instructions on how to change your password. If it does not arrive you can contact the forum administrator at <a href=\"mailto:%1$s\">%1$s</a>."
|
||||
|
||||
msgid "Error mail"
|
||||
msgstr "When sending email there was an error. Try later or contact the forum administrator at <a href=\"mailto:%1$s\">%1$s</a>."
|
||||
|
||||
msgid "Email flood"
|
||||
msgstr "This account has already requested a password reset in the past hour. Please wait %s minutes before trying again."
|
||||
|
||||
msgid "Pass not match"
|
||||
msgstr "Passwords do not match."
|
||||
|
||||
msgid "Change pass"
|
||||
msgstr "Change password"
|
||||
|
||||
msgid "Change password"
|
||||
msgstr "Change password"
|
||||
|
||||
msgid "New pass"
|
||||
msgstr "New password"
|
||||
|
||||
msgid "Confirm new pass"
|
||||
msgstr "Confirm new password"
|
||||
|
||||
msgid "Pass format"
|
||||
msgstr "Password must contain the digit, uppercase and lowercase letters, symbol different from the digits and letters."
|
||||
|
||||
msgid "Pass info"
|
||||
msgstr "Passwords must be at least 8 characters long. Passwords are case sensitive."
|
||||
|
||||
msgid "Pass updated"
|
||||
msgstr "Your password has been updated. You can now login with your new password."
|
|
@ -24,9 +24,15 @@ msgstr "."
|
|||
msgid "lang_thousands_sep"
|
||||
msgstr ","
|
||||
|
||||
msgid "Forum rules"
|
||||
msgstr "Forum rules"
|
||||
|
||||
msgid "Redirecting to index"
|
||||
msgstr "Redirecting to Index page."
|
||||
|
||||
msgid "Error mail"
|
||||
msgstr "When sending email there was an error. Please try again later or contact the forum administrator at <a href=\"mailto:%1$s\">%1$s</a>."
|
||||
|
||||
msgid "Bad token"
|
||||
msgstr "Bad token."
|
||||
|
||||
|
@ -451,7 +457,7 @@ msgid "New reports"
|
|||
msgstr "There are new reports"
|
||||
|
||||
msgid "Maintenance mode enabled"
|
||||
msgstr "Maintenance mode is enabled!"
|
||||
msgstr "<a href=\"%s\"Maintenance mode is enabled!</a>"
|
||||
|
||||
msgid "Size unit B"
|
||||
msgstr "%s B"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
Subject: Alert - New registration
|
||||
|
||||
User '<username>' registered in the forums at <base_url>
|
||||
User '<username>' registered in the forums at <fRootLink>
|
||||
|
||||
User profile: <profile_url>
|
||||
User profile: <userLink>
|
||||
|
||||
To administer this account, please visit the following page:
|
||||
<admin_url>
|
||||
|
||||
--
|
||||
<board_mailer> Mailer
|
||||
<fMailer> Mailer
|
||||
(Do not reply to this message)
|
||||
|
|
|
@ -2,13 +2,11 @@ Subject: New password requested
|
|||
|
||||
Hello <username>,
|
||||
|
||||
You have requested to have a new password assigned to your account in the discussion forum at <base_url>. If you didn't request this or if you don't want to change your password you should just ignore this message. Only if you visit the activation page below will your password be changed.
|
||||
|
||||
Your new password is: <new_password>
|
||||
You have requested to have a new password assigned to your account in the discussion forum at <fRootLink>
|
||||
|
||||
To change your password, please visit the following page:
|
||||
<activation_url>
|
||||
<link>
|
||||
|
||||
--
|
||||
<board_mailer> Mailer
|
||||
<fMailer> Mailer
|
||||
(Do not reply to this message)
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
Subject: Welcome to <board_title>!
|
||||
Subject: Welcome to <fTitle>!
|
||||
|
||||
Thank you for registering in the forums at <base_url>. Your account details are:
|
||||
Thank you for registering in the forums at <fRootLink>.
|
||||
|
||||
Username: <username>
|
||||
Password: <password>
|
||||
Your username: <username>
|
||||
|
||||
Login at <login_url> to activate the account.
|
||||
Go <link> to activate your account.
|
||||
|
||||
--
|
||||
<board_mailer> Mailer
|
||||
<fMailer> Mailer
|
||||
(Do not reply to this message)
|
||||
|
|
|
@ -78,6 +78,9 @@ msgstr "New password"
|
|||
msgid "Confirm new pass"
|
||||
msgstr "Confirm new password"
|
||||
|
||||
msgid "Pass format"
|
||||
msgstr "Password must contain the digit, uppercase and lowercase letters, symbol different from the digits and letters."
|
||||
|
||||
msgid "Pass info"
|
||||
msgstr "Passwords must be at least 8 characters long. Passwords are case sensitive."
|
||||
|
||||
|
|
70
app/lang/English/register.po
Normal file
70
app/lang/English/register.po
Normal file
|
@ -0,0 +1,70 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Project-Id-Version: ForkBB\n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: ForkBB <mio.visman@yandex.ru>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: en\n"
|
||||
|
||||
msgid "Sign up"
|
||||
msgstr "Sign up"
|
||||
|
||||
msgid "If no rules"
|
||||
msgstr "Treat other people the way you want to be treated yourself."
|
||||
|
||||
msgid "Bad agree"
|
||||
msgstr "ID forms obsolete. Please begin <a href=\"%s\">registration</a> again."
|
||||
|
||||
msgid "Reg cancel redirect"
|
||||
msgstr "No you agree with the forum rules. Registration cancelled. Redirecting …"
|
||||
|
||||
msgid "Registration flood"
|
||||
msgstr "A new user was registered with the same IP address as you within the last hour. To prevent registration flooding, at least an hour has to pass between registrations from the same IP. Sorry for the inconvenience."
|
||||
|
||||
msgid "Agree"
|
||||
msgstr "Agree"
|
||||
|
||||
msgid "Username guest"
|
||||
msgstr "The username guest is reserved. Please choose another username."
|
||||
|
||||
msgid "Username censor"
|
||||
msgstr "The username you entered contains one or more censored words. Please choose another username."
|
||||
|
||||
msgid "Banned username"
|
||||
msgstr "The username you entered is banned in this forum. Please choose another username."
|
||||
|
||||
msgid "Username not unique"
|
||||
msgstr "The username you entered is not unique. Please choose another username."
|
||||
|
||||
msgid "Banned email"
|
||||
msgstr "The email address you entered is banned in this forum. Please choose another email address."
|
||||
|
||||
msgid "Dupe email"
|
||||
msgstr "Someone else is already registered with that email address. Please choose another email address."
|
||||
|
||||
msgid "Reg email"
|
||||
msgstr "Thank you for registering. A letter with a link to activate your account was sent to the specified address. If it doesn't arrive you can contact the forum administrator at <a href=\"mailto:%1$s\">%1$s</a>."
|
||||
|
||||
msgid "Reg complete"
|
||||
msgstr "Registration complete. You can log in the forums."
|
||||
|
||||
msgid "Email info"
|
||||
msgstr "Please enter a valid email address. It will be used to activate your account."
|
||||
|
||||
msgid "Pass format"
|
||||
msgstr "Password must contain the digit, uppercase and lowercase letters, symbol different from the digits and letters."
|
||||
|
||||
msgid "Pass info"
|
||||
msgstr "Passwords must be at least 8 characters long. Passwords are case sensitive."
|
||||
|
||||
msgid "Login format"
|
||||
msgstr "The username must begin with a letter. May contain letters, numbers, spaces, dots, dashes and underscores."
|
||||
|
||||
msgid "Error welcom mail"
|
||||
msgstr "When sending email there was an error. Please use the password reset form or contact the forum administrator at <a href=\"mailto:%1$s\">%1$s</a>."
|
|
@ -12,6 +12,15 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ru\n"
|
||||
|
||||
msgid "Sign in"
|
||||
msgstr "Войти"
|
||||
|
||||
msgid "Banned email"
|
||||
msgstr "Введенный почтовый адрес заблокирован."
|
||||
|
||||
msgid "Account is not activated"
|
||||
msgstr "Аккаунт не активирован."
|
||||
|
||||
msgid "Wrong user/pass"
|
||||
msgstr "Неверное имя и/или пароль. Имя и пароль чувствительны к регистру!"
|
||||
|
||||
|
@ -39,11 +48,29 @@ msgstr "Запомнить меня"
|
|||
msgid "Forget mail"
|
||||
msgstr "Письмо с инструкцией по изменению пароля было выслано на указанный вами почтовый адрес. Если вы не получите его, свяжитесь с администрацией форума по адресу <a href=\"mailto:%1$s\">%1$s</a>."
|
||||
|
||||
msgid "Error mail"
|
||||
msgstr "При отправки письма возникла ошибка. Попробуйте позже или свяжитесь с администратором форума по адресу <a href=\"mailto:%1$s\">%1$s</a>."
|
||||
|
||||
msgid "Email flood"
|
||||
msgstr "Для этой учетной записи недавно уже запрашивали сброс пароля. Пожалуйста, подождите %s минут, прежде чем повторить попытку."
|
||||
|
||||
msgid "Pass not match"
|
||||
msgstr "Пароли не совпадают."
|
||||
|
||||
msgid "Change pass"
|
||||
msgstr "Смена пароля"
|
||||
|
||||
msgid "Change password"
|
||||
msgstr "Сменить пароль"
|
||||
|
||||
msgid "New pass"
|
||||
msgstr "Новый пароль"
|
||||
|
||||
msgid "Confirm new pass"
|
||||
msgstr "Ещё раз"
|
||||
|
||||
msgid "Pass format"
|
||||
msgstr "Пароль должен содержать цифру, строчную и прописную буквы, символ отличающийся от цифр и букв."
|
||||
|
||||
msgid "Pass info"
|
||||
msgstr "Пароль должен состоять минимум из 8 символов. Пароль чувствителен к регистру вводимых букв."
|
||||
|
||||
msgid "Pass updated"
|
||||
msgstr "Ваш пароль изменён. Вы можете войти на форум с новым паролем."
|
|
@ -24,9 +24,15 @@ msgstr "."
|
|||
msgid "lang_thousands_sep"
|
||||
msgstr ","
|
||||
|
||||
msgid "Forum rules"
|
||||
msgstr "Правила форума"
|
||||
|
||||
msgid "Redirecting to index"
|
||||
msgstr "Перенаправление на главную страницу форума."
|
||||
|
||||
msgid "Error mail"
|
||||
msgstr "При отправке письма возникла ошибка. Пожалуйста, повторите попытку позже или свяжитесь с администратором форума по адресу <a href=\"mailto:%1$s\">%1$s</a>."
|
||||
|
||||
msgid "Bad request"
|
||||
msgstr "Неверный запрос. Ссылка, по которой вы перешли, является неверной или просроченной."
|
||||
|
||||
|
@ -451,7 +457,7 @@ msgid "New reports"
|
|||
msgstr "Есть новые сигналы"
|
||||
|
||||
msgid "Maintenance mode enabled"
|
||||
msgstr "Включен режим обслуживания!"
|
||||
msgstr "<a href=\"%s\">Включен режим обслуживания!</a>"
|
||||
|
||||
msgid "Size unit B"
|
||||
msgstr "%s байт"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
Subject: Внимание - Новая регистрация
|
||||
|
||||
Пользователь '<username>' зарегистрировался на форуме по адресу <base_url>
|
||||
Пользователь '<username>' зарегистрировался на форуме по адресу <fRootLink>
|
||||
|
||||
Адрес профиля пользователя: <profile_url>
|
||||
Адрес профиля пользователя: <userLink>
|
||||
|
||||
Для управления этой учетной записью, пожалуйста, посетите следующую страницу:
|
||||
<admin_url>
|
||||
|
||||
--
|
||||
Отправитель <board_mailer>
|
||||
(Не отвечайте на это сообщение)
|
||||
Отправитель <fMailer>
|
||||
(Не отвечайте на это сообщение)
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
Subject: Запрос на смену пароля
|
||||
|
||||
Здравствуйте <username>,
|
||||
Здравствуйте, <username>.
|
||||
|
||||
Кто-то, возможно вы, сделал запрос на смену пароля аккаунта на форуме <base_url>. Если это не вы или если вы не хотите менять пароль, просто проигнорируйте это письмо. Ваш пароль изменится только если вы посетите активационную ссылку.
|
||||
Кто-то, возможно вы, сделал запрос на смену пароля аккаунта на форуме <fRootLink>
|
||||
|
||||
Ваш новый пароль: <new_password>
|
||||
|
||||
Чтобы установить этот пароль, пожалуйста пройдите по этой ссылке:
|
||||
<activation_url>
|
||||
Чтобы сменить пароль, вам нужно перейти по ссылке:
|
||||
<link>
|
||||
|
||||
--
|
||||
Отправитель <board_mailer>
|
||||
(Не отвечайте на это сообщение)
|
||||
Отправитель <fMailer>
|
||||
(Не отвечайте на это сообщение)
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
Subject: Добро пожаловать на <board_title>!
|
||||
Subject: Добро пожаловать на <fTitle>!
|
||||
|
||||
Добро пожаловать на форум по адресу <base_url>. Детали вашего аккаунта:
|
||||
Добро пожаловать на форум по адресу <fRootLink>.
|
||||
|
||||
Пользователь: <username>
|
||||
Пароль: <password>
|
||||
Ваше имя пользователя: <username>
|
||||
|
||||
Залогиньтесь на странице <login_url> чтобы активировать аккаунт.
|
||||
Перейдите по ссылке <link> чтобы активировать аккаунт.
|
||||
|
||||
--
|
||||
Отправитель <board_mailer>
|
||||
Отправитель <fMailer>
|
||||
(Не отвечайте на это сообщение)
|
||||
|
|
|
@ -78,6 +78,9 @@ msgstr "Новый пароль"
|
|||
msgid "Confirm new pass"
|
||||
msgstr "Ещё раз"
|
||||
|
||||
msgid "Pass format"
|
||||
msgstr "Пароль должен содержать цифру, строчную и прописную буквы, символ отличающийся от цифр и букв."
|
||||
|
||||
msgid "Pass info"
|
||||
msgstr "Пароль должен состоять минимум из 8 символов. Пароль чувствителен к регистру вводимых букв."
|
||||
|
||||
|
|
70
app/lang/Russian/register.po
Normal file
70
app/lang/Russian/register.po
Normal file
|
@ -0,0 +1,70 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
"Project-Id-Version: ForkBB\n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: ForkBB <mio.visman@yandex.ru>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ru\n"
|
||||
|
||||
msgid "Sign up"
|
||||
msgstr "Зарегистрироваться"
|
||||
|
||||
msgid "If no rules"
|
||||
msgstr "Относитесь к другим так, как хотите, чтобы относились к вам."
|
||||
|
||||
msgid "Bad agree"
|
||||
msgstr "Идентификатор формы устарел. Пожалуйста, начните <a href=\"%s\">регистрацию</a> заново."
|
||||
|
||||
msgid "Reg cancel redirect"
|
||||
msgstr "Нет вашего согласия с правилами форума. Регистрация отменена. Переадресация …"
|
||||
|
||||
msgid "Registration flood"
|
||||
msgstr "Недавно с вашего IP адреса был зарегистрирован новый пользователь. Должно пройти не менее часа до следующей регистрации с этого IP адреса. Извините за неудобства."
|
||||
|
||||
msgid "Agree"
|
||||
msgstr "Принимаю правила"
|
||||
|
||||
msgid "Username guest"
|
||||
msgstr "Гость - зарезервированное имя. Пожалуйста, выберите другое имя."
|
||||
|
||||
msgid "Username censor"
|
||||
msgstr "Выбранное имя пользователя содержит запрещенные слова. Пожалуйста, выберите другое имя."
|
||||
|
||||
msgid "Banned username"
|
||||
msgstr "Введенное имя пользователя заблокировано. Пожалуйста, выберите другое имя."
|
||||
|
||||
msgid "Username not unique"
|
||||
msgstr "Выбранное имя пользователя не уникально. Пожалуйста, выберите другое имя."
|
||||
|
||||
msgid "Banned email"
|
||||
msgstr "Введенный почтовый адрес заблокирован. Пожалуйста, выберите другой адрес."
|
||||
|
||||
msgid "Dupe email"
|
||||
msgstr "Введенный почтовый адрес уже кем-то используется. Пожалуйста, выберите другой адрес."
|
||||
|
||||
msgid "Reg email"
|
||||
msgstr "Спасибо за регистрацию. Письмо с ссылкой для активации аккаунта было отправлено на указанный почтовый адрес. Если оно не дойдет, свяжитесь с администратором форума по адресу <a href=\"mailto:%1$s\">%1$s</a>."
|
||||
|
||||
msgid "Reg complete"
|
||||
msgstr "Регистрация завершена. Вы можете войти на форум."
|
||||
|
||||
msgid "Email info"
|
||||
msgstr "Укажите действующий почтовый адрес. Он будет использован для активации аккаунта."
|
||||
|
||||
msgid "Pass format"
|
||||
msgstr "Пароль должен содержать цифру, строчную и прописную буквы, символ отличающийся от цифр и букв."
|
||||
|
||||
msgid "Pass info"
|
||||
msgstr "Пароль должен состоять минимум из 8 символов. Пароль чувствителен к регистру вводимых букв."
|
||||
|
||||
msgid "Login format"
|
||||
msgstr "Имя пользователя должно начинаться с буквы. Может содержать буквы, цифры, пробел, точку, дефис и знак подчеркивания."
|
||||
|
||||
msgid "Error welcom mail"
|
||||
msgstr "При отправке письма возникла ошибка. Пожалуйста, воспользуйтесь формой восстановления пароля или свяжитесь с администратором форума по адресу <a href=\"mailto:%1$s\">%1$s</a>."
|
|
@ -1,15 +1,21 @@
|
|||
@extends('layouts/main')
|
||||
<section class="f-main f-login">
|
||||
<div class="f-wdiv">
|
||||
<div class="f-lrdiv">
|
||||
<h2>{!! __('Change pass') !!}</h2>
|
||||
<form class="f-form" method="post" action="{!! $formAction !!}">
|
||||
<input type="hidden" name="token" value="{!! $formToken !!}">
|
||||
<label class="f-child1" for="id-password">{!! __('New pass') !!}</label>
|
||||
<input required id="id-password" type="password" name="password" pattern=".{8,}" autofocus="autofocus" tabindex="1">
|
||||
<label class="f-child1" for="id-password2">{!! __('Confirm new pass') !!}</label>
|
||||
<input required id="id-password2" type="password" name="password2" pattern=".{8,}" tabindex="2">
|
||||
<label class="f-child2">{!! __('Pass info') !!}</label>
|
||||
<input class="f-btn" type="submit" name="login" value="{!! __('Save') !!}" tabindex="3">
|
||||
<div>
|
||||
<label class="f-child1 f-req" for="id-password">{!! __('New pass') !!}</label>
|
||||
<input required class="f-ctrl" id="id-password" type="password" name="password" pattern=".{8,}" autofocus="autofocus" tabindex="1">
|
||||
</div>
|
||||
<div>
|
||||
<label class="f-child1 f-req" for="id-password2">{!! __('Confirm new pass') !!}</label>
|
||||
<input required class="f-ctrl" id="id-password2" type="password" name="password2" pattern=".{8,}" tabindex="2">
|
||||
<label class="f-child4">{!! __('Pass format') !!} {!! __('Pass info') !!}</label>
|
||||
</div>
|
||||
<div>
|
||||
<input class="f-btn" type="submit" name="login" value="{!! __('Change password') !!}" tabindex="3">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="{!! $fLang !!}" dir="{!! $fDirection !!}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="{!! $fLang !!} dir="{!! $fDirection !!}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
|
|
@ -1,24 +1,32 @@
|
|||
@extends('layouts/main')
|
||||
<section class="f-main f-login">
|
||||
<div class="f-wdiv">
|
||||
<div class="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="{{ $formRedirect }}">
|
||||
<label class="f-child1" for="id-username">{!! __('Username') !!}</label>
|
||||
<input required id="id-username" type="text" name="username" value="{{ $username }}" maxlength="25" autofocus="autofocus" spellcheck="false" tabindex="1">
|
||||
<label class="f-child1" for="id-password">{!! __('Password') !!}<a class="f-forgetlink" href="{!! $forgetLink !!}" tabindex="5">{!! __('Forgotten pass') !!}</a></label>
|
||||
<input required id="id-password" type="password" name="password" tabindex="2">
|
||||
@if($formSave)
|
||||
<input type="hidden" name="redirect" value="{{ $redirect }}">
|
||||
<div>
|
||||
<label class="f-child1 f-req" for="id-username">{!! __('Username') !!}</label>
|
||||
<input required class="f-ctrl" id="id-username" type="text" name="username" value="{{ $username }}" maxlength="25" autofocus="autofocus" spellcheck="false" tabindex="1">
|
||||
</div>
|
||||
<div>
|
||||
<label class="f-child1 f-req" for="id-password">{!! __('Password') !!}<a class="f-forgetlink" href="{!! $forgetLink !!}" tabindex="5">{!! __('Forgotten pass') !!}</a></label>
|
||||
<input required class="f-ctrl" id="id-password" type="password" name="password" tabindex="2">
|
||||
</div>
|
||||
<div>
|
||||
@if($save)
|
||||
<label class="f-child2"><input type="checkbox" name="save" value="1" tabindex="3" checked="checked">{!! __('Remember me') !!}</label>
|
||||
@else
|
||||
<label class="f-child2"><input type="checkbox" name="save" value="1" tabindex="3">{!! __('Remember me') !!}</label>
|
||||
@endif
|
||||
<input class="f-btn" type="submit" name="login" value="{!! __('Login') !!}" tabindex="4">
|
||||
</div>
|
||||
<div>
|
||||
<input class="f-btn" type="submit" name="login" value="{!! __('Sign in') !!}" tabindex="4">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@if($regLink)
|
||||
<div class="f-wdiv">
|
||||
<div class="f-lrdiv">
|
||||
<p class="f-child3"><a href="{!! $regLink !!}" tabindex="6">{!! __('Not registered') !!}</a></p>
|
||||
</div>
|
||||
@endif
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
@extends('layouts/main')
|
||||
<section class="f-main f-login">
|
||||
<div class="f-wdiv">
|
||||
<div class="f-lrdiv">
|
||||
<h2>{!! __('Password reset') !!}</h2>
|
||||
<form class="f-form" method="post" action="{!! $formAction !!}">
|
||||
<input type="hidden" name="token" value="{!! $formToken !!}">
|
||||
<label class="f-child1" for="id-email">{!! __('Email') !!}</label>
|
||||
<input required id="id-email" type="text" name="email" value="{{ $email }}" maxlength="80" autofocus="autofocus" spellcheck="false" tabindex="1">
|
||||
<label class="f-child2">{!! __('Password reset info') !!}</label>
|
||||
<input class="f-btn" type="submit" name="submit" value="{!! __('Submit') !!}" tabindex="2">
|
||||
<div>
|
||||
<label class="f-child1 f-req" for="id-email">{!! __('Email') !!}</label>
|
||||
<input required class="f-ctrl" id="id-email" type="text" name="email" value="{{ $email }}" maxlength="80" pattern=".+@.+" autofocus="autofocus" spellcheck="false" tabindex="1">
|
||||
<label class="f-child4">{!! __('Password reset info') !!}</label>
|
||||
</div>
|
||||
<div>
|
||||
<input class="f-btn" type="submit" name="submit" value="{!! __('Send email') !!}" tabindex="2">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
|
29
app/templates/register.tpl
Normal file
29
app/templates/register.tpl
Normal file
|
@ -0,0 +1,29 @@
|
|||
@extends('layouts/main')
|
||||
<section class="f-main f-register">
|
||||
<div class="f-lrdiv">
|
||||
<h2>{!! __('Register') !!}</h2>
|
||||
<form class="f-form" method="post" action="{!! $formAction !!}">
|
||||
<input type="hidden" name="token" value="{!! $formToken !!}">
|
||||
<input type="hidden" name="agree" value="{!! $agree !!}">
|
||||
<input type="hidden" name="on" value="{!! $on !!}">
|
||||
<div>
|
||||
<label class="f-child1 f-req" for="id-email">{!! __('Email') !!}</label>
|
||||
<input required class="f-ctrl" id="id-email" type="text" name="email" value="{{ $email }}" maxlength="80" pattern=".+@.+" autofocus="autofocus" spellcheck="false" tabindex="1">
|
||||
<label class="f-child4 f-fhint">{!! __('Email info') !!}</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="f-child1 f-req" for="id-username">{!! __('Username') !!}</label>
|
||||
<input required class="f-ctrl" id="id-username" type="text" name="username" value="{{ $username }}" maxlength="25" pattern=".{2,25}" spellcheck="false" tabindex="2">
|
||||
<label class="f-child4 f-fhint">{!! __('Login format') !!}</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="f-child1 f-req" for="id-password">{!! __('Password') !!}</label>
|
||||
<input required class="f-ctrl" id="id-password" type="password" name="password" pattern=".{8,}" tabindex="3">
|
||||
<label class="f-child4 f-fhint">{!! __('Pass format') !!} {!! __('Pass info') !!}</label>
|
||||
</div>
|
||||
<div>
|
||||
<input class="f-btn" type="submit" name="register" value="{!! __('Sign up') !!}" tabindex="5">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
|
@ -1,5 +1,18 @@
|
|||
@extends('layouts/main')
|
||||
<section class="f-main f-rules">
|
||||
<h2>{!! __('Forum rules') !!}</h2>
|
||||
<div>{!! $Rules !!}</div>
|
||||
<h2>{!! $title !!}</h2>
|
||||
<div id="id-rules">{!! $rules !!}</div>
|
||||
@if($formAction)
|
||||
<div class="f-lrdiv">
|
||||
<form class="f-form" method="post" action="{!! $formAction !!}">
|
||||
<input type="hidden" name="token" value="{!! $formToken !!}">
|
||||
<div>
|
||||
<label class="f-child2"><input type="checkbox" name="agree" value="{!! $formHash !!}" tabindex="1">{!! __('Agree') !!}</label>
|
||||
</div>
|
||||
<div>
|
||||
<input class="f-btn" type="submit" name="register" value="{!! __('Register') !!}" tabindex="2">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endif
|
||||
</section>
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
"homepage": "https://github.com/MioVisman"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ForkBB\\": "app/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"artoodetoo/dirk": "dev-master"
|
||||
|
|
4
composer.lock
generated
4
composer.lock
generated
|
@ -4,8 +4,8 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "6c899de021c8c6537d723a4f7d26f06d",
|
||||
"content-hash": "b734e8bdbede86eb0dbd047bb31d3a03",
|
||||
"hash": "ad22a23d7b225fa300553d8d0dcdaeb9",
|
||||
"content-hash": "2eea8744cdbc34c8408e6d137176a8df",
|
||||
"packages": [
|
||||
{
|
||||
"name": "artoodetoo/dirk",
|
||||
|
|
|
@ -669,6 +669,7 @@ switch ($stage)
|
|||
|
||||
$db->alter_field('users', 'password', 'VARCHAR(255)', false, '') or error('Unable to alter password field', __FILE__, __LINE__, $db->error());
|
||||
$db->add_field('user', 'u_mark_all_read', 'INT(10) UNSIGNED', true) or error('Unable to add u_mark_all_read field', __FILE__, __LINE__, $db->error());
|
||||
$db->add_field('user', 'email_confirmed', 'TINYINT(1)', false, 0, 'email') or error('Unable to add email_confirmed field', __FILE__, __LINE__, $db->error());
|
||||
|
||||
$db->add_field('online', 'o_position', 'VARCHAR(100)', false, '') or error('Unable to add o_position field', __FILE__, __LINE__, $db->error());
|
||||
$db->add_index('online', 'o_position_idx', array('o_position')) or error('Unable to add o_position_idx index', __FILE__, __LINE__, $db->error());
|
||||
|
|
|
@ -706,15 +706,11 @@ function delete_post($post_id, $topic_id)
|
|||
function censor_words($text)
|
||||
{
|
||||
global $container;
|
||||
static $search_for, $replace_with;
|
||||
|
||||
// If not already built in a previous call, build an array of censor words and their replacement text
|
||||
if (!isset($search_for)) {
|
||||
list($search_for, $replace_with) = $container->get('censoring');
|
||||
}
|
||||
list($search_for, $replace_with) = $container->censoring;
|
||||
|
||||
if (!empty($search_for)) {
|
||||
$text = substr(ucp_preg_replace($search_for, $replace_with, ' '.$text.' '), 1, -1);
|
||||
$text = preg_replace($search_for, $replace_with, $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
|
|
|
@ -194,6 +194,10 @@ select {
|
|||
content: ", ";
|
||||
}
|
||||
|
||||
.f-req:after {
|
||||
content: " *";
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* Меню */
|
||||
|
||||
|
@ -510,7 +514,7 @@ select {
|
|||
padding: 0.625rem;
|
||||
}
|
||||
|
||||
.f-rules > div {
|
||||
#id-rules {
|
||||
padding: 0.625rem;
|
||||
border: 0.0625rem solid #AA7939;
|
||||
background-color: #F8F4E3;
|
||||
|
@ -992,26 +996,27 @@ li + li .f-btn {
|
|||
}
|
||||
}
|
||||
|
||||
/*********/
|
||||
/* Логин */
|
||||
/*********/
|
||||
.f-login .f-wdiv {
|
||||
/*********************/
|
||||
/* Логин/Регистрация */
|
||||
/*********************/
|
||||
.f-lrdiv {
|
||||
margin: 1rem auto;
|
||||
max-width: 20rem;
|
||||
border: 0.0625rem solid #AA7939;
|
||||
border-radius: 0.1875rem;
|
||||
}
|
||||
|
||||
.f-login h2 {
|
||||
.f-lrdiv h2 {
|
||||
padding: 0.625rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.f-login .f-form {
|
||||
.f-lrdiv .f-form {
|
||||
padding: 0.625rem;
|
||||
}
|
||||
|
||||
.f-login .f-form > input {
|
||||
.f-lrdiv .f-ctrl,
|
||||
.f-lrdiv .f-btn {
|
||||
padding: 0.5rem;
|
||||
font-size: 1rem;
|
||||
display: block;
|
||||
|
@ -1020,7 +1025,10 @@ li + li .f-btn {
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.f-login .f-form > label {
|
||||
.f-lrdiv .f-child1,
|
||||
.f-lrdiv .f-child2,
|
||||
.f-lrdiv .f-child3,
|
||||
.f-lrdiv .f-child4 {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -1031,28 +1039,53 @@ li + li .f-btn {
|
|||
font-weight: normal;
|
||||
}
|
||||
|
||||
.f-login .f-child1 {
|
||||
.f-lrdiv .f-child1 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.f-login .f-child1:after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
.f-login .f-child2 {
|
||||
.f-lrdiv .f-child2 {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.f-login .f-child2 > input {
|
||||
.f-lrdiv .f-child2 > input {
|
||||
margin: 0 0.625rem 0 0;
|
||||
}
|
||||
|
||||
.f-login .f-btn {
|
||||
.f-lrdiv .f-btn {
|
||||
margin: 1rem 0 0.375rem 0;
|
||||
}
|
||||
|
||||
.f-login .f-child3 {
|
||||
.f-lrdiv .f-child3 {
|
||||
padding: 0.625rem;
|
||||
text-align: center;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.f-lrdiv .f-child4 {
|
||||
font-size: 0.8125rem;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.f-ctrl {
|
||||
border: 0.0625rem solid #AA7939;
|
||||
}
|
||||
|
||||
.f-ctrl:focus {
|
||||
box-shadow: inset 0px 0px 0.25rem 0 rgba(170,121,57,0.5), 0px 0px 0.25rem 0 rgba(170,121,57,0.5);
|
||||
}
|
||||
|
||||
.f-ctrl + .f-fhint {
|
||||
overflow: hidden;
|
||||
max-height: 0;
|
||||
-webkit-transition: max-height 0.5s, margin 0.5s;
|
||||
-webkit-transition-delay: 0.2s;
|
||||
transition: max-height 0.5s, margin 0.5s;
|
||||
transition-delay: 0.2s;
|
||||
}
|
||||
|
||||
.f-ctrl:focus + .f-fhint,
|
||||
.f-ctrl:active + .f-fhint {
|
||||
margin-top: -0.375rem;
|
||||
margin-bottom: 1rem;
|
||||
max-height: 1000rem;
|
||||
}
|
||||
|
|
1
vendor/composer/autoload_psr4.php
vendored
1
vendor/composer/autoload_psr4.php
vendored
|
@ -7,4 +7,5 @@ $baseDir = dirname($vendorDir);
|
|||
|
||||
return array(
|
||||
'R2\\Templating\\' => array($vendorDir . '/artoodetoo/dirk/src'),
|
||||
'ForkBB\\' => array($baseDir . '/app'),
|
||||
);
|
||||
|
|
8
vendor/composer/autoload_static.php
vendored
8
vendor/composer/autoload_static.php
vendored
|
@ -11,6 +11,10 @@ class ComposerStaticInit90ad93c7251d4f60daa9e545879c49e7
|
|||
array (
|
||||
'R2\\Templating\\' => 14,
|
||||
),
|
||||
'F' =>
|
||||
array (
|
||||
'ForkBB\\' => 7,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
|
@ -18,6 +22,10 @@ class ComposerStaticInit90ad93c7251d4f60daa9e545879c49e7
|
|||
array (
|
||||
0 => __DIR__ . '/..' . '/artoodetoo/dirk/src',
|
||||
),
|
||||
'ForkBB\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/../..' . '/app',
|
||||
),
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
|
|
Loading…
Reference in a new issue