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/CardinalNumeralGenerator.php (3 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\NumeralGenerator;
5
use morphos\S;
6
use RuntimeException;
7
8
/**
9
 * Rules are from http://www.fio.ru/pravila/grammatika/sklonenie-imen-chislitelnykh/
10
 */
11
class CardinalNumeralGenerator extends NumeralGenerator implements Cases
12
{
13
    use RussianLanguage, CasesHelper;
14
15
    /**
16
     * @var string[]
17
     * @phpstan-var array<int, string>
18
     */
19
    protected static $words = [
20
        1 => 'один',
21
        2 => 'два',
22
        3 => 'три',
23
        4 => 'четыре',
24
        5 => 'пять',
25
        6 => 'шесть',
26
        7 => 'семь',
27
        8 => 'восемь',
28
        9 => 'девять',
29
        10 => 'десять',
30
        11 => 'одиннадцать',
31
        12 => 'двенадцать',
32
        13 => 'тринадцать',
33
        14 => 'четырнадцать',
34
        15 => 'пятнадцать',
35
        16 => 'шестнадцать',
36
        17 => 'семнадцать',
37
        18 => 'восемнадцать',
38
        19 => 'девятнадцать',
39
        20 => 'двадцать',
40
        30 => 'тридцать',
41
        40 => 'сорок',
42
        50 => 'пятьдесят',
43
        60 => 'шестьдесят',
44
        70 => 'семьдесят',
45
        80 => 'восемьдесят',
46
        90 => 'девяносто',
47
        100 => 'сто',
48
        200 => 'двести',
49
        300 => 'триста',
50
        400 => 'четыреста',
51
        500 => 'пятьсот',
52
        600 => 'шестьсот',
53
        700 => 'семьсот',
54
        800 => 'восемьсот',
55
        900 => 'девятьсот',
56
    ];
57
58
    /**
59
     * @var string[]
60
     * @phpstan-var array<int, string>
61
     */
62
    protected static $exponents = [
63
        1000 => 'тысяча',
64
        1000000 => 'миллион',
65
        1000000000 => 'миллиард',
66
        1000000000000 => 'триллион',
67
        1000000000000000 => 'квадриллион',
68
    ];
69
70
    /**
71
     * @var array
72
     * @phpstan-var array<string, array<string, array<string, string>|string>>
73
     */
74
    protected static $precalculated = [
75
        'один' => [
76
            self::MALE => [
77
                self::IMENIT => 'один',
78
                self::RODIT => 'одного',
79
                self::DAT => 'одному',
80
                self::VINIT => 'один',
81
                self::TVORIT => 'одним',
82
                self::PREDLOJ => 'одном',
83
            ],
84
            self::FEMALE => [
85
                self::IMENIT => 'одна',
86
                self::RODIT => 'одной',
87
                self::DAT => 'одной',
88
                self::VINIT => 'одну',
89
                self::TVORIT => 'одной',
90
                self::PREDLOJ => 'одной',
91
            ],
92
            self::NEUTER => [
93
                self::IMENIT => 'одно',
94
                self::RODIT => 'одного',
95
                self::DAT => 'одному',
96
                self::VINIT => 'одно',
97
                self::TVORIT => 'одним',
98
                self::PREDLOJ => 'одном',
99
            ],
100
        ],
101
        'два' => [
102
            self::MALE => [
103
                self::IMENIT => 'два',
104
                self::RODIT => 'двух',
105
                self::DAT => 'двум',
106
                self::VINIT => 'два',
107
                self::TVORIT => 'двумя',
108
                self::PREDLOJ => 'двух',
109
            ],
110
            self::FEMALE => [
111
                self::IMENIT => 'две',
112
                self::RODIT => 'двух',
113
                self::DAT => 'двум',
114
                self::VINIT => 'две',
115
                self::TVORIT => 'двумя',
116
                self::PREDLOJ => 'двух',
117
            ],
118
            self::NEUTER => [
119
                self::IMENIT => 'два',
120
                self::RODIT => 'двух',
121
                self::DAT => 'двум',
122
                self::VINIT => 'два',
123
                self::TVORIT => 'двумя',
124
                self::PREDLOJ => 'двух',
125
            ],
126
        ],
127
        'три' => [
128
            self::IMENIT => 'три',
129
            self::RODIT => 'трех',
130
            self::DAT => 'трем',
131
            self::VINIT => 'три',
132
            self::TVORIT => 'тремя',
133
            self::PREDLOJ => 'трех',
134
        ],
135
        'четыре' => [
136
            self::IMENIT => 'четыре',
137
            self::RODIT => 'четырех',
138
            self::DAT => 'четырем',
139
            self::VINIT => 'четыре',
140
            self::TVORIT => 'четырьмя',
141
            self::PREDLOJ => 'четырех',
142
        ],
143
        'двести' => [
144
            self::IMENIT => 'двести',
145
            self::RODIT => 'двухсот',
146
            self::DAT => 'двумстам',
147
            self::VINIT => 'двести',
148
            self::TVORIT => 'двумястами',
149
            self::PREDLOJ => 'двухстах',
150
        ],
151
        'восемьсот' => [
152
            self::IMENIT => 'восемьсот',
153
            self::RODIT => 'восьмисот',
154
            self::DAT => 'восьмистам',
155
            self::VINIT => 'восемьсот',
156
            self::TVORIT => 'восьмистами',
157
            self::PREDLOJ => 'восьмистах',
158
        ],
159
        'тысяча' => [
160
            self::IMENIT => 'тысяча',
161
            self::RODIT => 'тысяч',
162
            self::DAT => 'тысячам',
163
            self::VINIT => 'тысяч',
164
            self::TVORIT => 'тысячей',
165
            self::PREDLOJ => 'тысячах',
166
        ],
167
    ];
168
169
    /**
170
     * @param int $number
171
     * @param string $gender
172
     * @return string[]
173
     * @phpstan-return array<string, string>
174
     * @throws \Exception
175
     */
176 33
    public static function getCases($number, $gender = self::MALE)
177
    {
178
        // simple numeral
179 33
        if (isset(static::$words[$number]) || isset(static::$exponents[$number])) {
180 33
            $word = isset(static::$words[$number]) ? static::$words[$number] : static::$exponents[$number];
181 33
            if (isset(static::$precalculated[$word])) {
182 21
                if (isset(static::$precalculated[$word][static::MALE])) {
183 10
                    return static::$precalculated[$word][$gender];
184
                } else {
185 18
                    return static::$precalculated[$word];
186
                }
187 24
            } elseif (($number >= 5 && $number <= 20) || $number == 30) {
188 14
                $prefix = S::slice($word, 0, -1);
189
                return [
190 14
                    static::IMENIT => $word,
191 14
                    static::RODIT => $prefix.'и',
192 14
                    static::DAT => $prefix.'и',
193 14
                    static::VINIT => $word,
194 14
                    static::TVORIT => $prefix.'ью',
195 14
                    static::PREDLOJ => $prefix.'и',
196
                ];
197 21
            } elseif (in_array($number, [40, 90, 100])) {
198 11
                $prefix = $number == 40 ? $word : S::slice($word, 0, -1);
199
                return [
200 11
                    static::IMENIT => $word,
201 11
                    static::RODIT => $prefix.'а',
202 11
                    static::DAT => $prefix.'а',
203 11
                    static::VINIT => $word,
204 11
                    static::TVORIT => $prefix.'а',
205 11
                    static::PREDLOJ => $prefix.'а',
206
                ];
207 18
            } elseif (($number >= 50 && $number <= 80)) {
208 10
                $prefix = S::slice($word, 0, -6);
209
                return [
210 10
                    static::IMENIT => $prefix.'ьдесят',
211 10
                    static::RODIT => $prefix.'идесяти',
212 10
                    static::DAT => $prefix.'идесяти',
213 10
                    static::VINIT => $prefix.'ьдесят',
214 10
                    static::TVORIT => $prefix.'ьюдесятью',
215 10
                    static::PREDLOJ => $prefix.'идесяти',
216
                ];
217 18
            } elseif (in_array($number, [300, 400])) {
218 6
                $prefix = S::slice($word, 0, -4);
219
                return [
220 6
                    static::IMENIT => $word,
221 6
                    static::RODIT => $prefix.'ехсот',
222 6
                    static::DAT => $prefix.'емстам',
223 6
                    static::VINIT => $word,
224 6
                    static::TVORIT => $prefix.($number == 300 ? 'е' : 'ь').'мястами',
225 6
                    static::PREDLOJ => $prefix.'ехстах',
226
                ];
227 12
            } elseif ($number >= 500 && $number <= 900) {
228 10
                $prefix = S::slice($word, 0, -4);
229
                return [
230 10
                    static::IMENIT => $word,
231 10
                    static::RODIT => $prefix.'исот',
232 10
                    static::DAT => $prefix.'истам',
233 10
                    static::VINIT => $word,
234 10
                    static::TVORIT => $prefix.'ьюстами',
235 10
                    static::PREDLOJ => $prefix.'истах',
236
                ];
237 2
            } elseif (isset(static::$exponents[$number])) {
238 2
                return NounDeclension::getCases($word, false);
239
            }
240
241
            throw new RuntimeException('Unreachable');
242
        }
243
244 21
        if ($number == 0) {
245
            return [
246
                static::IMENIT => 'ноль',
247
                static::RODIT => 'ноля',
248
                static::DAT => 'нолю',
249
                static::VINIT => 'ноль',
250
                static::TVORIT => 'нолём',
251
                static::PREDLOJ => 'ноле',
252
            ];
253
        } // compound numeral
254
255 21
        $parts = [];
256 21
        $result = [];
257
258 21
        foreach (array_reverse(static::$exponents, true) as $word_number => $word) {
259 21
            if ($number >= $word_number) {
260 13
                $count = (int)floor($number / $word_number);
261 13
                $parts[] = static::getCases($count, ($word_number == 1000 ? static::FEMALE : static::MALE));
262
263 13
                switch (NounPluralization::getNumeralForm($count)) {
264 13
                    case NounPluralization::ONE:
265 4
                        $parts[] = NounDeclension::getCases($word, false);
266 4
                        break;
267
268 12 View Code Duplication
                    case NounPluralization::TWO_FOUR:
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...
269 7
                        $part = NounPluralization::getCases($word);
270 7
                        if ($word_number != 1000) { // get dative case of word for 1000000, 1000000000 and 1000000000000
271 4
                            $part[Cases::IMENIT] = $part[Cases::VINIT] = NounDeclension::getCase($word, Cases::RODIT);
272
                        }
273 7
                        $parts[] = $part;
274 7
                        break;
275
276 9 View Code Duplication
                    case NounPluralization::FIVE_OTHER:
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...
277 9
                        $part = NounPluralization::getCases($word);
278 9
                        $part[Cases::IMENIT] = $part[Cases::VINIT] = $part[Cases::RODIT];
279 9
                        $parts[] = $part;
280 9
                        break;
281
                }
282
283 21
                $number = $number % ($count * $word_number);
284
            }
285
        }
286
287 21 View Code Duplication
        foreach (array_reverse(static::$words, true) as $word_number => $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...
288 21
            if ($number >= $word_number) {
289 21
                $parts[] = static::getCases($word_number, $gender);
290 21
                $number %= $word_number;
291
            }
292
        }
293
294
        // make one array with cases and delete 'o/об' prepositional from all parts except the last one
295 21
        foreach (array(static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ) as $case) {
296 21
            $result[$case] = [];
297 21
            foreach ($parts as $partN => $part) {
298 21
                $result[$case][] = $part[$case];
299
            }
300 21
            $result[$case] = implode(' ', $result[$case]);
301
        }
302
303 21
        return $result;
304
    }
305
306
    /**
307
     * @param int $number
308
     * @param string $case
309
     * @param string $gender
310
     *
311
     * @return string
312
     * @throws \Exception
313
     */
314 25
    public static function getCase($number, $case, $gender = self::MALE)
315
    {
316 25
        $case = static::canonizeCase($case);
317 25
        $forms = static::getCases($number, $gender);
318 25
        return $forms[$case];
319
    }
320
}
321