1<?php
2/**
3 * Ensures that getRequestData() is used to access super globals.
4 *
5 * PHP version 5
6 *
7 * @category  PHP
8 * @package   PHP_CodeSniffer_MySource
9 * @author    Greg Sherwood <gsherwood@squiz.net>
10 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
11 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
12 * @link      http://pear.php.net/package/PHP_CodeSniffer
13 */
14
15/**
16 * Ensures that getRequestData() is used to access super globals.
17 *
18 * @category  PHP
19 * @package   PHP_CodeSniffer_MySource
20 * @author    Greg Sherwood <gsherwood@squiz.net>
21 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
22 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
23 * @version   Release: @package_version@
24 * @link      http://pear.php.net/package/PHP_CodeSniffer
25 */
26class MySource_Sniffs_PHP_GetRequestDataSniff implements PHP_CodeSniffer_Sniff
27{
28
29
30    /**
31     * Returns an array of tokens this test wants to listen for.
32     *
33     * @return array
34     */
35    public function register()
36    {
37        return array(T_VARIABLE);
38
39    }//end register()
40
41
42    /**
43     * Processes this sniff, when one of its tokens is encountered.
44     *
45     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
46     * @param int                  $stackPtr  The position of the current token in
47     *                                        the stack passed in $tokens.
48     *
49     * @return void
50     */
51    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
52    {
53        $tokens = $phpcsFile->getTokens();
54
55        $varName = $tokens[$stackPtr]['content'];
56        if ($varName !== '$_REQUEST'
57            && $varName !== '$_GET'
58            && $varName !== '$_POST'
59            && $varName !== '$_FILES'
60        ) {
61            return;
62        }
63
64        // The only place these super globals can be accessed directly is
65        // in the getRequestData() method of the Security class.
66        $inClass = false;
67        foreach ($tokens[$stackPtr]['conditions'] as $i => $type) {
68            if ($tokens[$i]['code'] === T_CLASS) {
69                $className = $phpcsFile->findNext(T_STRING, $i);
70                $className = $tokens[$className]['content'];
71                if (strtolower($className) === 'security') {
72                    $inClass = true;
73                } else {
74                    // We don't have nested classes.
75                    break;
76                }
77            } else if ($inClass === true && $tokens[$i]['code'] === T_FUNCTION) {
78                $funcName = $phpcsFile->findNext(T_STRING, $i);
79                $funcName = $tokens[$funcName]['content'];
80                if (strtolower($funcName) === 'getrequestdata') {
81                    // This is valid.
82                    return;
83                } else {
84                    // We don't have nested functions.
85                    break;
86                }
87            }//end if
88        }//end foreach
89
90        // If we get to here, the super global was used incorrectly.
91        // First find out how it is being used.
92        $globalName = strtolower(substr($varName, 2));
93        $usedVar    = '';
94
95        $openBracket = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
96        if ($tokens[$openBracket]['code'] === T_OPEN_SQUARE_BRACKET) {
97            $closeBracket = $tokens[$openBracket]['bracket_closer'];
98            $usedVar      = $phpcsFile->getTokensAsString(($openBracket + 1), ($closeBracket - $openBracket - 1));
99        }
100
101        $type  = 'SuperglobalAccessed';
102        $error = 'The %s super global must not be accessed directly; use Security::getRequestData(';
103        $data  = array($varName);
104        if ($usedVar !== '') {
105            $type  .= 'WithVar';
106            $error .= '%s, \'%s\'';
107            $data[] = $usedVar;
108            $data[] = $globalName;
109        }
110
111        $error .= ') instead';
112        $phpcsFile->addError($error, $stackPtr, $type, $data);
113
114    }//end process()
115
116
117}//end class
118