Issues (51)

Security Analysis    no request data  

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.

BestIt/Sniffs/Formatting/TraitUseSpacingSniff.php (1 issue)

Labels
Severity

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
3
declare(strict_types=1);
4
5
namespace BestIt\Sniffs\Formatting;
6
7
use BestIt\CodeSniffer\Helper\ClassHelper;
8
use BestIt\CodeSniffer\Helper\TokenHelper;
9
use BestIt\Sniffs\AbstractSniff;
10
use BestIt\Sniffs\ClassRegistrationTrait;
11
use function substr_count;
12
use const T_CLOSE_CURLY_BRACKET;
13
use const T_OPEN_CURLY_BRACKET;
14
use const T_SEMICOLON;
15
use const T_WHITESPACE;
16
17
/**
18
 * Checks the newlines between the trait uses.
19
 *
20
 * This is a refactores copy of the slevomat code sniff.
21
 *
22
 * @author blange <[email protected]>
23
 * @package BestIt\Sniffs\Formatting
24
 */
25
class TraitUseSpacingSniff extends AbstractSniff
26
{
27
    use ClassRegistrationTrait;
28
29
    /**
30
     * You MUST not provide additional lines after your last rait usage.
31
     */
32
    public const CODE_INCORRECT_LINES_COUNT_AFTER_LAST_USE = 'IncorrectLinesCountAfterLastUse';
33
34
    /**
35
     * You MUST not provide additional new lines before your first trait use.
36
     */
37
    public const CODE_INCORRECT_LINES_COUNT_BEFORE_FIRST_USE = 'IncorrectLinesCountBeforeFirstUse';
38
39
    /**
40
     * You MUST not provide additional new lines between trait usages.
41
     */
42
    public const CODE_INCORRECT_LINES_COUNT_BETWEEN_USES = 'IncorrectLinesCountBetweenUses';
43
44
    /**
45
     * How many lines after the last use.
46
     */
47
    private const LINES_AFTER_LAST_USE = 1;
48
49
    /**
50
     * How many lines after the last use.
51
     */
52
    private const LINES_AFTER_LAST_USE_WHEN_LAST_IN_CLASS = 0;
53
54
    /**
55
     * How many use before the first one.
56
     */
57
    private const LINES_BEFORE_FIRST_USE = 0;
58
59
    /**
60
     * How many lines between the uses.
61
     */
62
    private const LINES_BETWEEN_USES = 0;
63
64
    /**
65
     * The message to the user for the error before usages.
66
     */
67
    private const MESSAGE_INCORRECT_LINES_COUNT_BEFORE_FIRST_USE =
68
        'Expected %d lines before first use statement, found %d.';
69
70
    /**
71
     * The message to the user for the error after the last usage.
72
     */
73
    private const MESSAGE_INCORRECT_LINES_COUNT_AFTER_LAST_USE =
74
        'Expected %d lines after last use statement, found %d.';
75
76
    /**
77
     * The message to the user for the error between uses.
78
     */
79
    private const MESSAGE_INCORRECT_LINES_COUNT_BETWEEN_USES =
80
        'Expected %d lines between same types of use statement, found %d.';
81
82
    /**
83
     * The use declarations positions of this "class".
84
     *
85
     * @var array
86
     */
87
    private array $uses;
0 ignored issues
show
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_ARRAY, expecting T_FUNCTION or T_CONST
Loading history...
88
89
    /**
90
     * Returns false if there are no uses.
91
     *
92
     * @return bool
93
     */
94
    protected function areRequirementsMet(): bool
95
    {
96
        return (bool) $this->uses = ClassHelper::getTraitUsePointers($this->getFile(), $this->getStackPos());
97
    }
98
99
    /**
100
     * Checks the line after the last use and registers an error if needed.
101
     *
102
     * @param int $lastUsePos
103
     *
104
     * @return void
105
     */
106
    private function checkLinesAfterLastUse(int $lastUsePos): void
107
    {
108
        $lastUseEndPos = $this->getLastUseEndPos($lastUsePos);
109
110
        list($realLinesAfterUse, $whitespaceEnd) = $this->getRealLinesAfterLastUse($lastUseEndPos);
111
112
        $requiredLinesAfter = $this->isEndOfClass($lastUseEndPos)
113
            ? self::LINES_AFTER_LAST_USE_WHEN_LAST_IN_CLASS
114
            : self::LINES_AFTER_LAST_USE;
115
116
        if ($realLinesAfterUse !== $requiredLinesAfter) {
117
            $fix = $this->getFile()->addFixableError(
118
                self::MESSAGE_INCORRECT_LINES_COUNT_AFTER_LAST_USE,
119
                $lastUsePos,
120
                self::CODE_INCORRECT_LINES_COUNT_AFTER_LAST_USE,
121
                [
122
                    $requiredLinesAfter,
123
                    $realLinesAfterUse
124
                ]
125
            );
126
127
            if ($fix) {
128
                $this->fixLineAfterLastUse($lastUseEndPos, $whitespaceEnd, $requiredLinesAfter);
129
            }
130
        }
131
    }
132
133
    /**
134
     * Checks the lines before the first usage and registers an error if needed.
135
     *
136
     * @param int $firstUsePos
137
     *
138
     * @return void
139
     */
140
    private function checkLinesBeforeFirstUse(int $firstUsePos): void
141
    {
142
        $posBeforeFirstUse = TokenHelper::findPreviousExcluding($this->getFile(), T_WHITESPACE, $firstUsePos - 1);
143
        $realLinesBeforeUse = $this->getRealLinesBeforeFirstUse($firstUsePos, $posBeforeFirstUse);
144
145
        if ($realLinesBeforeUse !== self::LINES_BEFORE_FIRST_USE) {
146
            $fix = $this->getFile()->addFixableError(
147
                self::MESSAGE_INCORRECT_LINES_COUNT_BEFORE_FIRST_USE,
148
                $firstUsePos,
149
                self::CODE_INCORRECT_LINES_COUNT_BEFORE_FIRST_USE,
150
                [
151
                    self::LINES_BEFORE_FIRST_USE,
152
                    $realLinesBeforeUse
153
                ]
154
            );
155
156
            if ($fix) {
157
                $this->fixLinesBeforeFirstUse($firstUsePos, $posBeforeFirstUse, self::LINES_BEFORE_FIRST_USE);
158
            }
159
        }
160
    }
161
162
    /**
163
     * Checks the lines between uses and registers an erro rif needed.
164
     *
165
     * @return void
166
     */
167
    private function checkLinesBetweenUses(): void
168
    {
169
        $file = $this->getFile();
170
        $previousUsePos = null;
171
172
        foreach ($this->uses as $usePos) {
173
            if ($previousUsePos === null) {
174
                $previousUsePos = $usePos;
175
                continue;
176
            }
177
178
            $posBeforeUse = TokenHelper::findPreviousEffective($file, $usePos - 1);
179
            $previousUseEndPos = TokenHelper::findNextLocal(
180
                $file,
181
                [T_SEMICOLON, T_OPEN_CURLY_BRACKET],
182
                $previousUsePos + 1
183
            );
184
185
            $realLinesBetweenUse = $this->getRealLinesBetweenUses(
186
                $previousUseEndPos,
187
                $usePos
188
            );
189
190
            $previousUsePos = $usePos;
191
192
            if ($realLinesBetweenUse !== self::LINES_BETWEEN_USES) {
193
                $errorParameters = [
194
                    self::MESSAGE_INCORRECT_LINES_COUNT_BETWEEN_USES,
195
                    $usePos,
196
                    self::CODE_INCORRECT_LINES_COUNT_BETWEEN_USES,
197
                    [
198
                        self::LINES_BETWEEN_USES,
199
                        $realLinesBetweenUse
200
                    ]
201
                ];
202
203
                if ($previousUseEndPos !== $posBeforeUse) {
204
                    $file->addError(...$errorParameters);
205
                } else {
206
                    $fix = $file->addFixableError(...$errorParameters);
207
208
                    if ($fix) {
209
                        $this->fixLinesBetweenUses($usePos, $previousUseEndPos, self::LINES_BETWEEN_USES);
210
                    }
211
                }
212
            }
213
        }
214
    }
215
216
    /**
217
     * Fixes the lines which are allowed after the last use.
218
     *
219
     * @param int $lastUseEndPos
220
     * @param int $whitespaceEnd
221
     * @param int $requiredLinesAfter
222
     *
223
     * @return void
224
     */
225
    private function fixLineAfterLastUse(
226
        int $lastUseEndPos,
227
        int $whitespaceEnd,
228
        int $requiredLinesAfter
229
    ): void {
230
        $file = $this->getFile();
231
232
        $file->fixer->beginChangeset();
233
234
        for ($i = $lastUseEndPos + 1; $i <= $whitespaceEnd; $i++) {
235
            $file->fixer->replaceToken($i, '');
236
        }
237
238
        for ($i = 0; $i <= $requiredLinesAfter; $i++) {
239
            $file->fixer->addNewline($lastUseEndPos);
240
        }
241
242
        $file->fixer->endChangeset();
243
    }
244
245
    /**
246
     * Fixes the lines before the first use.
247
     *
248
     * @param int $firstUsePos
249
     * @param int $posBeforeFirstUse
250
     *
251
     * @return void
252
     */
253
    private function fixLinesBeforeFirstUse(
254
        int $firstUsePos,
255
        int $posBeforeFirstUse
256
    ): void {
257
        $file = $this->getFile();
258
        $file->fixer->beginChangeset();
259
260
        $posBeforeIndentation = TokenHelper::findPreviousContent(
261
            $file,
262
            T_WHITESPACE,
263
            $file->eolChar,
264
            $firstUsePos,
265
            $posBeforeFirstUse
266
        );
267
268
        if ($posBeforeIndentation !== null) {
269
            for ($i = $posBeforeFirstUse + 1; $i <= $posBeforeIndentation; $i++) {
270
                $file->fixer->replaceToken($i, '');
271
            }
272
        }
273
        for ($i = 0; $i <= self::LINES_BEFORE_FIRST_USE; $i++) {
274
            $file->fixer->addNewline($posBeforeFirstUse);
275
        }
276
277
        $file->fixer->endChangeset();
278
    }
279
280
    /**
281
     * Fixes the lines between the uses.
282
     *
283
     * @param int $usePos
284
     * @param int $previousUseEndPos
285
     *
286
     * @return void
287
     */
288
    private function fixLinesBetweenUses(int $usePos, int $previousUseEndPos): void
289
    {
290
        $file = $this->getFile();
291
292
        $posBeforeIndentation = TokenHelper::findPreviousContent(
293
            $file,
294
            T_WHITESPACE,
295
            $file->eolChar,
296
            $usePos,
297
            $previousUseEndPos
298
        );
299
300
        $file->fixer->beginChangeset();
301
        if ($posBeforeIndentation !== null) {
302
            for ($i = $previousUseEndPos + 1; $i <= $posBeforeIndentation; $i++) {
303
                $file->fixer->replaceToken($i, '');
304
            }
305
        }
306
        for ($i = 0; $i <= self::LINES_BETWEEN_USES; $i++) {
307
            $file->fixer->addNewline($previousUseEndPos);
308
        }
309
        $file->fixer->endChangeset();
310
    }
311
312
    /**
313
     * Gets the position on which the last use ends.
314
     *
315
     * @param int $lastUsePos
316
     *
317
     * @return int
318
     */
319
    private function getLastUseEndPos(int $lastUsePos): int
320
    {
321
        $file = $this->getFile();
322
        $tokens = $file->getTokens();
323
324
        $lastUseEndPos = TokenHelper::findNextLocal(
325
            $file,
326
            [T_SEMICOLON, T_OPEN_CURLY_BRACKET],
327
            $lastUsePos + 1
328
        );
329
330
        if ($tokens[$lastUseEndPos]['code'] === T_OPEN_CURLY_BRACKET) {
331
            $lastUseEndPos = $tokens[$lastUseEndPos]['bracket_closer'];
332
        }
333
334
        return $lastUseEndPos;
335
    }
336
337
    /**
338
     * Gets the real lines after the last use.
339
     *
340
     * @param int $lastUseEndPos
341
     *
342
     * @return array The first element is the line count, and the second element is when the whitespace ends.
343
     */
344
    private function getRealLinesAfterLastUse(int $lastUseEndPos): array
345
    {
346
        $file = $this->getFile();
347
        $tokens = $file->getTokens();
348
        $whitespaceEnd = TokenHelper::findNextExcluding($file, T_WHITESPACE, $lastUseEndPos + 1) - 1;
349
350
        if ($lastUseEndPos !== $whitespaceEnd && $tokens[$whitespaceEnd]['content'] !== $file->eolChar) {
351
            $lastEolPos = TokenHelper::findPreviousContent(
352
                $file,
353
                T_WHITESPACE,
354
                $file->eolChar,
355
                $whitespaceEnd - 1,
356
                $lastUseEndPos
357
            );
358
            $whitespaceEnd = $lastEolPos ?? $lastUseEndPos;
359
        }
360
361
        $whitespaceAfterLastUse = TokenHelper::getContent($file, $lastUseEndPos + 1, $whitespaceEnd);
362
363
        $realLinesAfterUse = substr_count($whitespaceAfterLastUse, $file->eolChar) - 1;
364
365
        return [$realLinesAfterUse, $whitespaceEnd];
366
    }
367
368
    /**
369
     * Returns the real lines before the first use.
370
     *
371
     * @param int $firstUsePos
372
     * @param int $posBeforeFirstUse
373
     *
374
     * @return int
375
     */
376
    private function getRealLinesBeforeFirstUse(int $firstUsePos, int $posBeforeFirstUse): int
377
    {
378
        $file = $this->getFile();
379
        $whitespaceBeforeFirstUse = '';
380
381
        if ($posBeforeFirstUse + 1 !== $firstUsePos) {
382
            $whitespaceBeforeFirstUse .= TokenHelper::getContent(
383
                $file,
384
                $posBeforeFirstUse + 1,
385
                $firstUsePos - 1
386
            );
387
        }
388
389
        return substr_count($whitespaceBeforeFirstUse, $file->eolChar) - 1;
390
    }
391
392
    /**
393
     * Returns the real lines between the uses.
394
     *
395
     * @param int $previousUseEndPos
396
     * @param int $usePos
397
     *
398
     * @return int
399
     */
400
    private function getRealLinesBetweenUses(int &$previousUseEndPos, int $usePos): int
401
    {
402
        $tokens = $this->getFile()->getTokens();
403
404
        if ($tokens[$previousUseEndPos]['code'] === T_OPEN_CURLY_BRACKET) {
405
            $previousUseEndPos = $tokens[$previousUseEndPos]['bracket_closer'];
406
        }
407
408
        return $tokens[$usePos]['line'] - $tokens[$previousUseEndPos]['line'] - 1;
409
    }
410
411
    /**
412
     * Is the given Position the end of the class.
413
     *
414
     * @param int $lastUseEndPos
415
     *
416
     * @return bool
417
     */
418
    private function isEndOfClass(int $lastUseEndPos): bool
419
    {
420
        $file = $this->getFile();
421
        $tokens = $file->getTokens();
422
423
        $posAfterLastUse = TokenHelper::findNextEffective($file, $lastUseEndPos + 1);
424
425
        return $tokens[$posAfterLastUse]['code'] === T_CLOSE_CURLY_BRACKET;
426
    }
427
428
    /**
429
     * Processes the token.
430
     *
431
     * @return void
432
     */
433
    protected function processToken(): void
434
    {
435
        $this->checkLinesBeforeFirstUse($this->uses[0]);
436
        $this->checkLinesAfterLastUse($this->uses[count($this->uses) - 1]);
437
438
        if (count($this->uses) > 1) {
439
            $this->checkLinesBetweenUses();
440
        }
441
    }
442
}
443