• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PHPCompatibility / PHPCompatibility / 19804455605

30 Nov 2025 08:31PM UTC coverage: 98.306% (-0.04%) from 98.346%
19804455605

push

github

web-flow
Merge pull request #2014 from PHPCompatibility/php-8.5/new-removedterminatingcasewithsemicolon-sniff

PHP 8.5 | ✨ New `PHPCompatibility.ControlStructures.RemovedTerminatingCaseWithSemicolon` sniff (RFC)

30 of 34 new or added lines in 1 file covered. (88.24%)

21 existing lines in 15 files now uncovered.

8355 of 8499 relevant lines covered (98.31%)

20.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.68
/PHPCompatibility/Sniffs/ParameterValues/NewProcOpenCmdArraySniff.php
1
<?php
2
/**
3
 * PHPCompatibility, an external standard for PHP_CodeSniffer.
4
 *
5
 * @package   PHPCompatibility
6
 * @copyright 2012-2020 PHPCompatibility Contributors
7
 * @license   https://opensource.org/licenses/LGPL-3.0 LGPL3
8
 * @link      https://github.com/PHPCompatibility/PHPCompatibility
9
 */
10

11
namespace PHPCompatibility\Sniffs\ParameterValues;
12

13
use PHPCompatibility\AbstractFunctionCallParameterSniff;
14
use PHPCompatibility\Helpers\ScannedCode;
15
use PHP_CodeSniffer\Files\File;
16
use PHP_CodeSniffer\Util\Tokens;
17
use PHPCSUtils\Utils\PassedParameters;
18

19
/**
20
 * As of PHP 7.4, `proc_open()` now also accepts an array instead of a string for the command.
21
 *
22
 * In that case, the process will be opened directly (without going through a shell) and
23
 * PHP will take care of any necessary argument escaping.
24
 *
25
 * PHP version 7.4
26
 *
27
 * @link https://www.php.net/manual/en/migration74.new-features.php#migration74.new-features.standard.proc-open
28
 * @link https://www.php.net/manual/en/function.proc-open.php
29
 *
30
 * @since 9.3.0
31
 * @since 10.0.0 This class is now `final`.
32
 */
33
final class NewProcOpenCmdArraySniff extends AbstractFunctionCallParameterSniff
34
{
35

36
    /**
37
     * Functions to check for.
38
     *
39
     * @since 9.3.0
40
     *
41
     * @var array<string, true>
42
     */
43
    protected $targetFunctions = [
44
        'proc_open' => true,
45
    ];
46

47

48
    /**
49
     * Do a version check to determine if this sniff needs to run at all.
50
     *
51
     * @since 9.3.0
52
     *
53
     * @return bool
54
     */
55
    protected function bowOutEarly()
8✔
56
    {
57
        return false;
8✔
58
    }
59

60

61
    /**
62
     * Process the parameters of a matched function.
63
     *
64
     * @since 9.3.0
65
     *
66
     * @param \PHP_CodeSniffer\Files\File $phpcsFile    The file being scanned.
67
     * @param int                         $stackPtr     The position of the current token in the stack.
68
     * @param string                      $functionName The token content (function name) which was matched.
69
     * @param array                       $parameters   Array with information about the parameters.
70
     *
71
     * @return void
72
     */
73
    public function processParameters(File $phpcsFile, $stackPtr, $functionName, $parameters)
8✔
74
    {
75
        $targetParam = PassedParameters::getParameterFromStack($parameters, 1, 'command');
8✔
76
        if ($targetParam === false) {
8✔
UNCOV
77
            return;
×
78
        }
79

80
        $tokens       = $phpcsFile->getTokens();
8✔
81
        $nextNonEmpty = $phpcsFile->findNext(Tokens::EMPTY_TOKENS, $targetParam['start'], $targetParam['end'], true);
8✔
82

83
        if ($nextNonEmpty === false) {
8✔
84
            // Shouldn't be possible.
85
            return;
8✔
86
        }
87

88
        if ($tokens[$nextNonEmpty]['code'] !== \T_ARRAY
8✔
89
            && $tokens[$nextNonEmpty]['code'] !== \T_OPEN_SHORT_ARRAY
8✔
90
        ) {
91
            // Not passed as an array.
92
            return;
8✔
93
        }
94

95
        if (ScannedCode::shouldRunOnOrBelow('7.3') === true) {
8✔
96
            $phpcsFile->addError(
4✔
97
                'The proc_open() function did not accept $command to be passed in array format in PHP 7.3 and earlier.',
4✔
98
                $nextNonEmpty,
4✔
99
                'Found'
4✔
100
            );
2✔
101
        }
102

103
        if (ScannedCode::shouldRunOnOrAbove('7.4') === true) {
8✔
104
            if (\strpos(\strtolower($targetParam['clean']), 'escapeshellarg(') === false) {
4✔
105
                // Efficiency: prevent needlessly walking the array.
106
                return;
4✔
107
            }
108

109
            $items = PassedParameters::getParameters($phpcsFile, $nextNonEmpty);
4✔
110

111
            if (empty($items)) {
4✔
UNCOV
112
                return;
×
113
            }
114

115
            foreach ($items as $item) {
4✔
116
                for ($i = $item['start']; $i <= $item['end']; $i++) {
4✔
117
                    if ($tokens[$i]['code'] !== \T_STRING
4✔
118
                        && $tokens[$i]['code'] !== \T_NAME_FULLY_QUALIFIED
4✔
119
                    ) {
120
                        continue;
4✔
121
                    }
122

123
                    $contentLc = \strtolower($tokens[$i]['content']);
4✔
124
                    if ($contentLc !== 'escapeshellarg' && $contentLc !== '\escapeshellarg') {
4✔
UNCOV
125
                        continue;
×
126
                    }
127

128
                    // @todo Potential future enhancement: check if it's a call to the PHP native function.
129

130
                    $phpcsFile->addWarning(
4✔
131
                        'When passing the $command parameter to proc_open() as an array, PHP will take care of any necessary argument escaping. Found: %s',
4✔
132
                        $i,
4✔
133
                        'Invalid',
4✔
134
                        [$item['clean']]
4✔
135
                    );
2✔
136

137
                    // Only throw one error per array item.
138
                    break;
4✔
139
                }
140
            }
141
        }
142
    }
4✔
143
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc