Skip to content

Commit

Permalink
feat(GetRequestData): Add rule to prevent direct usage of $_GET, $_PO…
Browse files Browse the repository at this point in the history
…ST, $_REQUEST and $_FILES in Drupal 8 (#2958175 by alexpott, Arkener)
  • Loading branch information
alexpott authored and klausi committed Dec 7, 2019
1 parent 69b071b commit 326c945
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 0 deletions.
107 changes: 107 additions & 0 deletions coder_sniffer/DrupalPractice/Sniffs/Variables/GetRequestDataSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php
/**
* \DrupalPractice\Sniffs\Variables\GetRequestDataSniff.
*
* @category PHP
* @package PHP_CodeSniffer
* @link http://pear.php.net/package/PHP_CodeSniffer
*/

namespace DrupalPractice\Sniffs\Variables;

use DrupalPractice\Project;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;

/**
* Ensures that Symfony request object is used to access super globals.
*
* Inspired by GetRequestDataSniff.php from Squiz Labs.
*
* @see https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php
*
* @category PHP
* @package PHP_CodeSniffer
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class GetRequestDataSniff implements Sniff
{


/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return [T_VARIABLE];

}//end register()


/**
* Processes this test, when one of its tokens is encountered.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void|int
*/
public function process(File $phpcsFile, $stackPtr)
{
if (Project::getCoreVersion($phpcsFile) < 8) {
// No need to check this file again, mark it as done.
return ($phpcsFile->numTokens + 1);
}

$tokens = $phpcsFile->getTokens();
$varName = $tokens[$stackPtr]['content'];
if ($varName !== '$_REQUEST'
&& $varName !== '$_GET'
&& $varName !== '$_POST'
&& $varName !== '$_FILES'
&& $varName !== '$_COOKIE'
) {
return;
}

// If we get to here, the super global was used incorrectly.
// First find out how it is being used.
$usedVar = '';

$openBracket = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
if ($tokens[$openBracket]['code'] === T_OPEN_SQUARE_BRACKET) {
$closeBracket = $tokens[$openBracket]['bracket_closer'];
$usedVar = $phpcsFile->getTokensAsString(($openBracket + 1), ($closeBracket - $openBracket - 1));
}

$requestPropertyMap = [
'$_REQUEST' => 'request',
'$_GET' => 'query',
'$_POST' => 'request',
'$_FILES' => 'files',
'$_COOKIE' => 'cookies',
];

$type = 'SuperglobalAccessed';
$error = 'The %s super global must not be accessed directly; inject the request.stack service and use $stack->getCurrentRequest()->%s';
$data = [
$varName,
$requestPropertyMap[$varName],
];

if ($usedVar !== '') {
$type .= 'WithVar';
$error .= '->get(%s)';
$data[] = $usedVar;
}

$error .= ' instead';
$phpcsFile->addError($error, $stackPtr, $type, $data);

}//end process()


}//end class
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

$get = $_GET['test_get'];
$post = $_POST['test_post'];
$request = $_REQUEST['test_request'];
$files = $_FILES['test_files'];
$cookie = $_COOKIE['test_cookie'];

$get = $_GET;
$post = $_POST;
$request = $_REQUEST;
$files = $_FILES;
$cookie = $_COOKIE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace DrupalPractice\Sniffs\Variables;

use Drupal\Test\CoderSniffUnitTest;

class GetRequestDataUnitTest extends CoderSniffUnitTest
{


/**
* Returns the lines where errors should occur.
*
* The key of the array should represent the line number and the value
* should represent the number of errors that should occur on that line.
*
* @return array(int => int)
*/
public function getErrorList()
{
return [
3 => 1,
4 => 1,
5 => 1,
6 => 1,
7 => 1,
9 => 1,
10 => 1,
11 => 1,
12 => 1,
13 => 1,
];

}//end getErrorList()


/**
* Returns the lines where warnings should occur.
*
* The key of the array should represent the line number and the value
* should represent the number of warnings that should occur on that line.
*
* @return array(int => int)
*/
public function getWarningList()
{
return [];

}//end getWarningList()


}//end class
3 changes: 3 additions & 0 deletions coder_sniffer/DrupalPractice/Test/Variables/test.info.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: Test
type: module
core: 8.x

0 comments on commit 326c945

Please sign in to comment.