Validator
This commit is contained in:
parent
44bb5dc6ca
commit
ffdcefb076
14 changed files with 545 additions and 132 deletions
app
Controllers
Core
Models
lang
templates/login
include
|
@ -40,8 +40,8 @@ class Routing
|
|||
$r->add('GET', '/login/forget', 'Auth:forget', 'Forget');
|
||||
$r->add('POST', '/login/forget', 'Auth:forgetPost');
|
||||
// смена пароля
|
||||
$r->add('GET', '/login/{email}/{key}', 'Auth:changePass', 'ChangePassword');
|
||||
$r->add('POST', '/login/{email}/{key}', 'Auth:changePassPost');
|
||||
$r->add('GET', '/login/{email}/{key}/{hash}', 'Auth:changePass', 'ChangePassword');
|
||||
$r->add('POST', '/login/{email}/{key}/{hash}', 'Auth:changePassPost');
|
||||
|
||||
// регистрация
|
||||
if ($config['o_regs_allow'] == '1') {
|
||||
|
@ -120,5 +120,4 @@ class Routing
|
|||
}
|
||||
return $page;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ class Router
|
|||
|
||||
/**
|
||||
* Конструктор
|
||||
* @param string $prefix
|
||||
* @param string $base
|
||||
*/
|
||||
public function __construct($base = '')
|
||||
{
|
||||
|
@ -183,8 +183,6 @@ class Router
|
|||
return [self::OK, $data[0], $args];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (empty($allowed)) {
|
||||
return [self::NOT_FOUND];
|
||||
} else {
|
||||
|
|
|
@ -16,9 +16,7 @@ class Secury
|
|||
|
||||
/**
|
||||
* Конструктор
|
||||
*
|
||||
* @param array $hmac
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
|
@ -35,12 +33,20 @@ class Secury
|
|||
|
||||
/**
|
||||
* Обертка для hash_hmac
|
||||
*
|
||||
* @param string $data
|
||||
* @return string
|
||||
*/
|
||||
public function hash($data)
|
||||
{
|
||||
return $this->hmac($data, md5(__DIR__));
|
||||
}
|
||||
|
||||
/**
|
||||
* Обертка для hash_hmac
|
||||
* @param string $data
|
||||
* @param string $key
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function hmac($data, $key)
|
||||
{
|
||||
|
@ -52,11 +58,9 @@ class Secury
|
|||
|
||||
/**
|
||||
* Возвращает случайный набор байтов заданной длины
|
||||
*
|
||||
* @param int $len
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
* @return string
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function randomKey($len)
|
||||
{
|
||||
|
@ -76,15 +80,12 @@ class Secury
|
|||
if (strlen($key) < $len) {
|
||||
throw new RuntimeException('Could not gather sufficient random data');
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает случайную строку заданной длины состоящую из символов 0-9 и a-f
|
||||
*
|
||||
* @param int $len
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function randomHash($len)
|
||||
|
@ -95,9 +96,7 @@ class Secury
|
|||
/**
|
||||
* Возвращает случайную строку заданной длины состоящую из цифр, латиницы,
|
||||
* знака минус и символа подчеркивания
|
||||
*
|
||||
* @param int $len
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function randomPass($len)
|
||||
|
@ -108,15 +107,12 @@ class Secury
|
|||
for ($i = 0; $i < $len; ++$i) {
|
||||
$result .= substr($chars, (ord($key[$i]) % strlen($chars)), 1);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacing invalid UTF-8 characters and remove control characters
|
||||
*
|
||||
* @param string|array $data
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public function replInvalidChars($data)
|
||||
|
@ -124,13 +120,11 @@ class Secury
|
|||
if (is_array($data)) {
|
||||
return array_map([$this, 'replInvalidChars'], $data);
|
||||
}
|
||||
|
||||
// Replacing invalid UTF-8 characters
|
||||
// slow, small memory
|
||||
//$data = mb_convert_encoding((string) $data, 'UTF-8', 'UTF-8');
|
||||
// fast, large memory
|
||||
$data = htmlspecialchars_decode(htmlspecialchars((string) $data, ENT_SUBSTITUTE, 'UTF-8'));
|
||||
|
||||
// Remove control characters
|
||||
return preg_replace('%[\x00-\x08\x0B-\x0C\x0E-\x1F]%', '', $data);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ class Csrf
|
|||
|
||||
/**
|
||||
* Конструктор
|
||||
*
|
||||
* @param Secury $secury
|
||||
* @param User $user
|
||||
*/
|
||||
|
@ -51,7 +50,7 @@ class Csrf
|
|||
* @param array $args
|
||||
* @return bool
|
||||
*/
|
||||
public function check($token, $marker, array $args = [])
|
||||
public function verify($token, $marker, array $args = [])
|
||||
{
|
||||
return is_string($token)
|
||||
&& preg_match('%f(\d+)$%D', $token, $matches)
|
||||
|
@ -59,5 +58,4 @@ class Csrf
|
|||
&& $matches[1] + 1800 > time()
|
||||
&& hash_equals($this->create($marker, $args, $matches[1]), $token);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class Online
|
|||
protected $user;
|
||||
|
||||
/**
|
||||
* Контролер
|
||||
* Конструктор
|
||||
* @param array $config
|
||||
* @param DB $db
|
||||
* @param User $user
|
||||
|
|
|
@ -33,7 +33,7 @@ class Auth extends Page
|
|||
{
|
||||
$this->c->get('Lang')->load('login');
|
||||
|
||||
if ($this->c->get('Csrf')->check($args['token'], 'Logout', $args)) {
|
||||
if ($this->c->get('Csrf')->verify($args['token'], 'Logout', $args)) {
|
||||
$user = $this->c->get('user');
|
||||
|
||||
$this->c->get('UserCookie')->deleteUserCookie();
|
||||
|
@ -43,7 +43,7 @@ class Auth extends Page
|
|||
return $this->c->get('Redirect')->setPage('Index')->setMessage(__('Logout redirect'));
|
||||
}
|
||||
|
||||
return $this->c->get('Redirect')->setPage('Index')->setMessage(__('Bad request'));
|
||||
return $this->c->get('Redirect')->setPage('Index')->setMessage(__('Bad token'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,36 +89,33 @@ class Auth extends Page
|
|||
{
|
||||
$this->c->get('Lang')->load('login');
|
||||
|
||||
$username = $this->c->get('Request')->postStr('username', '');
|
||||
$password = $this->c->get('Request')->postStr('password', '');
|
||||
$token = $this->c->get('Request')->postStr('token');
|
||||
$save = $this->c->get('Request')->postStr('save');
|
||||
$v = $this->c->get('Validator');
|
||||
$v->setRules([
|
||||
'token' => 'token:Login',
|
||||
'redirect' => 'referer:Index',
|
||||
'username' => ['required|string|min:2|max:25', __('Username')],
|
||||
'password' => ['required|string', __('Password')],
|
||||
'save' => 'checkbox',
|
||||
]);
|
||||
|
||||
$redirect = $this->c->get('Request')->postStr('redirect', '');
|
||||
$redirect = $this->c->get('Router')->validate($redirect, 'Index');
|
||||
$ok = $v->validation($_POST);
|
||||
$data = $v->getData();
|
||||
$this->iswev = $v->getErrors();
|
||||
|
||||
$args = [
|
||||
'_username' => $username,
|
||||
'_redirect' => $redirect,
|
||||
'_save' => $save,
|
||||
];
|
||||
|
||||
if (! $this->c->get('Csrf')->check($token, 'Login')) {
|
||||
$this->iswev['e'][] = __('Bad token');
|
||||
return $this->login($args);
|
||||
}
|
||||
|
||||
if (empty($username) || empty($password)) {
|
||||
if ($ok && ! $this->loginProcess($data['username'], $data['password'], $data['save'])) {
|
||||
$this->iswev['v'][] = __('Wrong user/pass');
|
||||
return $this->login($args);
|
||||
$ok = false;
|
||||
}
|
||||
|
||||
if (! $this->loginProcess($username, $password, ! empty($save))) {
|
||||
$this->iswev['v'][] = __('Wrong user/pass');
|
||||
return $this->login($args);
|
||||
if ($ok) {
|
||||
return $this->c->get('Redirect')->setUrl($data['redirect'])->setMessage(__('Login redirect'));
|
||||
} else {
|
||||
return $this->login([
|
||||
'_username' => $data['username'],
|
||||
'_redirect' => $data['redirect'],
|
||||
'_save' => $data['save'],
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->c->get('Redirect')->setUrl($redirect)->setMessage(__('Login redirect'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,7 +193,7 @@ class Auth extends Page
|
|||
}
|
||||
|
||||
$this->titles = [
|
||||
__('Request pass'),
|
||||
__('Password reset'),
|
||||
];
|
||||
$this->data = [
|
||||
'email' => $args['_email'],
|
||||
|
@ -215,43 +212,43 @@ class Auth extends Page
|
|||
{
|
||||
$this->c->get('Lang')->load('login');
|
||||
|
||||
$token = $this->c->get('Request')->postStr('token');
|
||||
$email = $this->c->get('Request')->postStr('email');
|
||||
$v = $this->c->get('Validator');
|
||||
$v->setRules([
|
||||
'token' => 'token:Forget',
|
||||
'email' => 'required|email',
|
||||
])->setMessages([
|
||||
'email' => __('Invalid email'),
|
||||
]);
|
||||
|
||||
$args = [
|
||||
'_email' => $email,
|
||||
];
|
||||
$ok = $v->validation($_POST);
|
||||
$data = $v->getData();
|
||||
$this->iswev = $v->getErrors();
|
||||
|
||||
if (! $this->c->get('Csrf')->check($token, 'Forget')) {
|
||||
$this->iswev['e'][] = __('Bad token');
|
||||
return $this->forget($args);
|
||||
if ($ok && ($user = $this->c->get('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) {
|
||||
return $this->forget([
|
||||
'_email' => $data['email'],
|
||||
]);
|
||||
}
|
||||
|
||||
$mail = $this->c->get('Mail');
|
||||
if (! $mail->valid($email)) {
|
||||
$this->iswev['v'][] = __('Invalid email');
|
||||
return $this->forget($args);
|
||||
}
|
||||
|
||||
$user = $this->c->get('UserMapper')->getUser($email, 'email');
|
||||
if (null == $user) {
|
||||
$this->iswev['v'][] = __('Invalid email');
|
||||
return $this->forget($args);
|
||||
}
|
||||
|
||||
if (! empty($user->lastEmailSent) && time() - $user->lastEmailSent < 3600) {
|
||||
$this->iswev['e'][] = __('Email flood', (int) (($user->lastEmailSent + 3600 - time()) / 60));
|
||||
return $this->forget($args);
|
||||
}
|
||||
|
||||
$mail->setFolder($this->c->getParameter('DIR_LANG'))
|
||||
->setLanguage($user->language);
|
||||
|
||||
$key = 'p' . $this->c->get('Secury')->randomPass(75);
|
||||
$link = $this->c->get('Router')->link('ChangePassword', ['email' => $email, 'key' => $key]);
|
||||
$data = ['key' => $key, 'link' => $link];
|
||||
$hash = $this->c->get('Secury')->hash($data['email'] . $key);
|
||||
$link = $this->c->get('Router')->link('ChangePassword', ['email' => $data['email'], 'key' => $key, 'hash' => $hash]);
|
||||
$tplData = ['link' => $link];
|
||||
|
||||
if ($mail->send($email, 'change_password.tpl', $data)) {
|
||||
if ($mail->send($data['email'], 'change_password.tpl', $tplData)) {
|
||||
$this->c->get('UserMapper')->updateUser($user->id, ['activate_string' => $key, 'last_email_sent' => time()]);
|
||||
return $this->c->get('Message')->message(__('Forget mail', $this->config['o_admin_email']), false, 200);
|
||||
} else {
|
||||
|
@ -269,14 +266,19 @@ class Auth extends Page
|
|||
$this->nameTpl = 'login/password';
|
||||
$this->onlinePos = 'password';
|
||||
|
||||
// что-то пошло не так
|
||||
if (! $this->c->get('Mail')->valid($args['email'])
|
||||
|| ($user = $this->c->get('UserMapper')->getUser($args['email'], 'email')) === null
|
||||
|| empty($user->activateString)
|
||||
|| $user->activateString{0} !== 'p'
|
||||
|| ! hash_equals($user->activateString, $args['key'])
|
||||
) {
|
||||
return $this->c->get('Message')->message(__('Bad request'), false);
|
||||
if (isset($args['_ok'])) {
|
||||
unset($args['_ok']);
|
||||
} else {
|
||||
// что-то пошло не так
|
||||
if (! hash_equals($args['hash'], $this->c->get('Secury')->hash($args['email'] . $args['key']))
|
||||
|| ! $this->c->get('Mail')->valid($args['email'])
|
||||
|| ($user = $this->c->get('UserMapper')->getUser($args['email'], 'email')) === null
|
||||
|| empty($user->activateString)
|
||||
|| $user->activateString{0} !== 'p'
|
||||
|| ! hash_equals($user->activateString, $args['key'])
|
||||
) {
|
||||
return $this->c->get('Message')->message(__('Bad request'), false);
|
||||
}
|
||||
}
|
||||
|
||||
$this->c->get('Lang')->load('login');
|
||||
|
@ -300,14 +302,11 @@ class Auth extends Page
|
|||
*/
|
||||
public function changePassPost(array $args)
|
||||
{
|
||||
$token = $this->c->get('Request')->postStr('token');
|
||||
$password = $this->c->get('Request')->postStr('password', '');
|
||||
$password2 = $this->c->get('Request')->postStr('password2', '');
|
||||
|
||||
$this->c->get('Lang')->load('login');
|
||||
|
||||
// что-то пошло не так
|
||||
if (! $this->c->get('Mail')->valid($args['email'])
|
||||
if (! hash_equals($args['hash'], $this->c->get('Secury')->hash($args['email'] . $args['key']))
|
||||
|| ! $this->c->get('Mail')->valid($args['email'])
|
||||
|| ($user = $this->c->get('UserMapper')->getUser($args['email'], 'email')) === null
|
||||
|| empty($user->activateString)
|
||||
|| $user->activateString{0} !== 'p'
|
||||
|
@ -316,23 +315,29 @@ class Auth extends Page
|
|||
return $this->c->get('Message')->message(__('Bad request'), false);
|
||||
}
|
||||
|
||||
if (! $this->c->get('Csrf')->check($token, 'ChangePassword', $args)) {
|
||||
$this->iswev['e'][] = __('Bad token');
|
||||
return $this->changePass($args);
|
||||
}
|
||||
if (mb_strlen($password) < 6) {
|
||||
$this->iswev['v'][] = __('Pass too short');
|
||||
return $this->changePass($args);
|
||||
}
|
||||
if ($password !== $password2) {
|
||||
$this->iswev['v'][] = __('Pass not match');
|
||||
return $this->changePass($args);
|
||||
}
|
||||
|
||||
$this->c->get('UserMapper')->updateUser($user->id, ['password' => password_hash($password, PASSWORD_DEFAULT), 'activate_string' => null]);
|
||||
|
||||
$this->c->get('Lang')->load('profile');
|
||||
|
||||
$v = $this->c->get('Validator');
|
||||
$v->setRules([
|
||||
'token' => 'token:ChangePassword',
|
||||
'password' => ['required|string|min:8', __('New pass')],
|
||||
'password2' => 'required|same:password',
|
||||
])->setArguments([
|
||||
'token' => $args,
|
||||
])->setMessages([
|
||||
'password2' => __('Pass not match'),
|
||||
]);
|
||||
|
||||
if (! $v->validation($_POST)) {
|
||||
$this->iswev = $v->getErrors();
|
||||
$args['_ok'] = true;
|
||||
return $this->changePass($args);
|
||||
}
|
||||
$data = $v->getData();
|
||||
|
||||
$this->c->get('UserMapper')->updateUser($user->id, ['password' => password_hash($data['password'], PASSWORD_DEFAULT), 'activate_string' => null]);
|
||||
|
||||
$this->iswev['s'][] = __('Pass updated');
|
||||
return $this->login([]);
|
||||
return $this->login(['_redirect' => $this->c->get('Router')->link('Index')]);
|
||||
}
|
||||
}
|
||||
|
|
423
app/Models/Validator.php
Normal file
423
app/Models/Validator.php
Normal file
|
@ -0,0 +1,423 @@
|
|||
<?php
|
||||
|
||||
namespace ForkBB\Models;
|
||||
|
||||
use R2\DependencyInjection\ContainerInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class Validator
|
||||
{
|
||||
const T_UNKNOWN = 0;
|
||||
const T_STRING = 1;
|
||||
const T_NUMERIC = 2;
|
||||
const T_INT = 3;
|
||||
const T_ARRAY = 4;
|
||||
|
||||
/**
|
||||
* Контейнер
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $c;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $rules;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $arguments;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $messages;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $aliases;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $errors;
|
||||
|
||||
/**
|
||||
* Тип текущего поля при валидации
|
||||
* @var int
|
||||
*/
|
||||
protected $curType;
|
||||
|
||||
/**
|
||||
* Конструктор
|
||||
* @param ContainerInterface $container
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->c = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Установка правил проверки
|
||||
* @param array $list
|
||||
* @return Validator
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function setRules(array $list)
|
||||
{
|
||||
$this->rules = [];
|
||||
$this->data = [];
|
||||
$this->alias = [];
|
||||
$this->errors = [];
|
||||
$this->arguments = [];
|
||||
foreach ($list as $field => $raw) {
|
||||
$rules = [];
|
||||
// псевдоним содержится в списке правил
|
||||
if (is_array($raw)) {
|
||||
$this->aliases[$field] = $raw[1];
|
||||
$raw = $raw[0];
|
||||
}
|
||||
// перебор правил для текущего поля
|
||||
$rawRules = explode('|', $raw);
|
||||
foreach ($rawRules as $rule) {
|
||||
$tmp = explode(':', $rule, 2);
|
||||
if (! method_exists($this, $tmp[0] . 'Rule')) {
|
||||
throw new RuntimeException('Rule not found');
|
||||
}
|
||||
$rules[$tmp[0]] = isset($tmp[1]) ? $tmp[1] : '';
|
||||
}
|
||||
$this->rules[$field] = $rules;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Установка дополнительных аргументов для конкретных "имя поля"."имя правила".
|
||||
* @param array $arguments
|
||||
* @return Validator
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Установка сообщений для конкретных "имя поля"."имя правила".
|
||||
* @param array $messages
|
||||
* @return Validator
|
||||
*/
|
||||
public function setMessages(array $messages)
|
||||
{
|
||||
$this->messages = $messages;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Установка псевдонимов имен полей для сообщений об ошибках
|
||||
* @param array $aliases
|
||||
* @return Validator
|
||||
*/
|
||||
public function setAliases(array $aliases)
|
||||
{
|
||||
$this->aliases = $aliases;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверка данных
|
||||
* Удачная проверка возвращает true
|
||||
* @param array $raw
|
||||
* @return bool
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function validation(array $raw)
|
||||
{
|
||||
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->get('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;
|
||||
}
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение дополнительных аргументов
|
||||
* @param string $field
|
||||
* @param string $field
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getArguments($field, $rule)
|
||||
{
|
||||
if (isset($this->arguments[$field . '.'. $rule])) {
|
||||
return $this->arguments[$field . '.'. $rule];
|
||||
} elseif (isset($this->arguments[$field])) {
|
||||
return $this->arguments[$field];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Обработка ошибки
|
||||
* @param mixed $error
|
||||
* @param string $field
|
||||
* @param string $rule
|
||||
* @param string $attr
|
||||
* @param bool $ok
|
||||
* return bool
|
||||
*/
|
||||
protected function error($error, $field, $rule, $attr, $ok)
|
||||
{
|
||||
if (is_bool($error)) {
|
||||
return $ok;
|
||||
}
|
||||
// псевдоним имени поля
|
||||
$alias = isset($this->aliases[$field]) ? $this->aliases[$field] : $field;
|
||||
// текст ошибки
|
||||
if (isset($this->messages[$field . '.' . $rule])) {
|
||||
$error = $this->messages[$field . '.' . $rule];
|
||||
} elseif (isset($this->messages[$field])) {
|
||||
$error = $this->messages[$field];
|
||||
}
|
||||
$type = 'v';
|
||||
// ошибка содержит тип
|
||||
if (is_array($error)) {
|
||||
$type = $error[1];
|
||||
$error = $error[0];
|
||||
}
|
||||
$this->errors[$type][] = __($error, [':alias' => $alias, ':attr' => $attr]);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает проверенные данные
|
||||
* Поля с ошибками содержат значения по умолчанию или значения с ошибками
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
if (empty($this->data)) {
|
||||
throw new RuntimeException('Data not found');
|
||||
}
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возращает массив ошибок
|
||||
* @return array
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$this->curType = self::T_STRING;
|
||||
return [$value, false];
|
||||
} else {
|
||||
return [$attr, 'The :alias must be string'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function numericRule($value, $attr)
|
||||
{
|
||||
if (is_numeric($value)) {
|
||||
$this->curType = self::T_NUMERIC;
|
||||
return [0 + $value, false];
|
||||
} else {
|
||||
return [$attr, 'The :alias must be numeric'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function intRule($value, $attr)
|
||||
{
|
||||
if (is_numeric($value) && is_int(0 + $value)) {
|
||||
$this->curType = self::T_INT;
|
||||
return [(int) $value, false];
|
||||
} else {
|
||||
return [$attr, 'The :alias must be integer'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function arrayRule($value, $attr)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$this->curType = self::T_ARRAY;
|
||||
return [$value, false];
|
||||
} else {
|
||||
return [$attr, 'The :alias must be array'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function minRule($value, $attr)
|
||||
{
|
||||
switch ($this->curType) {
|
||||
case self::T_STRING:
|
||||
if (mb_strlen($value) < $attr) {
|
||||
return [$value, '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'];
|
||||
}
|
||||
break;
|
||||
case self::T_ARRAY:
|
||||
if (count($value) < $attr) {
|
||||
return [$value, 'The :alias minimum is :attr elements'];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ['', 'The :alias minimum is :attr'];
|
||||
break;
|
||||
}
|
||||
return [$value, false];
|
||||
}
|
||||
|
||||
protected function maxRule($value, $attr)
|
||||
{
|
||||
switch ($this->curType) {
|
||||
case self::T_STRING:
|
||||
if (mb_strlen($value) > $attr) {
|
||||
return [$value, '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'];
|
||||
}
|
||||
break;
|
||||
case self::T_ARRAY:
|
||||
if (count($value) > $attr) {
|
||||
return [$value, 'The :alias maximum is :attr elements'];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ['', 'The :alias maximum is :attr'];
|
||||
break;
|
||||
}
|
||||
return [$value, false];
|
||||
}
|
||||
|
||||
protected function tokenRule($value, $attr, $args)
|
||||
{
|
||||
if (! is_array($args)) {
|
||||
$args = [];
|
||||
}
|
||||
if (is_string($value) && $this->c->get('Csrf')->verify($value, $attr, $args)) {
|
||||
return [$value, false];
|
||||
} else {
|
||||
return ['', ['Bad token', 'e']];
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkboxRule($value, $attr)
|
||||
{
|
||||
return [! empty($value), false]; //????
|
||||
}
|
||||
|
||||
protected function refererRule($value, $attr, $args)
|
||||
{
|
||||
if (! is_array($args)) {
|
||||
$args = [];
|
||||
}
|
||||
return [$this->c->get('Router')->validate($value, $attr), false];
|
||||
}
|
||||
|
||||
protected function emailRule($value, $attr)
|
||||
{
|
||||
if ($this->c->get('Mail')->valid($value)) {
|
||||
return [$value, false];
|
||||
} else {
|
||||
if (! is_string($value)) {
|
||||
$value = (string) $value;
|
||||
}
|
||||
return [$value, 'The :alias is not valid email'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function sameRule($value, $attr)
|
||||
{
|
||||
if (isset($this->data[$attr]) && $value === $this->data[$attr]) {
|
||||
return [$value, false];
|
||||
} else {
|
||||
return [$value, 'The :alias must be same with original'];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,10 +24,10 @@ msgstr "Logged in successfully. Redirecting …"
|
|||
msgid "Logout redirect"
|
||||
msgstr "Logged out. Redirecting …"
|
||||
|
||||
msgid "Request pass"
|
||||
msgstr "Request password"
|
||||
msgid "Password reset"
|
||||
msgstr "Password reset"
|
||||
|
||||
msgid "Request pass info"
|
||||
msgid "Password reset info"
|
||||
msgstr "An email will be sent to the specified address with instructions on how to change your password."
|
||||
|
||||
msgid "Not registered"
|
||||
|
@ -43,10 +43,7 @@ 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 requesting a new password again."
|
||||
|
||||
msgid "Pass too short"
|
||||
msgstr "Passwords must be at least 6 characters long."
|
||||
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."
|
||||
|
|
|
@ -79,7 +79,7 @@ msgid "Confirm new pass"
|
|||
msgstr "Confirm new password"
|
||||
|
||||
msgid "Pass info"
|
||||
msgstr "Passwords must be at least 6 characters long. Passwords are case sensitive."
|
||||
msgstr "Passwords must be at least 8 characters long. Passwords are case sensitive."
|
||||
|
||||
msgid "Email key bad"
|
||||
msgstr "The specified email activation key was incorrect or has expired. Please re-request change of email address. If that fails, contact the forum administrator at"
|
||||
|
|
|
@ -24,11 +24,11 @@ msgstr "Успешный вход. Переадресация …"
|
|||
msgid "Logout redirect"
|
||||
msgstr "Выход произведён. Переадресация …"
|
||||
|
||||
msgid "Request pass"
|
||||
msgstr "Восстановление пароля"
|
||||
msgid "Password reset"
|
||||
msgstr "Сброс пароля"
|
||||
|
||||
msgid "Request pass info"
|
||||
msgstr "Инструкция по смене пароля будет выслана на указанный адрес."
|
||||
msgid "Password reset info"
|
||||
msgstr "Инструкция по смене пароля будет выслана на указанный почтовый адрес."
|
||||
|
||||
msgid "Not registered"
|
||||
msgstr "Ещё не зарегистрированы?"
|
||||
|
@ -43,10 +43,7 @@ msgid "Error mail"
|
|||
msgstr "При отправки письма возникла ошибка. Попробуйте позже или свяжитесь с администратором форума по адресу <a href=\"mailto:%1$s\">%1$s</a>."
|
||||
|
||||
msgid "Email flood"
|
||||
msgstr "Для этой учетной записи недавно уже запрашивали новый пароль. Пожалуйста, подождите %s минут, прежде чем повторить попытку."
|
||||
|
||||
msgid "Pass too short"
|
||||
msgstr "Пароль должен состоять минимум из 6 символов."
|
||||
msgstr "Для этой учетной записи недавно уже запрашивали сброс пароля. Пожалуйста, подождите %s минут, прежде чем повторить попытку."
|
||||
|
||||
msgid "Pass not match"
|
||||
msgstr "Пароли не совпадают."
|
||||
|
|
|
@ -79,7 +79,7 @@ msgid "Confirm new pass"
|
|||
msgstr "Ещё раз"
|
||||
|
||||
msgid "Pass info"
|
||||
msgstr "Пароль должен состоять минимум из 6 символов. Пароль чувствителен к регистру вводимых букв."
|
||||
msgstr "Пароль должен состоять минимум из 8 символов. Пароль чувствителен к регистру вводимых букв."
|
||||
|
||||
msgid "Email key bad"
|
||||
msgstr "Указанный ключ активации почтового адреса неверен или истек срок его действия. Пожалуйста, повторно запросите смену почтового адреса. Если ничего не получится, то свяжитесь с администрацией; почтовый адрес для связи"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
@extends('layouts/main')
|
||||
<section class="f-main f-login">
|
||||
<div class="f-wdiv">
|
||||
<h2>{!! __('Request pass') !!}</h2>
|
||||
<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">{!! __('Request pass info') !!}</label>
|
||||
<label class="f-child2">{!! __('Password reset info') !!}</label>
|
||||
<input class="f-btn" type="submit" name="submit" value="{!! __('Submit') !!}" tabindex="2">
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
<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=".{6,}" autofocus="autofocus" tabindex="1">
|
||||
<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=".{6,}" tabindex="2">
|
||||
<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">
|
||||
</form>
|
||||
|
|
|
@ -2083,6 +2083,8 @@ function __($data, ...$args)
|
|||
|
||||
if (empty($args)) {
|
||||
return $tr;
|
||||
} elseif (is_array($args[0])) {
|
||||
return strtr($tr, $args[0]);
|
||||
} else {
|
||||
return sprintf($tr, ...$args);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue