2017-12-07

This commit is contained in:
Visman 2017-12-07 19:21:51 +07:00
parent 375a014e20
commit c49db50c23
10 changed files with 215 additions and 104 deletions

View file

@ -92,21 +92,34 @@ class Mail
public function valid($email, $strict = false, $idna = false)
{
if (! is_string($email)
|| mb_strlen($email, 'UTF-8') > 80
|| ! preg_match('%^([a-z0-9_!#$\%&\'*+-/=?^`{|}~]+(?:\.[a-z0-9_!#$\%&\'*+-/=?^`{|}~]+)*)@([^\x00-\x20]+)$%Di', $email, $matches)
|| mb_strlen($email, 'UTF-8') > 80 //?????
|| ! preg_match('%^([^\x00-\x1F\\\/\s@]+)@([^\x00-\x1F\s@]+)$%Du', $email, $matches)
) {
return false;
}
$local = $matches[1];
$domain = mb_strtolower($matches[2], 'UTF-8');
if (! preg_match('%^(?:[\p{L}\p{N}]+(?:\-[\p{L}\p{N}]+)*\.)*\p{L}+$%u', $domain)) {
return false;
if ($domain{0} === '[' && substr($domain, -1) === ']') {
$ip = substr($domain, 1, -1);
if (! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
return $false;
}
$domainASCII = $domain;
} else {
$ip = null;
if (! preg_match('%^(?:[\p{L}\p{N}]+(?:\-[\p{L}\p{N}]+)*\.)*\p{L}+$%u', $domain)) {
return false;
}
$domainASCII = idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46);
}
$domainASCII = idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46);
if ($strict) {
$mx = @dns_get_record($domainASCII, DNS_MX); //????
if ($ip) {
$mx = @checkdnsrr($ip, 'MX');
} else {
$mx = @dns_get_record($domainASCII, DNS_MX);
}
if (empty($mx)) {
return false;
}

View file

@ -3,6 +3,7 @@
namespace ForkBB\Core;
use Parserus;
use ForkBB\Core\Container;
class Parser extends Parserus
{
@ -65,4 +66,92 @@ class Parser extends Parserus
}
return parent::addBBCode($bb);
}
/**
* Проверяет разметку сообщения с бб-кодами
* Пытается исправить неточности разметки
* Генерирует ошибки разметки
*
* @param string $text
* @param bool $isSignature
*
* @return string
*/
public function prepare($text, $isSignature = false)
{
if ($isSignature) {
$whiteList = $this->c->config->p_sig_bbcode == '1' ? $this->c->BBCODE_INFO['forSign'] : [];
$blackList = $this->c->config->p_sig_img_tag == '1' ? [] : ['img'];
} else {
$whiteList = $this->c->config->p_message_bbcode == '1' ? null : [];
$blackList = $this->c->config->p_message_img_tag == '1' ? [] : ['img'];
}
$this->setAttr('isSign', $isSignature)
->setWhiteList($whiteList)
->setBlackList($blackList)
->parse($text, ['strict' => true])
->stripEmptyTags(" \n\t\r\v", true);
if ($this->c->config->o_make_links == '1') {
$this->detectUrls();
}
return preg_replace('%^(\x20*\n)+|(\n\x20*)+$%D', '', $this->getCode());
}
/**
* Преобразует бб-коды в html в сообщениях
*
* @param null|string $text
* @param bool $hideSmilies
*
* @return string
*/
public function parseMessage($text = null, $hideSmilies = false)
{
// при null предполагается брать данные после prepare()
if (null !== $text) {
$whiteList = $this->c->config->p_message_bbcode == '1' ? null : [];
$blackList = $this->c->config->p_message_img_tag == '1' ? [] : ['img'];
$this->setAttr('isSign', false)
->setWhiteList($whiteList)
->setBlackList($blackList)
->parse($text);
}
if (! $hideSmilies && $this->c->config->o_smilies == '1') {
$this->detectSmilies();
}
return $this->getHtml();
}
/**
* Преобразует бб-коды в html в подписях пользователей
*
* @param null|string $text
*
* @return string
*/
public function parseSignature($text = null)
{
// при null предполагается брать данные после prepare()
if (null !== $text) {
$whiteList = $this->c->config->p_sig_bbcode == '1' ? $this->c->BBCODE_INFO['forSign'] : [];
$blackList = $this->c->config->p_sig_img_tag == '1' ? [] : ['img'];
$this->setAttr('isSign', true)
->setWhiteList($whiteList)
->setBlackList($blackList)
->parse($text);
}
if ($this->c->config->o_smilies_sig == '1') {
$this->detectSmilies();
}
return $this->getHtml();
}
}

