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

PHPCSStandards / PHP_CodeSniffer / 16032942235

02 Jul 2025 06:29PM UTC coverage: 78.448% (+0.007%) from 78.441%
16032942235

Pull #1151

github

web-flow
Merge b2b0d856b into 368817d89
Pull Request #1151: Generic/Syntax: add support for inspecting code passed via STDIN

22 of 24 new or added lines in 1 file covered. (91.67%)

2 existing lines in 1 file now uncovered.

25210 of 32136 relevant lines covered (78.45%)

69.41 hits per line

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

94.87
/src/Standards/Generic/Sniffs/PHP/SyntaxSniff.php
1
<?php
2
/**
3
 * Ensures PHP believes the syntax is clean.
4
 *
5
 * @author    Greg Sherwood <gsherwood@squiz.net>
6
 * @author    Blaine Schmeisser <blainesch@gmail.com>
7
 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
8
 * @license   https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
9
 */
10

11
namespace PHP_CodeSniffer\Standards\Generic\Sniffs\PHP;
12

13
use PHP_CodeSniffer\Config;
14
use PHP_CodeSniffer\Files\File;
15
use PHP_CodeSniffer\Sniffs\Sniff;
16
use PHP_CodeSniffer\Util\Common;
17

18
class SyntaxSniff implements Sniff
19
{
20

21
    /**
22
     * The path to the PHP version we are checking with.
23
     *
24
     * @var string
25
     */
26
    private $phpPath = null;
27

28

29
    /**
30
     * Returns an array of tokens this test wants to listen for.
31
     *
32
     * @return array<int|string>
33
     */
34
    public function register()
18✔
35
    {
36
        return [
7✔
37
            T_OPEN_TAG,
18✔
38
            T_OPEN_TAG_WITH_ECHO,
18✔
39
        ];
14✔
40

41
    }//end register()
42

43

44
    /**
45
     * Processes this test, when one of its tokens is encountered.
46
     *
47
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
48
     * @param int                         $stackPtr  The position of the current token in
49
     *                                               the stack passed in $tokens.
50
     *
51
     * @return int
52
     */
53
    public function process(File $phpcsFile, $stackPtr)
18✔
54
    {
55
        if ($this->phpPath === null) {
18✔
56
            $this->phpPath = Config::getExecutablePath('php');
18✔
57
        }
7✔
58

59
        $cmd     = $this->getLintCommand($phpcsFile);
18✔
60
        $output  = shell_exec($cmd);
18✔
61
        $matches = [];
18✔
62
        if (preg_match('/^.*error:(.*) in .* on line ([0-9]+)/m', trim($output), $matches) === 1) {
18✔
63
            $error = trim($matches[1]);
13✔
64
            $line  = (int) $matches[2];
13✔
65
            $phpcsFile->addErrorOnLine("PHP syntax error: $error", $line, 'PHPSyntax');
13✔
66
        }
5✔
67

68
        // Ignore the rest of the file.
69
        return $phpcsFile->numTokens;
18✔
70

71
    }//end process()
72

73

74
    /**
75
     * Returns the command used to lint PHP code.
76
     *
77
     * This method handles different scenarios based on the input source:
78
     * - For STDIN input on Windows: Creates a temporary file and uses direct file linting.
79
     * - For STDIN input on non-Windows: Pipes the content through echo to PHP linter.
80
     * - For regular files: Uses direct file linting.
81
     *
82
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The File object.
83
     *
84
     * @return string The command used to lint PHP code.
85
     */
86
    private function getLintCommand(File $phpcsFile)
18✔
87
    {
88
        if ($phpcsFile->getFilename() === 'STDIN') {
18✔
89
            $content = $phpcsFile->getTokensAsString(0, $phpcsFile->numTokens);
15✔
90

91
            if (stripos(PHP_OS, 'WIN') === 0) {
15✔
92
                $tempFile = $this->createTempFile($content);
6✔
93
                return $this->getFileLintCommand($tempFile);
6✔
94
            }
95

96
            return "echo ".escapeshellarg($content)." | ".Common::escapeshellcmd($this->phpPath)." -l -d display_errors=1 -d error_prepend_string='' 2>&1";
9✔
97
        }//end if
98

99
        return $this->getFileLintCommand($phpcsFile->getFilename());
3✔
100

101
    }//end getLintCommand()
102

103

104
    /**
105
     * Creates a temporary file with the given content and registers a shutdown function to delete
106
     * the file when the script ends.
107
     *
108
     * @param string $content The content to write to the temporary file.
109
     *
110
     * @return string The path to the created temporary file.
111
     */
112
    private function createTempFile($content)
6✔
113
    {
114
        $tempFile = tempnam(sys_get_temp_dir(), 'phpcs-syntax-sniff');
6✔
115
        file_put_contents($tempFile, $content);
6✔
116

117
        register_shutdown_function(
6✔
118
            function () use ($tempFile) {
3✔
NEW
UNCOV
119
                if (file_exists($tempFile) === true) {
×
NEW
UNCOV
120
                    unlink($tempFile);
×
121
                }
122
            }
3✔
123
        );
6✔
124

125
        return $tempFile;
6✔
126

127
    }//end createTempFile()
128

129

130
    /**
131
     * Returns the command used to lint a specific PHP file.
132
     *
133
     * @param string $fileName The name of the file to be checked.
134
     *
135
     * @return string The command used to lint the specified PHP file.
136
     */
137
    private function getFileLintCommand($fileName)
9✔
138
    {
139
        $escapedFileName = escapeshellarg($fileName);
9✔
140
        return Common::escapeshellcmd($this->phpPath)." -l -d display_errors=1 -d error_prepend_string='' $escapedFileName 2>&1";
9✔
141

142
    }//end getFileLintCommand()
143

144

145
}//end class
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