Issues (116)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Russian/NounPluralization.php (9 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace morphos\Russian;
3
4
use morphos\S;
5
6
/**
7
 * Rules are from http://morpher.ru/Russian/Noun.aspx
8
 */
9
class NounPluralization extends \morphos\BasePluralization implements Cases
10
{
11
    use RussianLanguage, CasesHelper;
12
13
    const ONE = 1;
14
    const TWO_FOUR = 2;
15
    const FIVE_OTHER = 3;
16
17
    /**
18
     * @var string[][]
19
     * @phpstan-var array<string, string[]>
20
     */
21
    protected static $abnormalExceptions = [
22
        'человек' => ['люди', 'человек', 'людям', 'людей', 'людьми', 'людях'],
23
    ];
24
25
    /** @var string[] */
26
    protected static $neuterExceptions = [
27
        'поле',
28
        'море',
29
    ];
30
31
    /**
32
     * @var string[]
33
     * @phpstan-var array<string, string>
34
     */
35
    protected static $genitiveExceptions = [
36
        'письмо' => 'писем',
37
        'пятно' => 'пятен',
38
        'кресло' => 'кресел',
39
        'коромысло' => 'коромысел',
40
        'ядро' => 'ядер',
41
        'блюдце' => 'блюдец',
42
        'полотенце' => 'полотенец',
43
        'гривна' => 'гривен',
44
        'год' => 'лет',
45
    ];
46
47
    /**
48
     * Склонение существительного для сочетания с числом (кол-вом предметов).
49
     *
50
     * @param string|int $word        Название предмета
51
     * @param int|float|string $count Количество предметов
52
     * @param bool       $animateness Признак одушевленности
53
     * @param string     $case        Род существительного
54
     *
55
     * @return string
56
     * @throws \Exception
57
     */
58 62
    public static function pluralize($word, $count = 2, $animateness = false, $case = null)
59
    {
60
        // меняем местами аргументы, если они переданы в старом формате
61 62 View Code Duplication
        if (is_string($count) && is_numeric($word)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
62 1
            list($count, $word) = [$word, $count];
63
        }
64
65 62
        if ($case !== null)
66 3
            $case = static::canonizeCase($case);
67
68
        // для адъективных существительных правила склонения проще:
69
        // только две формы
70 62 View Code Duplication
        if (static::isAdjectiveNoun($word)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
71 3
            if (static::getNumeralForm($count) == static::ONE)
72 2
                return $word;
73
            else
74 3
                return NounPluralization::getCase($word,
75 3
                    $case !== null
76
                        ? $case
77 3
                        : static::RODIT, $animateness);
78
        }
79
80 60
        if ($case === null) {
81 57
            switch (static::getNumeralForm($count)) {
82 57
                case static::ONE:
83 29
                    return $word;
84 57
                case static::TWO_FOUR:
85 36
                    return NounDeclension::getCase($word, static::RODIT, $animateness);
86 44
                case static::FIVE_OTHER:
87 44
                    return NounPluralization::getCase($word, static::RODIT, $animateness);
88
            }
89
        }
90
91 3 View Code Duplication
        if (static::getNumeralForm($count) == static::ONE)
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
92 3
            return NounDeclension::getCase($word, $case, $animateness);
93
        else
94 3
            return NounPluralization::getCase($word, $case, $animateness);
95
    }
96
97
    /**
98
     * @param int|float $count
99
     * @return int
100
     */
101 74
    public static function getNumeralForm($count)
102
    {
103 74
        if ($count > 100) {
104 48
            $count %= 100;
105
        }
106 74
        $ending = $count % 10;
107
108 74
        if (($count > 20 && $ending == 1) || $count == 1) {
109 38
            return static::ONE;
110 73
        } elseif (($count > 20 && in_array($ending, range(2, 4))) || in_array($count, range(2, 4))) {
111 48
            return static::TWO_FOUR;
112
        } else {
113 56
            return static::FIVE_OTHER;
114
        }
115
    }
116
117
    /**
118
     * @param string $word
119
     * @param string $case
120
     * @param bool $animateness
121
     * @return string
122
     * @throws \Exception
123
     */
124 49
    public static function getCase($word, $case, $animateness = false)
125
    {
126 49
        $case = static::canonizeCase($case);
127 49
        $forms = static::getCases($word, $animateness);
128 49
        return $forms[$case];
129
    }
130
131
    /**
132
     * @param string $word
133
     * @param bool $animateness
134
     * @return string[]
135
     * @phpstan-return array<string, string>
136
     */
137 97
    public static function getCases($word, $animateness = false)
138
    {
139 97
        $word = S::lower($word);
140
141 97 View Code Duplication
        if (in_array($word, NounDeclension::$immutableWords, true)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
142
            return [
143 1
                static::IMENIT => $word,
144 1
                static::RODIT => $word,
145 1
                static::DAT => $word,
146 1
                static::VINIT => $word,
147 1
                static::TVORIT => $word,
148 1
                static::PREDLOJ => $word,
149
            ];
150
        }
151
152 97 View Code Duplication
        if (isset(static::$abnormalExceptions[$word])) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
153 1
            return array_combine(
154 1
                [static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ],
155 1
                static::$abnormalExceptions[$word]);
156
        }
157
158
        // Адъективное склонение (Сущ, образованные от прилагательных и причастий)
159
        // Пример: прохожий, существительное
160 96
        if (static::isAdjectiveNoun($word)) {
161 11
            return static::declinateAdjective($word, $animateness);
162
        }
163
164
        // Субстантивное склонение (существительные)
165 86
        return static::declinateSubstative($word, $animateness);
166
    }
167
168
    /**
169
     * Склонение обычных существительных.
170
     * @param string $word
171
     * @param bool $animateness
172
     * @return string[]
173
     * @phpstan-return array<string, string>
174
     */
175 86
    protected static function declinateSubstative($word, $animateness)
176
    {
177 86
        $prefix = S::slice($word, 0, -1);
178 86
        $last = S::slice($word, -1);
179
180 86
        if (($declension = NounDeclension::getDeclension($word)) == NounDeclension::SECOND_DECLENSION) {
181 56
            $soft_last = $last == 'й' || (in_array($last, ['ь', 'е', 'ё', 'ю', 'я'], true)
182
                    && ((
183 21
                        static::isConsonant(S::slice($word, -2, -1)) && !static::isHissingConsonant(S::slice($word, -2, -1)))
184 56
                        || S::slice($word, -2, -1) == 'и'));
185 56
            $prefix = NounDeclension::getPrefixOfSecondDeclension($word, $last);
186 42
        } elseif ($declension == NounDeclension::FIRST_DECLENSION) {
187 37
            $soft_last = static::checkLastConsonantSoftness($word);
188
        } else {
189 5
            $soft_last = in_array(S::slice($word, -2), ['чь', 'сь', 'ть', 'нь', 'дь'], true);
190
        }
191
192 86
        $forms = [];
193
194 86
        if (in_array($last, ['ч', 'г'], true)
195 84
            || in_array(S::slice($word, -2), ['чь', 'сь', 'ть', 'нь', 'рь', 'дь', 'ль'], true)
196 86
            || (static::isVowel($last) && in_array(S::slice($word, -2, -1), ['ч', 'к'], true))) { // before ч, чь, сь, ч+vowel, к+vowel
197 44
            $forms[Cases::IMENIT] = $prefix.'и';
198 48
        } elseif (in_array($last, ['н', 'ц', 'р', 'т'], true)) {
199 19
            $forms[Cases::IMENIT] = $prefix.'ы';
200 View Code Duplication
        } else {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
201 33
            $forms[Cases::IMENIT] = static::chooseVowelAfterConsonant($last, $soft_last, $prefix.'я', $prefix.'а');
202
        }
203
204
        // RODIT
205 86
        if (isset(static::$genitiveExceptions[$word])) {
206 10
            $forms[Cases::RODIT] = static::$genitiveExceptions[$word];
207 78
        } elseif (in_array($last, ['о', 'е'], true)) {
208
            // exceptions
209 8
            if (in_array($word, static::$neuterExceptions, true)) {
210 3
                $forms[Cases::RODIT] = $prefix.'ей';
211 5 View Code Duplication
            } elseif (S::slice($word, -2, -1) == 'и') {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
212 2
                $forms[Cases::RODIT] = $prefix.'й';
213
            } else {
214 8
                $forms[Cases::RODIT] = $prefix;
215
            }
216 70
        } elseif (S::slice($word, -2) == 'ка' && S::slice($word, -3, -2) !== 'и') { // words ending with -ка: чашка, вилка, ложка, тарелка, копейка, батарейка, аптека
217 13
            if (S::slice($word, -3, -2) == 'л') {
218 2
                $forms[Cases::RODIT] = S::slice($word, 0, -2).'ок';
219 11
            } elseif (in_array(S::slice($word, -3, -2), ['й', 'е'], true)) {
220 9
                $forms[Cases::RODIT] = S::slice($word, 0, -3).'ек';
221
            } else {
222 13
                $forms[Cases::RODIT] = S::slice($word, 0, -2).'ек';
223
            }
224 63
        } elseif (in_array($last, ['а'], true)) { // обида, ябеда
225 23
            $forms[Cases::RODIT] = $prefix;
226 47 View Code Duplication
        } elseif (in_array($last, ['я'], true)) { // молния
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
227 1
            $forms[Cases::RODIT] = $prefix.'й';
228 46
        } elseif (RussianLanguage::isHissingConsonant($last) || ($soft_last && $last != 'й') || in_array(S::slice($word, -2), ['чь', 'сь', 'ть', 'нь', 'дь'], true)) {
229 22
            $forms[Cases::RODIT] = $prefix.'ей';
230 27 View Code Duplication
        } elseif ($last == 'й' || S::slice($word, -2) == 'яц') { // месяц
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
231 7
            $forms[Cases::RODIT] = $prefix.'ев';
232
        } else { // (static::isConsonant($last) && !RussianLanguage::isHissingConsonant($last))
233 20
            $forms[Cases::RODIT] = $prefix.'ов';
234
        }
235
236
        // DAT
237 86
        $forms[Cases::DAT] = static::chooseVowelAfterConsonant($last, $soft_last && S::slice($word, -2, -1) != 'ч', $prefix.'ям', $prefix.'ам');
238
239
        // VINIT
240 86
        $forms[Cases::VINIT] = NounDeclension::getVinitCaseByAnimateness($forms, $animateness);
241
242
        // TVORIT
243
        // my personal rule
244 86
        if ($last == 'ь' && $declension == NounDeclension::THIRD_DECLENSION && !in_array(S::slice($word, -2), ['чь', 'сь', 'ть', 'нь', 'дь'], true)) {
245
            $forms[Cases::TVORIT] = $prefix.'ми';
246
        } else {
247 86
            $forms[Cases::TVORIT] = static::chooseVowelAfterConsonant($last, $soft_last && S::slice($word, -2, -1) != 'ч', $prefix.'ями', $prefix.'ами');
248
        }
249
250
        // PREDLOJ
251 86
        $forms[Cases::PREDLOJ] = static::chooseVowelAfterConsonant($last, $soft_last && S::slice($word, -2, -1) != 'ч', $prefix.'ях', $prefix.'ах');
252 86
        return $forms;
253
    }
254
255
    /**
256
     * Склонение существительных, образованных от прилагательных и причастий.
257
     * Rules are from http://rusgram.narod.ru/1216-1231.html
258
     * @param string $word
259
     * @param bool $animateness
260
     * @return string[]
261
     * @phpstan-return array<string, string>
262
     */
263 11
    protected static function declinateAdjective($word, $animateness)
264
    {
265 11
        $prefix = S::slice($word, 0, -2);
266 11
        $vowel = static::isHissingConsonant(S::slice($prefix, -1)) ? 'и' : 'ы';
267
        return [
268 11
            Cases::IMENIT => $prefix.$vowel.'е',
269 11
            Cases::RODIT => $prefix.$vowel.'х',
270 11
            Cases::DAT => $prefix.$vowel.'м',
271 11
            Cases::VINIT => $prefix.$vowel.($animateness ? 'х' : 'е'),
272 11
            Cases::TVORIT => $prefix.$vowel.'ми',
273 11
            Cases::PREDLOJ => $prefix.$vowel.'х',
274
        ];
275
    }
276
}
277