View file

@ -2,6 +2,8 @@
namespace ForkBB\Core;
use InvalidArgumentException;
class Router
{
const OK = 200;
@ -103,40 +105,43 @@ class Router
public function link($marker = null, array $args = [])
{
$result = $this->baseUrl;
if (is_string($marker) && isset($this->links[$marker])) {
$s = $this->links[$marker];
foreach ($args as $key => $val) {
if ($key == '#') {
$s .= '#' . rawurlencode($val);
continue;
} elseif ($key == 'page' && $val === 1) {
$anchor = isset($args['#']) ? '#' . rawurlencode($args['#']) : '';
// маркер пустой
if (null === $marker) {
return $result . "/{$anchor}";
// такой ссылки нет
} elseif (! isset($this->links[$marker])) {
return $result . '/';
// ссылка статична
} elseif (is_string($data = $this->links[$marker])) {
return $result . $data . $anchor;
}
list($link, $names, $request) = $data;
$data = [];
// перечисление имен переменных для построения ссылки
foreach ($names as $name) {
// значение есть
if (isset($args[$name])) {
// кроме page = 1
if ($name != 'page' || $args[$name] !== 1) {
$data['{' . $name . '}'] = rawurlencode(preg_replace('%[\s\\\/]+%u', '-', $args[$name]));
continue;
}
$s = preg_replace_callback( //????
'%\{' . preg_quote($key, '%') . '(?::[^{}]+)?\}%',
function($match) use ($val) {
if (is_string($val)) {
$val = trim(preg_replace('%[^\p{L}\p{N}_]+%u', '-', $val), '_-');
} elseif (is_numeric($val)) { //????
$val = (string) $val;
} else {
$val = null;
}
return isset($val[0]) ? rawurlencode($val) : '-';
},
$s
);
}
$s = preg_replace('%\[[^{}\[\]]*\{[^}]+\}[^{}\[\]]*\]%', '', $s);
if (strpos($s, '{') === false) {
$result .= str_replace(['[', ']'], '', $s);
// значения нет, но оно обязательно
if ($request[$name]) {
return $result . '/';
// значение не обязательно
} else {
$result .= '/';
$link = preg_replace('%\[[^\[\]{}]*{' . preg_quote($name, '%') . '}[^\[\]{}]*\]%', '', $link);
}
} else {
$result .= '/';
}
return $result;
$link = str_replace(['[', ']'], '', $link);
return $result . strtr($link, $data) . $anchor;
}
/**
@ -227,12 +232,15 @@ class Router
$this->methods[$method] = 1;
}
$link = $route;
if (($pos = strpos($route, '#')) !== false) {
$route = substr($route, 0, $pos);
$link = $route;
$anchor = '';
if (false !== strpos($route, '#')) {
list($route, $anchor) = explode('#', $route, 2);
$anchor = '#' . $anchor;
}
if (false === strpbrk($route, '{}[]')) {
$data = null;
if (is_array($method)) {
foreach ($method as $m) {
$this->statical[$route][$m] = $handler;
@ -255,7 +263,11 @@ class Router
}
if ($marker) {
$this->links[$marker] = $link;
if ($data) {
$this->links[$marker] = [$data[3] . $anchor, $data[2], $data[4]];
} else {
$this->links[$marker] = $link;
}
}
}
@ -281,11 +293,14 @@ class Router
}
$pattern = '%^';
$var = false;
$first = false;
$buffer = '';
$args = [];
$s = 0;
$var = false;
$first = false;
$buffer = '';
$args = [];
$s = 0;
$req = true;
$argReq = [];
$temp = '';
foreach ($parts as $part) {
if ($var) {
@ -301,9 +316,11 @@ class Router
return false;
}
$pattern .= '(?P<' . $data[0] . '>' . $data[1] . ')';
$args[] = $data[0];
$var = false;
$buffer = '';
$args[] = $data[0];
$temp .= '{' . $data[0] . '}';
$var = false;
$buffer = '';
$argsReq[$data[0]] = $req;
break;
default:
$buffer .= $part;
@ -311,8 +328,9 @@ class Router
} elseif ($first) {
switch ($part) {
case '/':
$first = false;
$first = false;
$pattern .= preg_quote($part, '%');
$temp .= $part;
break;
default:
return false;
@ -322,7 +340,9 @@ class Router
case '[':
++$s;
$pattern .= '(?:';
$first = true;
$first = true;
$req = false;
$temp .= '[';
break;
case ']':
--$s;
@ -330,6 +350,8 @@ class Router
return false;
}
$pattern .= ')?';
$req = true;
$temp .= ']';
break;
case '{':
$var = true;
@ -338,6 +360,7 @@ class Router
return false;
default:
$pattern .= preg_quote($part, '%');
$temp .= $part;
}
}
}
@ -345,6 +368,6 @@ class Router
return false;
}
$pattern .= '$%D';
return [$base, $pattern, $args];
return [$base, $pattern, $args, $temp, $argsReq];
}
}

View file

@ -145,7 +145,7 @@ class Auth extends Page
$user->update();
$this->c->Online->delete($this->c->user);
$this->c->Cookie->setUser($user);
$this->c->Cookie->setUser($user, (bool) $v->save);
}
}
return $password;

View file

@ -67,7 +67,7 @@ class Post extends Page
$args['_vars'] = $v->getData();
if (null !== $v->preview && ! $v->getErrors()) {
$this->previewHtml = $this->c->Parser->getHtml();
$this->previewHtml = $this->c->Parser->parseMessage(null, (bool) $v->hide_smilies);
}
return $this->newTopic($args, $forum);
@ -105,7 +105,7 @@ class Post extends Page
$this->nameTpl = 'post';
$this->onlinePos = 'topic-' . $topic->id;
$this->canonical = $this->c->Router->link('NewReply', $args);
$this->canonical = $this->c->Router->link('NewReply', ['id' => $topic->id]);
$this->robots = 'noindex';
$this->crumbs = $this->crumbs(__('Post a reply'), $topic);
$this->form = $this->messageForm($topic, 'NewReply', $args);
@ -142,7 +142,7 @@ class Post extends Page
$args['_vars'] = $v->getData();
if (null !== $v->preview && ! $v->getErrors()) {
$this->previewHtml = $this->c->Parser->getHtml();
$this->previewHtml = $this->c->Parser->parseMessage(null, (bool) $v->hide_smilies);
}
return $this->newReply($args, $topic);
@ -206,9 +206,10 @@ class Post extends Page
// попытка объеденить новое сообщение с крайним в теме
if ($merge) {
$lastPost = $this->c->ModelPost->load($topic->last_post_id);
$lastPost = $this->c->ModelPost->load($topic->last_post_id);
$newLength = mb_strlen($lastPost->message . $v->message, 'UTF-8');
if ($this->c->MAX_POST_SIZE > mb_strlen($lastPost->message . $v->message, 'UTF-8') + 100) { //????
if ($newLength < $this->c->MAX_POST_SIZE - 100) {
$lastPost->message = $lastPost->message . "\n[after=" . ($now - $topic->last_post) . "]\n" . $v->message; //????
$lastPost->posted = $lastPost->posted + 1; //???? прибаляем 1 секунду для появления в новых //????
@ -339,7 +340,7 @@ class Post extends Page
* @param Validator $v
* @param string $message
*
* @return array
* @return string
*/
public function vCheckMessage(Validator $v, $message, $attr, $executive)
{
@ -355,23 +356,7 @@ class Post extends Page
$v->addError('All caps message');
// проверка парсером
} else {
$bbWList = $this->c->config->p_message_bbcode == '1' ? null : [];
$bbBList = $this->c->config->p_message_img_tag == '1' ? [] : ['img'];
$this->c->Parser->setAttr('isSign', false)
->setWhiteList($bbWList)
->setBlackList($bbBList)
->parse($message, ['strict' => true])
->stripEmptyTags(" \n\t\r\v", true);
if ($this->c->config->o_make_links == '1') {
$this->c->Parser->detectUrls();
}
if ($v->hide_smilies != '1' && $this->c->config->o_smilies == '1') {
$this->c->Parser->detectSmilies();
}
$message = $this->c->Parser->prepare($message); //????
foreach($this->c->Parser->getErrors() as $error) {
$v->addError($error);
@ -381,6 +366,30 @@ class Post extends Page
return $message;
}
/**
* Проверка времени ограничения флуда
*
* @param Validator $v
* @param null|string $submit
*
* @return null|string
*/
public function vCheckTimeout(Validator $v, $submit)
{
if (null === $submit) {
return null;
}
$user = $this->c->user;
$time = time() - (int) $user->last_post;
if ($time < $user->g_post_flood) {
$v->addError(__('Flood start', $user->g_post_flood, $user->g_post_flood - $time), 'e');
}
return $submit;
}
/**
* Подготовка валидатора к проверке данных из формы создания темы/сообщения
*
@ -436,6 +445,7 @@ class Post extends Page
'check_username' => [$this, 'vCheckUsername'],
'check_subject' => [$this, 'vCheckSubject'],
'check_message' => [$this, 'vCheckMessage'],
'check_timeout' => [$this, 'vCheckTimeout'],
])->setRules([
'token' => 'token:' . $marker,
'email' => [$ruleEmail, __('Email')],
@ -445,8 +455,8 @@ class Post extends Page
'stick_fp' => $ruleStickFP,
'merge_post' => $ruleMergePost,
'hide_smilies' => $ruleHideSmilies,
'submit' => 'string', //????
'preview' => 'string', //????
'submit' => 'string|check_timeout', //????
'message' => 'required|string:trim|max:' . $this->c->MAX_POST_SIZE . '|check_message',
])->setArguments([
'token' => $args,

View file

@ -115,18 +115,6 @@ class Post extends DataModel
*/
public function html()
{
$bbWList = $this->c->config->p_message_bbcode == '1' ? null : [];
$bbBList = $this->c->config->p_message_img_tag == '1' ? [] : ['img'];
$parser = $this->c->Parser->setAttr('isSign', false)
->setWhiteList($bbWList)
->setBlackList($bbBList)
->parse($this->cens()->message);
if ($this->hide_smilies != '1' && $this->c->config->o_smilies == '1') {
$parser->detectSmilies();
}
return $parser->getHtml();
return $this->c->Parser->parseMessage($this->cens()->message, (bool) $this->hide_smilies); //????
}
}

View file

@ -199,18 +199,6 @@ class User extends DataModel
*/
protected function gethtmlSign()
{
$bbWList = $this->c->config->p_sig_bbcode == '1' ? $this->c->BBCODE_INFO['forSign'] : [];
$bbBList = $this->c->config->p_sig_img_tag == '1' ? [] : ['img'];
$parser = $this->c->Parser->setAttr('isSign', true)
->setWhiteList($bbWList)
->setBlackList($bbBList)
->parse($this->cens()->signature);
if ($this->c->config->o_smilies_sig == '1') {
$parser->detectSmilies();
}
return $parser->getHtml();
return $this->c->Parser->parseSignature($this->cens()->signature); //????
}
}

View file

@ -73,7 +73,7 @@ msgid "Topic review"
msgstr "Topic review (newest first)"
msgid "Flood start"
msgstr "At least %s seconds have to pass between posts. Please wait %s seconds and try posting again."
msgstr "At least %1$s seconds have to pass between posts. Please wait %2$s seconds and try posting again."
msgid "Preview"
msgstr "Preview"

View file

@ -73,7 +73,7 @@ msgid "Topic review"
msgstr "Обзор темы (новое вверху)"
msgid "Flood start"
msgstr "Хотя бы %s секунд должно пройти между отправкой сообщений. Пожалуйста, подождите %s секунд и попробуйте снова."
msgstr "Хотя бы %1$s секунд должно пройти между отправкой сообщений. Пожалуйста, подождите %2$s секунд и попробуйте снова."
msgid "Preview"
msgstr "Предпросмотр"

View file

@ -20,7 +20,7 @@
<h2>{!! __('Post preview') !!}</h2>
<div class="f-post-body clearfix">
<div class="f-post-right f-post-main">
{!! $p->previewHtml !!}
{!! $p->cens()->previewHtml !!}
</div>
</div>
</section>