1<?php
2/**
3 * Checks that the file does not end with a closing tag.
4 *
5 * @author    Greg Sherwood <gsherwood@squiz.net>
6 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
7 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8 */
9
10namespace PHP_CodeSniffer\Standards\Zend\Sniffs\Files;
11
12use PHP_CodeSniffer\Sniffs\Sniff;
13use PHP_CodeSniffer\Files\File;
14use PHP_CodeSniffer\Util\Tokens;
15
16class ClosingTagSniff implements Sniff
17{
18
19
20    /**
21     * Returns an array of tokens this test wants to listen for.
22     *
23     * @return array
24     */
25    public function register()
26    {
27        return [T_OPEN_TAG];
28
29    }//end register()
30
31
32    /**
33     * Processes this sniff, when one of its tokens is encountered.
34     *
35     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
36     * @param int                         $stackPtr  The position of the current token in
37     *                                               the stack passed in $tokens.
38     *
39     * @return void
40     */
41    public function process(File $phpcsFile, $stackPtr)
42    {
43        // Find the last non-empty token.
44        $tokens = $phpcsFile->getTokens();
45        for ($last = ($phpcsFile->numTokens - 1); $last > 0; $last--) {
46            if (trim($tokens[$last]['content']) !== '') {
47                break;
48            }
49        }
50
51        if ($tokens[$last]['code'] === T_CLOSE_TAG) {
52            $error = 'A closing tag is not permitted at the end of a PHP file';
53            $fix   = $phpcsFile->addFixableError($error, $last, 'NotAllowed');
54            if ($fix === true) {
55                $phpcsFile->fixer->beginChangeset();
56                $phpcsFile->fixer->replaceToken($last, $phpcsFile->eolChar);
57                $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($last - 1), null, true);
58                if ($tokens[$prev]['code'] !== T_SEMICOLON
59                    && $tokens[$prev]['code'] !== T_CLOSE_CURLY_BRACKET
60                    && $tokens[$prev]['code'] !== T_OPEN_TAG
61                ) {
62                    $phpcsFile->fixer->addContent($prev, ';');
63                }
64
65                $phpcsFile->fixer->endChangeset();
66            }
67
68            $phpcsFile->recordMetric($stackPtr, 'PHP closing tag at EOF', 'yes');
69        } else {
70            $phpcsFile->recordMetric($stackPtr, 'PHP closing tag at EOF', 'no');
71        }//end if
72
73        // Ignore the rest of the file.
74        return ($phpcsFile->numTokens + 1);
75
76    }//end process()
77
78
79}//end class
80