From 3c280cc1353a05b7fe1a58ff140e10749827ad8a Mon Sep 17 00:00:00 2001 From: Evg Date: Mon, 15 Aug 2022 14:57:23 +0300 Subject: [PATCH] =?UTF-8?q?DEV:=20=D0=9E=D0=BF=D1=82=D0=B8=D0=BC=D0=B8?= =?UTF-8?q?=D0=B7=D0=B8=D1=80=D1=83=D0=B5=D0=BC=20=D0=B7=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=81=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D0=B8=20(composer)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Controllers/Auth/RecoverController.php | 2 +- app/Controllers/SearchController.php | 10 +- .../User/InvitationsController.php | 2 +- app/Libraries/SendEmail.php | 67 +- app/Libraries/Stemmer/LinguaStem.php | 575 ++++++++++++++++++ app/Libraries/Stemmer/lib/en.php | 10 + app/Libraries/Stemmer/lib/ru.php | 16 + app/Libraries/Stemmer/lib/uk.php | 16 + composer.json | 4 +- 9 files changed, 652 insertions(+), 50 deletions(-) create mode 100644 app/Libraries/Stemmer/LinguaStem.php create mode 100644 app/Libraries/Stemmer/lib/en.php create mode 100644 app/Libraries/Stemmer/lib/ru.php create mode 100644 app/Libraries/Stemmer/lib/uk.php diff --git a/app/Controllers/Auth/RecoverController.php b/app/Controllers/Auth/RecoverController.php index eace92b2..894cfed9 100644 --- a/app/Controllers/Auth/RecoverController.php +++ b/app/Controllers/Auth/RecoverController.php @@ -53,7 +53,7 @@ class RecoverController extends Controller is_return(__('msg.account_verified'), 'error', $redirect); } - $code = $uInfo['id'] . '-' . Html::randomString('crypto', 25); + $code = $uInfo['id'] . '-' . Html::randomString('crypto', 24); UserModel::initRecover( [ 'activate_date' => date('Y-m-d H:i:s'), diff --git a/app/Controllers/SearchController.php b/app/Controllers/SearchController.php index 52ffcf6f..75f46741 100644 --- a/app/Controllers/SearchController.php +++ b/app/Controllers/SearchController.php @@ -4,8 +4,7 @@ namespace App\Controllers; use Hleb\Constructor\Handlers\Request; use App\Models\SearchModel; -use Wamania\Snowball\StemmerFactory; -use UserData, Meta; +use UserData, Meta, LinguaStem; class SearchController extends Controller { @@ -37,12 +36,11 @@ class SearchController extends Controller if ($q) { $lang = config('general.lang'); - if (!in_array($lang, ['ru', 'en', 'ro', 'fr', 'de'])) { + if (!in_array($lang, ['ru', 'en'])) { $lang = 'en'; } - - $stemmer = StemmerFactory::create($lang); - $stem = $stemmer->stem($q); + $stem = new LinguaStem($lang); + $stem = $stem->text($q); $results = SearchModel::getSearch($pageNumber, $this->limit, $stem, $type); $count = SearchModel::getSearchCount($stem, $type); diff --git a/app/Controllers/User/InvitationsController.php b/app/Controllers/User/InvitationsController.php index 242c1aeb..e271b855 100644 --- a/app/Controllers/User/InvitationsController.php +++ b/app/Controllers/User/InvitationsController.php @@ -68,7 +68,7 @@ class InvitationsController extends Controller is_return(__('msg.invate_limit_stop'), 'error', $redirect); } - $invitation_code = Html::randomString('crypto', 25); + $invitation_code = Html::randomString('crypto', 24); InvitationModel::create( [ diff --git a/app/Libraries/SendEmail.php b/app/Libraries/SendEmail.php index 132c356c..ddeabd06 100644 --- a/app/Libraries/SendEmail.php +++ b/app/Libraries/SendEmail.php @@ -2,9 +2,8 @@ use App\Models\User\{SettingModel, UserModel}; -use PHPMailer\PHPMailer\PHPMailer; -use PHPMailer\PHPMailer\SMTP; -use PHPMailer\PHPMailer\Exception; +use Phphleb\Muller\StandardMail; +use Phphleb\Muller\Src\DefaultMail; class SendEmail { @@ -58,49 +57,37 @@ class SendEmail public static function send($email, $subject = '', $message = '') { - $mail = new PHPMailer(); - if (config('integration.smtp')) { + + $mailSMTP = new SendMailSmtpClass(config('integration.smtp_user'), config('integration.smtp_pass'), 'ssl://' . config('integration.smtp_host'), config('integration.smtp_port'), "UTF-8"); + + $from = array( + config('meta.name'), // Имя отправителя + config('integration.smtp_user') // почта отправителя + ); - try { - // Server settings - // $mail->SMTPDebug = SMTP::DEBUG_SERVER; - $mail->isSMTP(); - $mail->CharSet = "utf-8"; - $mail->Host = config('integration.smtp_host'); - $mail->SMTPAuth = true; - $mail->Username = config('integration.smtp_user'); - $mail->Password = config('integration.smtp_pass'); - $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; - $mail->Port = config('integration.smtp_port'); + $result = $mailSMTP->send($email, $subject, $message, $from); - //Recipients - $mail->setFrom(config('integration.smtp_user'), config('meta.name')); - $mail->addAddress($email, ''); - - //Content - $mail->isHTML(true); - $mail->Subject = $subject; - $mail->Body = $message; - - $mail->send(); - } catch (Exception $e) { - echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}"; + if($result === true){ + echo "Done"; + }else{ + echo "Error: " . $result; } + } else { - // При включенной возможно варианты (if enabled, options are possible) - // https://github.com/PHPMailer/PHPMailer/issues/2465?ysclid=l665mmji6w128130571#issuecomment-897547946 - // $mail->isSendmail(); - $mail->CharSet = "utf-8"; - $mail->setFrom(config('general.email'), config('meta.title')); - $mail->addAddress($email, ''); - $mail->Subject = $subject; - $mail->msgHTML($message); + $mail = new \Phphleb\Muller\StandardMail(false); + $mail->setNameFrom(config('meta.name')); // вот тут было длинное + $mail->setAddressFrom(config('general.email')); - //send the message, check for errors - if (!$mail->send()) { - echo 'Mailer Error: ' . $mail->ErrorInfo; - } + $mail->setTo($email); + + $mail->setTitle($subject); + $mail->setContent($message); + + $mail->setDebug(true); + $mail->setDebugPath(HLEB_GLOBAL_DIRECTORY . DIRECTORY_SEPARATOR . 'storage/logs'); + + $mail->send(); } return true; } diff --git a/app/Libraries/Stemmer/LinguaStem.php b/app/Libraries/Stemmer/LinguaStem.php new file mode 100644 index 00000000..0170566f --- /dev/null +++ b/app/Libraries/Stemmer/LinguaStem.php @@ -0,0 +1,575 @@ + + * @link https://github.com/wdmg/lingua-stem + * @copyright Copyright (c) 2020 by W.D.M.Group, Ukraine (https://wdmg.com.ua/) + * @copyright Copyright (c) 2017 by Roman Romadin + * @copyright Copyright (c) 2005 by Richard Heyes (https://www.phpguru.org/) + * @copyright Copyright (c) 2005 by Jon Abernathy, Hostmake LLC + * @copyright Copyright (C) 2003 by Aldo Calpini + * @copyright Copyright (C) 2004 by Aleksandr Guidrevitch + * @license https://opensource.org/licenses/MIT Massachusetts Institute of Technology (MIT) License + * + * См. https://github.com/wdmg/lingua-stem + * Usage: + * + * $stem = new LinguaStem('en'); + * print $stem::word($word); + * + * or + * + * $stem = new LinguaStem('en'); + * print $stem->text($text); + * + */ + +class LinguaStem { + + /** + * @var int, Default cahce level + */ + public $caching = 0; + + /** + * @var string, Locale in ISO 639-1, like `en`, `uk` or `ru` + */ + protected $_locale; + + /** + * @var array, RegEx patterns collertion + */ + protected $_patterns; + + /** + * @var array, Words basis cache + */ + private $cache = []; + + /** + * LinguaStem constructor. + * + * @param null $locale + */ + function __construct($locale = null) { + + mb_internal_encoding('UTF-8'); + + if (!is_null($locale) && is_string($locale)) { + + // Sub-string `en-US`, `en_US` to `en` + $locale = mb_substr($locale, 0, 2); + $this->_locale = mb_strtolower($locale); + + if ($library = require __DIR__ . '/lib/' . $this->_locale . '.php') { + if (isset($library[$this->_locale])) { + $this->_patterns = $library[$this->_locale]; + } + } else { + // Exeption + } + } + } + + /** + * Performs pattern replacement + * + * @param $subject + * @param $pattern + * @param $replacement + * @param int $limit + * @return bool + */ + private function stringReplace(&$subject, $pattern, $replacement, $limit = -1) + { + $orig = $subject; + $subject = preg_replace($pattern, $replacement, $subject, $limit); + return $orig !== $subject; + } + + /** + * Performs pattern matching + * + * @param $subject + * @param $pattern + * @return bool (false)|int + */ + private function pregMatch($subject, $pattern) + { + return preg_match($pattern, $subject); + } + + /** + * Processing one words and return word basis + * + * @param $word + * @return string + */ + public function word($word) + { + $word = mb_strtolower($word); + + + if (mb_strlen($word) <= 2) + return $word; + + if ($this->_locale == 'ru') + $word = str_replace('ё', 'е', $word); + + if ($this->_locale == 'uk') + $word = str_replace('ґ', 'г', $word); + + # Check against cache of stemmed words + if ($this->caching && isset($this->_cache[$word])) { + return $this->_cache[$word]; + } + + $stem = $word; + do { + $start = null; + $end = null; + if (isset($this->_patterns['rvre'])) { + + if (!preg_match($this->_patterns['rvre'], $word, $p)) + break; + + $start = $p[1]; + $end = $p[2]; + } + + if (!$start || !$end) + break; + + // Step 1 + if ($this->_locale == 'en') { + + // Part a + if (mb_substr($end, -1) == 's') { + $this->stringReplace($end, '/sses/', 'ss') + OR $this->stringReplace($end, '/ies/', 'i') + OR $this->stringReplace($end, '/ss/', 'ss') + OR $this->stringReplace($end, '/s/', ''); + } + + // Part b + if ( + mb_substr($end, -2, 1) != 'e' + OR !$this->stringReplace($end, '/eed/', 'ee') + ) { // First rule + if (isset($this->_patterns['vowel'])) { + + // ing and ed + if ( + $this->pregMatch(mb_substr($end, 0, -3), $this->_patterns['vowel']) && + $this->stringReplace($end, '/ing/', '') + OR $this->pregMatch(mb_substr($end, 0, -2), $this->_patterns['vowel']) && + $this->stringReplace($end, '/ed/', '') + ) { // Note use of && and OR, for precedence reasons + + // If one of above two test successful + if ( + !$this->stringReplace($end, '/at/', 'ate') + AND !$this->stringReplace($end, '/bl/', 'ble') + AND !$this->stringReplace($end, '/iz/', 'ize') + ) { + + // Double consonant ending + if (isset($this->_patterns['consonant'])) { + if ( + $this->doubleConsonant($end, $this->_patterns['consonant']) + AND mb_substr($end, -2) != 'll' + AND mb_substr($end, -2) != 'ss' + AND mb_substr($end, -2) != 'zz' + ) { + $end = mb_substr($end, 0, -1); + } else if ( + $this->mCount($end, $this->_patterns['vowel'], $this->_patterns['consonant']) == 1 + AND $this->cvcSequence($end, $this->_patterns['vowel'], $this->_patterns['consonant']) + ) { + $end .= 'e'; + } + } + } + } + + // Step 1c + if ( + mb_substr($end, -1) == 'y' && + $this->pregMatch(mb_substr($end, 0, -1), $this->_patterns['vowel']) + ) { + $this->stringReplace($end, '/y/', 'i'); + } + } + } + + } else if ($this->_locale == 'ru' || $this->_locale == 'uk') { + + if (isset($this->_patterns['perfectiveground']) && isset($this->_patterns['reflexive'])) { + + if (!$this->stringReplace($end, $this->_patterns['perfectiveground'], '')) { + + $this->stringReplace($end, $this->_patterns['reflexive'], ''); + + if (isset($this->_patterns['adjective']) && isset($this->_patterns['participle'])) { + + if ($this->stringReplace($end, $this->_patterns['adjective'], '')) { + + $this->stringReplace($end, $this->_patterns['participle'], ''); + + } else { + + if (isset($this->_patterns['verb']) && isset($this->_patterns['noun'])) { + + if (!$this->stringReplace($end, $this->_patterns['verb'], '')) + $this->stringReplace($end, $this->_patterns['noun'], ''); + + } + + } + } + } + } + } + + // Step 2 + if ($this->_locale == 'en') { + switch (mb_substr($end, -2, 1)) { + + case 'a': + $this->stringReplace($end, '/ational/', 'ate') + OR $this->stringReplace($end, '/tional/', 'tion'); + break; + + case 'c': + $this->stringReplace($end, '/enci/', 'ence') + OR $this->stringReplace($end, '/anci/', 'ance'); + break; + + case 'e': + $this->stringReplace($end, '/izer/', 'ize'); + break; + + case 'g': + $this->stringReplace($end, '/logi/', 'log'); + break; + + case 'l': + $this->stringReplace($end, '/entli/', 'ent') + OR $this->stringReplace($end, '/ousli/', 'ous') + OR $this->stringReplace($end, '/alli/', 'al') + OR $this->stringReplace($end, '/bli/', 'ble') + OR $this->stringReplace($end, '/eli/', 'e'); + break; + + case 'o': + $this->stringReplace($end, '/ization/', 'ize') + OR $this->stringReplace($end, '/ation/', 'ate') + OR $this->stringReplace($end, '/ator/', 'ate'); + break; + + case 's': + $this->stringReplace($end, '/iveness/', 'ive') + OR $this->stringReplace($end, '/fulness/', 'ful') + OR $this->stringReplace($end, '/ousness/', 'ous') + OR $this->stringReplace($end, '/alism/', 'al'); + break; + + case 't': + $this->stringReplace($end, '/biliti/', 'ble') + OR $this->stringReplace($end, '/aliti/', 'al') + OR $this->stringReplace($end, '/iviti/', 'ive'); + break; + } + } else if ($this->_locale == 'ru') { + $this->stringReplace($end, '/и$/', ''); + } else if ($this->_locale == 'uk') { + $this->stringReplace($end, '/ії$/', ''); + } + + // Step 3 + if ($this->_locale == 'en') { + switch (mb_substr($end, -2, 1)) { + case 'a': + $this->stringReplace($end, '/ical/', 'ic'); + break; + + case 's': + $this->stringReplace($end, '/ness/', ''); + break; + + case 't': + $this->stringReplace($end, '/icate/', 'ic') + OR $this->stringReplace($end, '/iciti/', 'ic'); + break; + + case 'u': + $this->stringReplace($end, '/ful/', ''); + break; + + case 'v': + $this->stringReplace($end, '/ative/', ''); + break; + + case 'z': + $this->stringReplace($end, '/alize/', 'al'); + break; + } + } else if ($this->_locale == 'ru' || $this->_locale == 'uk') { + if (isset($this->_patterns['derivational'])) { + if ($this->pregMatch($end, $this->_patterns['derivational'])) { + if ($this->_locale == 'ru') + $this->stringReplace($end, '/ость?$/', ''); + if ($this->_locale == 'uk') + $this->stringReplace($end, '/ость?$/', ''); + } + } + } + + // Step 4 + if ($this->_locale == 'en') { + switch (mb_substr($end, -2, 1)) { + case 'a': + $this->stringReplace($end, '/al/', '', 1); + break; + + case 'c': + $this->stringReplace($end, '/ance/', '', 1) + OR $this->stringReplace($end, '/ence/', '', 1); + break; + + case 'e': + $this->stringReplace($end, '/er/', '', 1); + break; + + case 'i': + $this->stringReplace($end, '/ic/', '', 1); + break; + + case 'l': + $this->stringReplace($end, '/able/', '', 1) + OR $this->stringReplace($end, '/ible/', '', 1); + break; + + case 'n': + $this->stringReplace($end, '/ant/', '', 1) + OR $this->stringReplace($end, '/ement/', '', 1) + OR $this->stringReplace($end, '/ment/', '', 1) + OR $this->stringReplace($end, '/ent/', '', 1); + break; + + case 'o': + if (substr($end, -4) == 'tion' OR substr($end, -4) == 'sion') { + $this->stringReplace($end, '/ion/', '', 1); + } else { + $this->stringReplace($end, '/ou/', '', 1); + } + break; + + case 's': + $this->stringReplace($end, '/ism/', '', 1); + break; + + case 't': + $this->stringReplace($end, '/ate/', '', 1) + OR $this->stringReplace($end, '/iti/', '', 1); + break; + + case 'u': + $this->stringReplace($end, '/ous/', '', 1); + break; + + case 'v': + $this->stringReplace($end, '/ive/', '', 1); + break; + + case 'z': + $this->stringReplace($end, '/ize/', '', 1); + break; + } + } else if ($this->_locale == 'ru' || $this->_locale == 'uk') { + if (!$this->stringReplace($end, '/ь$/', '')) { + $this->stringReplace($end, '/ейше?/', ''); + $this->stringReplace($end, '/нн$/', 'н'); + } + } + + // Step 5 + if ($this->_locale == 'en') { + if (isset($this->_patterns['vowel']) && isset($this->_patterns['consonant'])) { + + // Part a + if (mb_substr($end, -1) == 'e') { + if ($this->mCount(mb_substr($end, 0, -1), $this->_patterns['vowel'], $this->_patterns['consonant']) > 1) { + $this->stringReplace($end, '/e/', ''); + } else if ($this->mCount(mb_substr($end, 0, -1)) == 1) { + if (!$this->cvcSequence(mb_substr($end, 0, -1), $this->_patterns['vowel'], $this->_patterns['consonant'])) { + $this->stringReplace($end, '/e/', ''); + } + } + } + + // Part b + if ( + $this->mCount($end, $this->_patterns['vowel'], $this->_patterns['consonant']) > 1 + AND $this->doubleConsonant($end, $this->_patterns['consonant']) + AND mb_substr($end, -1) == 'l' + ) { + $end = mb_substr($end, 0, -1); + } + + } + } + + $stem = $start . $end; + + } while (false); + + if ($this->caching) + $this->_cache[$word] = $stem; + + return $stem; + } + + /** + * Processing all words in the text, leaving spaces and other punctuation marks in place. + * + * @param $text + * @return string + */ + public function text($text) + { + $word_sep = array('?', ' ', '.', ',', ';', '!', '"', '\'', '`', "\r", "\n", "\t"); + $pos = 0; + + while($pos < mb_strlen($text)) { + + $min_new_pos = mb_strlen($text); + foreach ($word_sep as $sep) { + $new_pos_candidate = mb_strpos($text, $sep, $pos); + if ($new_pos_candidate !== false) { + $min_new_pos = ($new_pos_candidate < $min_new_pos) ? $new_pos_candidate : $min_new_pos; + } + } + + $new_pos = $min_new_pos; + $word_part = mb_substr($text, $pos, $new_pos - $pos); + + if (isset($this->_patterns['alphabet'])) + $word = preg_replace($this->_patterns['alphabet'], "", $word_part); + else + $word = preg_replace('/[^A-Za-z-]/u', "", $word_part); + + if ($word == '') { + $pos = $new_pos + 1; + } else { + $stemmed = $this->word($word); + $stemmed_part = str_ireplace($word, $stemmed, $word_part); + $text = mb_substr($text, 0, $pos) . $stemmed_part . mb_substr($text, $new_pos); + $pos = $new_pos - ((mb_strlen($word) - mb_strlen($stemmed))); + } + } + + return $text; + } + + /** + * Add words to cache + * + * '0' means 'no caching'. This is the default level. + * '1' means 'cache per run'. This caches stemming results during a single call. + * '2' means 'cache indefinitely'. This caches stemming results until either the process exits or the 'clear_cache' method is called. + * @param int $param legal value + * @return int|mixed + */ + public function addCache($param) + { + $level = @$param['-level']; + if ($level) { + if (!$this->pregMatch($level, '/^[012]$/')) { + die(__CLASS__ . "::addCache() - Legal values are '0', '1' or '2'. '$level' is not a legal value"); + } + $this->caching = $level; + } + + return $this->caching; + } + + /** + * Clearing words cache + */ + public function clearCache() + { + $this->_cache = []; + } + + /** + * Measures the number of consonant sequences in $string. + * + * gives 0 + * vc gives 1 + * vcvc gives 2 + * vcvcvc gives 3 + * + * @param null $string The string to return the m count for + * @param null $vowel regex of vowel + * @param null $consonant regex of consonant + * @return int|null the count of consonant sequences + */ + private function mCount($string = null, $vowel = null, $consonant = null) + { + if (!is_null($string) && !is_null($vowel) && !is_null($consonant)) { + $vowel = ltrim(rtrim($vowel, '+/'), '/'); + $consonant = ltrim(rtrim($consonant, '+/'), '/'); + $string = preg_replace("/^$consonant+/", '', $string); + $string = preg_replace("/$vowel+$/", '', $string); + preg_match_all("/($vowel+$consonant+)/", $string, $matches); + return count($matches[1]); + } + return null; + } + + + /** + * Returns true/false as to whether the given string contains two + * of the same consonant next to each other at the end of the string. + * + * @param null $string string to check + * @param null $consonant regex of consonant + * @return bool|null result + */ + private function doubleConsonant($string = null, $consonant = null) + { + if (!is_null($string) && !is_null($consonant)) { + $consonant = ltrim(rtrim($consonant, '+/'), '/'); + return preg_match("/$consonant[2]$/", $string, $matches) AND $matches[0][0] == $matches[0][1]; + } + return null; + } + + + /** + * Checks for ending CVC sequence where second C is not W, X or Y + * + * @param null $string string to check + * @param null $vowel regex of vowel + * @param null $consonant regex of consonant + * @return bool|null result + */ + private function cvcSequence($string = null, $vowel = null, $consonant = null) + { + if (!is_null($string) && !is_null($vowel) && !is_null($consonant)) { + + $vowel = ltrim(rtrim($vowel, '+/'), '/'); + $consonant = ltrim(rtrim($consonant, '+/'), '/'); + + return preg_match("/($consonant$vowel$consonant)$/", $string, $matches) + AND mb_strlen($matches[1]) == 3 + AND $matches[1][2] != 'w' + AND $matches[1][2] != 'x' + AND $matches[1][2] != 'y'; + } + return null; + } +} \ No newline at end of file diff --git a/app/Libraries/Stemmer/lib/en.php b/app/Libraries/Stemmer/lib/en.php new file mode 100644 index 00000000..59d8038e --- /dev/null +++ b/app/Libraries/Stemmer/lib/en.php @@ -0,0 +1,10 @@ + [ + 'vowel' => '/(?:[aeiou]|(? '/(?:[bcdfghjklmnpqrstvwxz]|(?<=[aeiou])y|^y)/', + 'rvre' => '/^(.*?[aeiou])(.*)$/', + 'alphabet' => '/[^A-Za-z\x{2010}-]/u', + ] + ]; +?> \ No newline at end of file diff --git a/app/Libraries/Stemmer/lib/ru.php b/app/Libraries/Stemmer/lib/ru.php new file mode 100644 index 00000000..2532164c --- /dev/null +++ b/app/Libraries/Stemmer/lib/ru.php @@ -0,0 +1,16 @@ + [ + 'vowel' => '/аеиоуыэюя/', + 'perfectiveground' => '/((ив|ивши|ившись|ыв|ывши|ывшись)|((?<=[ая])(в|вши|вшись)))$/', + 'reflexive' => '/(с[яь])$/', + 'adjective' => '/(ее|ие|ые|ое|ими|ыми|ей|ий|ый|ой|ем|им|ым|ом|его|ого|ему|ому|их|ых|ую|юю|ая|яя|ою|ею)$/', + 'participle' => '/((ивш|ывш|ующ)|((?<=[ая])(ем|нн|вш|ющ|щ)))$/', + 'verb' => '/((ила|ыла|ена|ейте|уйте|ите|или|ыли|ей|уй|ил|ыл|им|ым|ен|ило|ыло|ено|ят|ует|уют|ит|ыт|ены|ить|ыть|ишь|ую|ю)|((?<=[ая])(ла|на|ете|йте|ли|й|л|ем|н|ло|но|ет|ют|ны|ть|ешь|нно)))$/', + 'noun' => '/(а|ев|ов|ие|ье|е|иями|ями|ами|еи|ии|и|ией|ей|ой|ий|й|иям|ям|ием|ем|ам|ом|о|у|ах|иях|ях|ы|ь|ию|ью|ю|ия|ья|я)$/', + 'rvre' => '/^(.*?[аеиоуыэюя])(.*)$/', + 'derivational' => '/[^аеиоуыэюя][аеиоуыэюя]+[^аеиоуыэюя]+[аеиоуыэюя].*(?<=о)сть?$/', + 'alphabet' => '/[^АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя\x{2010}-]/u', + ] + ]; +?> \ No newline at end of file diff --git a/app/Libraries/Stemmer/lib/uk.php b/app/Libraries/Stemmer/lib/uk.php new file mode 100644 index 00000000..a631e8fe --- /dev/null +++ b/app/Libraries/Stemmer/lib/uk.php @@ -0,0 +1,16 @@ + [ + 'vowel' => '/аеіоуиєюяї/', + 'perfectiveground' => '/((ів|івши|івшись|ив|ивши|ившись)|((?<=[ая])(в|вши|вшись)))$/', + 'reflexive' => '/(с[яь])$/', + 'adjective' => '/(ее|іе|ие|ое|ими|іми|ої|а|е|і|у|ю|ій|ий|ой|ем|ім|им|ом|его|ого|ему|ому|іх|их|ую|юю|ая|яя|ою|ею)$/', + 'participle' => '/((івш|ивш|уюч|ьн|л)|((?<=[ая])(ем|нн|вш|ющ|щ)))$/', + 'verb' => '/((іла|ила|ена|ейте|уйте|іть|іли|или|ей|уй|іл|ил|ім|им|ен|іло|ило|ено|ять|ує|ують|іт|ит|ени|іть|ить|ую|ю)|((?<=[ая])(ла|на|ете|йте|ли|й|л|ем|н|ло|но|ет|ют|ны|ть|ешь|нно)))$/', + 'noun' => '/(а|ев|ов|іе|ье|е|іями|ями|ами|еї|ії|и|ією|ею|єю|ой|ий|й|иям|ям|ием|ем|ам|ом|о|у|ах|іях|ях|и|і|ь|ію|ью|ю|ия|ья|я)$/', + 'rvre' => '/^(.*?[аеіоуиєюяї])(.*)$/', + 'derivational' => '/[^аеіоуиєюяї][аеіоуиєюяї]+[^аеіоуиєюяї]+[аеіоуиєюяї].*(?<=і)сть?$/', + 'alphabet' => '/[^АБВГДЕ`ЖЗІЇЙКЛМНОПРСТУФХЦЧШЩ\'ИЄЬЮЯабвгдежзіїйклмнопрстуфхцчшщиєьюя\x{2010}-]/u', + ] + ]; +?> \ No newline at end of file diff --git a/composer.json b/composer.json index 6f1d9c8c..5a8e98de 100644 --- a/composer.json +++ b/composer.json @@ -31,10 +31,10 @@ "phphleb/imageresizer": "dev-master", "phphleb/debugpan": "1.*", "phphleb/radjax": "dev-master", + "phphleb/muller": "dev-main", + "ipatov/smtp-mail": "dev-master", "cocur/slugify": "^4.1", - "phpmailer/phpmailer": "^6.6.3", "erusev/parsedown": "^1.8.0@beta", - "wamania/php-stemmer": "^3.0", "donatj/phpuseragentparser": "dev-master", "utopia-php/domains": "dev-master", "geshi/geshi": "dev-master",