Records an error against a specific token in the file.
public addError ( string $error, integer $stackPtr, string $code = '', array $data = [], integer $severity, boolean $fixable = false ) : boolean | ||
$error | string | The error message. |
$stackPtr | integer | The stack position where the error occurred. |
$code | string | A violation code unique to the sniff message. |
$data | array | Replacements for the error message. |
$severity | integer | The severity level for this error. A value of 0 will be converted into the default severity level. |
$fixable | boolean | Can the error be fixed by the sniff? |
return | boolean |
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Make sure this is the first PHP open tag so we don't process // the same file twice. $prevOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, $stackPtr - 1); if ($prevOpenTag !== false) { return; } $fileName = $phpcsFile->getFileName(); $extension = substr($fileName, strrpos($fileName, '.')); $nextClass = $phpcsFile->findNext(array(T_CLASS, T_INTERFACE), $stackPtr); if ($extension === '.php') { if ($nextClass !== false) { $error = '%s found in ".php" file; use ".inc" extension instead'; $data = array(ucfirst($tokens[$nextClass]['content'])); $phpcsFile->addError($error, $stackPtr, 'ClassFound', $data); } } else { if ($extension === '.inc') { if ($nextClass === false) { $error = 'No interface or class found in ".inc" file; use ".php" extension instead'; $phpcsFile->addError($error, $stackPtr, 'NoClass'); } } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param integer $stackPtr The position of the current token in the * stack passed in $tokens. * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Process !! casts if ($tokens[$stackPtr]['code'] == T_BOOLEAN_NOT) { $nextToken = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if (!$nextToken) { return; } if ($tokens[$nextToken]['code'] != T_BOOLEAN_NOT) { return; } $error = 'Usage of !! cast is not allowed. Please use (bool) to cast.'; $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); return; } // Only allow short forms if both short and long forms are possible $matching = array('(boolean)' => '(bool)', '(integer)' => '(int)'); $content = $tokens[$stackPtr]['content']; $key = strtolower($content); if (isset($matching[$key])) { $error = 'Please use ' . $matching[$key] . ' instead of ' . $content . '.'; $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); return; } if ($content !== $key) { $error = 'Please use ' . $key . ' instead of ' . $content . '.'; $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); return; } }
/** * Processes the tokens that this sniff is interested in. * * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. * @param int $stackPtr The position in the stack where * the token was found. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr - 1]['code'] !== T_WHITESPACE) { $error = 'Expected 1 space before opening brace of class definition; 0 found'; $phpcsFile->addError($error, $stackPtr); } else { $content = $tokens[$stackPtr - 1]['content']; if ($content !== ' ') { $length = strlen($content); if ($length === 1) { $length = 'tab'; } $error = "Expected 1 space before opening brace of class definition; {$length} found"; $phpcsFile->addError($error, $stackPtr); } } //end if $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr + 1, null, true); if ($next !== false && $tokens[$next]['line'] !== $tokens[$stackPtr]['line'] + 1) { $num = $tokens[$next]['line'] - $tokens[$stackPtr]['line'] - 1; $error = "Expected 0 blank lines after opening brace of class definition; {$num} found"; $phpcsFile->addError($error, $stackPtr); } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { // Only run this sniff once per info file. $end = count($phpcsFile->getTokens()) + 1; $fileExtension = strtolower(substr($phpcsFile->getFilename(), -4)); if ($fileExtension !== 'info') { return $end; } $tokens = $phpcsFile->getTokens(); $contents = file_get_contents($phpcsFile->getFilename()); $info = Drupal_Sniffs_InfoFiles_ClassFilesSniff::drupalParseInfoFormat($contents); if (isset($info['name']) === false) { $error = '"name" property is missing in the info file'; $phpcsFile->addError($error, $stackPtr, 'Name'); } if (isset($info['description']) === false) { $error = '"description" property is missing in the info file'; $phpcsFile->addError($error, $stackPtr, 'Description'); } if (isset($info['core']) === false) { $error = '"core" property is missing in the info file'; $phpcsFile->addError($error, $stackPtr, 'Core'); } else { if ($info['core'] === '7.x' && isset($info['php']) === true && $info['php'] <= '5.2') { $error = 'Drupal 7 core already requires PHP 5.2'; $ptr = Drupal_Sniffs_InfoFiles_ClassFilesSniff::getPtr('php', $info['php'], $phpcsFile); $phpcsFile->addError($error, $ptr, 'D7PHPVersion'); } } return $end; }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The current file being processed. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $path = $phpcsFile->getFileName(); if (!preg_match("/(views)/i", $path)) { return; } $tokens = $phpcsFile->getTokens(); $classname = $tokens[$phpcsFile->findNext(T_STRING, $stackPtr)]['content']; if (preg_match("/(helpers)/i", $path)) { $final_classname = $this->classname_without_type($classname, "Helper"); $msg_on_error = "Cake convention expects the helper class name to end with 'Helper'"; } else { $final_classname = $this->classname_with_type($classname, "View"); $msg_on_error = "Cake convention expects the view class name to end with 'View'"; } if (is_null($final_classname)) { $phpcsFile->addError($msg_on_error, $stackPtr); return; } $expected_file_name = preg_replace('/([A-Z])/', '_${1}', $final_classname); if (strpos($expected_file_name, "_") === 0) { $expected_file_name = substr($expected_file_name, 1, strlen($expected_file_name)); } $expected_file_name = strtolower($expected_file_name) . ".php"; if (!preg_match("/" . $expected_file_name . "/", $path)) { $error = "File name is expected to be, '" . $expected_file_name . "' for Class with name, '" . $classname . "'"; $phpcsFile->addError($error, $stackPtr); } }
/** * Processes this test when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * @param int $currScope A pointer to the start of the scope. * * @return void */ protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) { $className = $phpcsFile->getDeclarationName($currScope); $methodName = $phpcsFile->getDeclarationName($stackPtr); if (strcasecmp($methodName, $className) === 0) { $error = 'PHP4 style constructors are not allowed; use "__construct()" instead'; $phpcsFile->addError($error, $stackPtr, 'OldStyle'); } else { if (strcasecmp($methodName, '__construct') !== 0) { // Not a constructor. return; } } $tokens = $phpcsFile->getTokens(); $parentClassName = $phpcsFile->findExtendedClassName($currScope); if ($parentClassName === false) { return; } $endFunctionIndex = $tokens[$stackPtr]['scope_closer']; $startIndex = $stackPtr; while ($doubleColonIndex = $phpcsFile->findNext(array(T_DOUBLE_COLON), $startIndex, $endFunctionIndex)) { if ($tokens[$doubleColonIndex + 1]['code'] === T_STRING && $tokens[$doubleColonIndex + 1]['content'] === $parentClassName) { $error = 'PHP4 style calls to parent constructors are not allowed; use "parent::__construct()" instead'; $phpcsFile->addError($error, $doubleColonIndex + 1, 'OldStyleCall'); } $startIndex = $doubleColonIndex + 1; } }
/** * Processes the tokens that this sniff is interested in. * * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. * @param int $stackPtr The position in the stack where * the token was found. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($next === false) { return; } if ($tokens[$next]['code'] !== T_CLOSE_TAG) { $found = $tokens[$next]['line'] - $tokens[$stackPtr]['line'] - 1; if ($found !== 1) { $error = 'Expected one blank line after closing brace of class definition; %s found'; $data = array($found); $phpcsFile->addError($error, $stackPtr, 'SpacingAfterClose', $data); } } // Ignore nested style definitions from here on. The spacing before the closing brace // (a single blank line) will be enforced by the above check, which ensures there is a // blank line after the last nested class. $found = $phpcsFile->findPrevious(T_CLOSE_CURLY_BRACKET, $stackPtr - 1, $tokens[$stackPtr]['bracket_opener']); if ($found !== false) { return; } $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr - 1, null, true); if ($prev !== false && $tokens[$prev]['line'] !== $tokens[$stackPtr]['line'] - 1) { $num = $tokens[$stackPtr]['line'] - $tokens[$prev]['line'] - 1; $error = 'Expected 0 blank lines before closing brace of class definition; %s found'; $data = array($num); $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeClose', $data); } }
/** * Processes this sniff, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // No bracket can have space before them. $prevType = $tokens[$stackPtr - 1]['code']; if (in_array($prevType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { $nonSpace = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr - 2, null, true); $expected = $tokens[$nonSpace]['content'] . $tokens[$stackPtr]['content']; $found = $phpcsFile->getTokensAsString($nonSpace, $stackPtr - $nonSpace) . $tokens[$stackPtr]['content']; $error = 'Space found before square bracket; expected "%s" but found "%s"'; $data = array($expected, $found); $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeBracket', $data); } if ($tokens[$stackPtr]['type'] === 'T_OPEN_SQUARE_BRACKET') { // Open brackets can't have spaces on after them either. $nextType = $tokens[$stackPtr + 1]['code']; if (in_array($nextType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { $nonSpace = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr + 2, null, true); $expected = $tokens[$stackPtr]['content'] . $tokens[$nonSpace]['content']; $found = $phpcsFile->getTokensAsString($stackPtr, $nonSpace - $stackPtr + 1); $error = 'Space found after square bracket; expected "%s" but found "%s"'; $data = array($expected, $found); $phpcsFile->addError($error, $stackPtr, 'SpaceAfterBracket', $data); } } }
/** * Processes the function tokens within the class. * * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. * @param int $stackPtr The position where the token was found. * * @return void */ protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // if ($tokens[$stackPtr]['content'][1] === '_') { // $error = 'Property name "%s" should not be prefixed with an underscore to indicate visibility'; // $data = array($tokens[$stackPtr]['content']); // $phpcsFile->addWarning($error, $stackPtr, 'Underscore', $data); // } // Detect multiple properties defined at the same time. Throw an error // for this, but also only process the first property in the list so we don't // repeat errors. $find = PHP_CodeSniffer_Tokens::$scopeModifiers; $find = array_merge($find, array(T_VARIABLE, T_VAR, T_SEMICOLON)); $prev = $phpcsFile->findPrevious($find, $stackPtr - 1); if ($tokens[$prev]['code'] === T_VARIABLE) { return; } if ($tokens[$prev]['code'] === T_VAR) { $error = 'The var keyword must not be used to declare a property'; $phpcsFile->addError($error, $stackPtr, 'VarUsed'); } $next = $phpcsFile->findNext(array(T_VARIABLE, T_SEMICOLON), $stackPtr + 1); if ($tokens[$next]['code'] === T_VARIABLE) { $error = 'There must not be more than one property declared per statement'; $phpcsFile->addError($error, $stackPtr, 'Multiple'); } $modifier = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$scopeModifiers, $stackPtr); if ($modifier === false || $tokens[$modifier]['line'] !== $tokens[$stackPtr]['line']) { $error = 'Visibility must be declared on property "%s"'; $data = array($tokens[$stackPtr]['content']); $phpcsFile->addError($error, $stackPtr, 'ScopeMissing', $data); } }
/** * Processes this sniff, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in * the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $keyword = $tokens[$stackPtr]['content']; $tokenCode = $tokens[$stackPtr]['type']; switch ($tokenCode) { case 'T_INCLUDE_ONCE': // Here we are looking if the found include_once keyword is // part of an XClass declaration where this is allowed. if ($tokens[$stackPtr + 7]['content'] === "'XCLASS'") { return; } $error = 'Including files with "' . $keyword . '" is not allowed; '; $error .= 'use "require_once" instead'; $phpcsFile->addError($error, $stackPtr); break; case 'T_REQUIRE': $error = 'Including files with "' . $keyword . '" is not allowed; '; $error .= 'use "require_once" instead'; $phpcsFile->addError($error, $stackPtr); break; case 'T_INCLUDE': $error = 'Including files with "' . $keyword . '" is not allowed; '; $error .= 'use "require_once" instead'; $phpcsFile->addError($error, $stackPtr); break; default: } //end switch }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The current file being processed. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $trait = $phpcsFile->findNext(T_STRING, $stackPtr); $name = $tokens[$trait]['content']; if (preg_match('|^[A-Z]|', $name) === 0) { $error = 'Each %s name must begin with a capital letter'; $errorData = array($tokens[$stackPtr]['content']); $phpcsFile->addError($error, $stackPtr, 'StartWithCapital', $errorData); } if ($this->allowUnderscore === true) { if (preg_match('|_[a-z]|', $name)) { $error = 'Trait "%s" is not in camel caps with underscores format'; $phpcsFile->addError($error, $stackPtr, 'CamelCapsWithUnderscore', array($name)); } $name = lcfirst(str_replace('_', '', $name)); } else { if (strpos($name, '_') !== FALSE) { $error = 'Underscores are not allowed in trait "%s"'; $phpcsFile->addError($error, $stackPtr, 'NoUnderscore', array($name)); } $name = array(lcfirst($name)); } if (PHP_CodeSniffer::isCamelCaps($name, false, true, true) === false) { $error = 'Trait "%s" is not in camel caps format'; $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', array($name)); } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $this->requiredSpacesAfterOpen = (int) $this->requiredSpacesAfterOpen; $this->requiredSpacesBeforeClose = (int) $this->requiredSpacesBeforeClose; $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]['parenthesis_opener']) === true && isset($tokens[$stackPtr]['parenthesis_closer']) === true) { $parenOpener = $tokens[$stackPtr]['parenthesis_opener']; $parenCloser = $tokens[$stackPtr]['parenthesis_closer']; $spaceAfterOpen = 0; if ($tokens[$parenOpener + 1]['code'] === T_WHITESPACE) { $spaceAfterOpen = strlen(rtrim($tokens[$parenOpener + 1]['content'], $phpcsFile->eolChar)); } if ($spaceAfterOpen !== $this->requiredSpacesAfterOpen) { $error = 'Expected %s spaces after opening bracket; %s found'; $data = array($this->requiredSpacesAfterOpen, $spaceAfterOpen); $phpcsFile->addError($error, $parenOpener + 1, 'SpacingAfterOpenBrace', $data); } if ($tokens[$parenOpener]['line'] === $tokens[$parenCloser]['line']) { $spaceBeforeClose = 0; if ($tokens[$parenCloser - 1]['code'] === T_WHITESPACE) { $spaceBeforeClose = strlen(ltrim($tokens[$parenCloser - 1]['content'], $phpcsFile->eolChar)); } if ($spaceBeforeClose !== $this->requiredSpacesBeforeClose) { $error = 'Expected %s spaces before closing bracket; %s found'; $data = array($this->requiredSpacesBeforeClose, $spaceBeforeClose); $phpcsFile->addError($error, $parenCloser - 1, 'SpaceBeforeCloseBrace', $data); } } } //end if }
/** * Processes the tokens within the scope. * * @param PHP_CodeSniffer_File $phpcsFile The file being processed. * @param int $stackPtr The position where this token was * found. * @param int $currScope The position of the current scope. * * @return void */ protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) { $methodName = $phpcsFile->getDeclarationName($stackPtr); if ($methodName === null) { // Ignore closures. return; } $className = $phpcsFile->getDeclarationName($currScope); $errorData = array($className . '::' . $methodName); // Is this a magic method. IE. is prefixed with "__". if (preg_match('|^__|', $methodName) !== 0) { $magicPart = substr($methodName, 2); if (in_array($magicPart, $this->magicMethods) === false) { $error = 'Method name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; $phpcsFile->addError($error, $stackPtr, 'MethodDoubleUnderscore', $errorData); } return; } $methodProps = $phpcsFile->getMethodProperties($stackPtr); $scope = $methodProps['scope']; $scopeSpecified = $methodProps['scope_specified']; // Methods should not contain underscores. if (strpos($methodName, '_') !== false) { if ($scopeSpecified === true) { $error = '%s method name "%s" is not in lowerCamel format, it must not contain underscores'; $data = array(ucfirst($scope), $errorData[0]); $phpcsFile->addError($error, $stackPtr, 'ScopeNotLowerCamel', $data); } else { $error = 'Method name "%s" is not in lowerCamel format, it must not contain underscores'; $phpcsFile->addError($error, $stackPtr, 'NotLowerCamel', $errorData); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param integer $stackPtr The position of the current token * in the stack passed in $tokens. * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]['scope_closer']) === false) { // Probably an interface method. return; } $closeBrace = $tokens[$stackPtr]['scope_closer']; $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, $closeBrace - 1, null, true); $braceLine = $tokens[$closeBrace]['line']; $prevLine = $tokens[$prevContent]['line']; $found = $braceLine - $prevLine - 1; if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true) { // Nested function. if ($found < 0) { $error = 'Closing brace of nested function must be on a new line'; $phpcsFile->addError($error, $closeBrace, 'ContentBeforeClose'); } elseif ($found > 0) { $error = 'Expected 0 blank lines before closing brace of nested function; %s found'; $data = array($found); $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeNestedClose', $data); } } else { if ($found !== 0) { $error = 'Expected 0 blank lines before closing function brace; %s found'; $data = array($found); $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeClose', $data); } } }
/** * Processes this test, when one of its tokens is encountered. * * Operations to check for: * $i = 1 + 1; * $i = $i + 1; * $i = (1 + 1) - 1; * * Operations to ignore: * array($i => -1); * $i = -1; * range(-10, -1); * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in * the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $has_equality_token = in_array($tokens[$stackPtr - 2]['code'], PHP_CodeSniffer_Tokens::$equalityTokens); // Ensure this is a construct to check. $lastSyntaxItem = $phpcsFile->findPrevious(array(T_WHITESPACE), $stackPtr - 1, $tokens[$stackPtr]['column'] * -1, true, NULL, true); $needs_operator_suffix = in_array($tokens[$lastSyntaxItem]['code'], array(T_LNUMBER, T_DNUMBER, T_CLOSE_PARENTHESIS, T_CLOSE_SQUARE_BRACKET, T_CLOSE_CURLY_BRACKET, T_VARIABLE, T_STRING, T_CONSTANT_ENCAPSED_STRING)); $needs_operator_prefix = !in_array($tokens[$lastSyntaxItem]['code'], array(T_OPEN_PARENTHESIS, T_EQUAL)); if ($needs_operator_suffix && ($tokens[$stackPtr - 2]['code'] !== T_EQUAL && $tokens[$stackPtr - 2]['code'] !== T_DOUBLE_ARROW && !$has_equality_token && !($tokens[$stackPtr]['code'] === T_EQUAL && $tokens[$stackPtr + 1]['code'] === T_BITWISE_AND) && ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE || $tokens[$stackPtr + 1]['content'] != ' '))) { $error = 'An operator statement must be followed by a single space'; $phpcsFile->addError($error, $stackPtr); } if ($needs_operator_prefix) { $error = false; if ($tokens[$stackPtr - 1]['code'] !== T_WHITESPACE) { $error = true; } else { if ($tokens[$stackPtr - 1]['content'] !== ' ' && $tokens[$stackPtr]['code'] !== T_EQUAL) { $nonWhiteSpace = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr - 1, null, true); // Make sure that the previous operand is on the same line before // throwing an error. if ($tokens[$nonWhiteSpace]['line'] === $tokens[$stackPtr]['line']) { $error = true; } } } if ($error === true) { $error = 'There must be a single space before an operator statement'; $phpcsFile->addError($error, $stackPtr); } } //end if }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param integer $stackPtr The position of the current token in the * stack passed in $tokens. * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr - 1]['code'] !== T_WHITESPACE) { $message = 'Expected 1 space before ., but 0 found'; $phpcsFile->addError($message, $stackPtr, 'MissingBefore'); } else { $content = str_replace("\r\n", "\n", $tokens[$stackPtr - 1]['content']); $spaces = strlen($content); if ($spaces > 1) { $message = 'Expected 1 space before ., but %d found'; $data = array($spaces); $phpcsFile->addError($message, $stackPtr, 'TooManyBefore', $data); } } if ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) { $message = 'Expected 1 space after ., but 0 found'; $phpcsFile->addError($message, $stackPtr, 'MissingAfter'); } else { $content = str_replace("\r\n", "\n", $tokens[$stackPtr + 1]['content']); $spaces = strlen($content); if ($spaces > 1) { $message = 'Expected 1 space after ., but %d found'; $data = array($spaces); $phpcsFile->addError($message, $stackPtr, 'TooManyAfter', $data); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile * @param int $stackPtr */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $functionToken = $phpcsFile->findNext(T_FUNCTION, $stackPtr); if ($functionToken === false) { return; } $nameToken = $phpcsFile->findNext(T_STRING, $functionToken); if (in_array($tokens[$nameToken]['content'], $this->magicMethods) === false) { return; } $scopeToken = $phpcsFile->findPrevious(array(T_PUBLIC, T_PROTECTED, T_PRIVATE), $nameToken, $stackPtr); if ($scopeToken === false) { return; } if ($tokens[$scopeToken]['type'] != 'T_PUBLIC') { $error = "Magic methods must be public (since PHP 5.3) !"; $phpcsFile->addError($error, $stackPtr); } $staticToken = $phpcsFile->findPrevious(T_STATIC, $scopeToken, $scopeToken - 2); if ($staticToken === false) { return; } else { $error = "Magic methods can not be static (since PHP 5.3) !"; $phpcsFile->addError($error, $stackPtr); } }
/** * Process the return comment of this function comment. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * @param int $commentStart The position in the stack where the comment started. * * @return void */ protected function processReturn(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart) { $tokens = $phpcsFile->getTokens(); // Skip constructor and destructor. $methodName = $phpcsFile->getDeclarationName($stackPtr); $isSpecialMethod = $methodName === '__construct' || $methodName === '__destruct'; $return = null; foreach ($tokens[$commentStart]['comment_tags'] as $tag) { if ($tokens[$tag]['content'] === '@return') { if ($return !== null) { $error = 'Only 1 @return tag is allowed in a function comment'; $phpcsFile->addError($error, $tag, 'DuplicateReturn'); return; } $return = $tag; } } if ($isSpecialMethod === true) { return; } if ($return !== null) { $content = $tokens[$return + 2]['content']; if (empty($content) === true || $tokens[$return + 2]['code'] !== T_DOC_COMMENT_STRING) { $error = 'Return type missing for @return tag in function comment'; $phpcsFile->addError($error, $return, 'MissingReturnType'); } elseif (!$this->functionHasReturnStatement($phpcsFile, $stackPtr)) { $error = 'Function return type is set, but function has no return statement'; $phpcsFile->addError($error, $return, 'InvalidNoReturn'); } } elseif ($this->functionHasReturnStatement($phpcsFile, $stackPtr)) { $error = 'Missing @return tag in function comment.'; $phpcsFile->addError($error, $tokens[$commentStart]['comment_closer'], 'MissingReturn'); } //end if }
/** * Processes this test, when one of its tokens is encountered. */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Check decrement / increment. if ($tokens[$stackPtr]['code'] === T_DEC || $tokens[$stackPtr]['code'] === T_INC) { $modifyLeft = substr($tokens[$stackPtr - 1]['content'], 0, 1) === '$' || $tokens[$stackPtr + 1]['content'] === ';'; if ($modifyLeft === true && $tokens[$stackPtr - 1]['code'] === T_WHITESPACE) { $error = 'There must not be a single space before a unary operator statement'; $phpcsFile->addError($error, $stackPtr, 'IncDecLeft'); return; } if ($modifyLeft === false && !in_array(substr($tokens[$stackPtr + 1]['content'], 0, 1), array('$', ','))) { $error = 'A unary operator statement must not be followed by a single space'; $phpcsFile->addError($error, $stackPtr, 'IncDecRight'); return; } } // Check "!" operator. if ($tokens[$stackPtr]['code'] === T_BOOLEAN_NOT && $tokens[$stackPtr + 1]['code'] === T_WHITESPACE) { $error = 'A unary operator statement must not be followed by a space'; $phpcsFile->addError($error, $stackPtr, 'BooleanNot'); return; } // Find the last syntax item to determine if this is an unary operator. $lastSyntaxItem = $phpcsFile->findPrevious(array(T_WHITESPACE), $stackPtr - 1, $tokens[$stackPtr]['column'] * -1, true, null, true); $operatorSuffixAllowed = in_array($tokens[$lastSyntaxItem]['code'], array(T_LNUMBER, T_DNUMBER, T_CLOSE_PARENTHESIS, T_CLOSE_CURLY_BRACKET, T_CLOSE_SQUARE_BRACKET, T_VARIABLE, T_STRING)); // Check plus / minus value assignments or comparisons. if ($tokens[$stackPtr]['code'] === T_MINUS || $tokens[$stackPtr]['code'] === T_PLUS) { if ($operatorSuffixAllowed === false && $tokens[$stackPtr + 1]['code'] === T_WHITESPACE) { $error = 'A unary operator statement must not be followed by a space'; $phpcsFile->addError($error, $stackPtr); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param integer $stackPtr The position of the current token in * the token stack. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { if ($this->_phpVersion === null) { $this->_phpVersion = PHP_CodeSniffer::getConfigData('php_version'); if ($this->_phpVersion === null) { $this->_phpVersion = PHP_VERSION_ID; } } $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]['scope_closer']) === false) { return; } $errorData = array(strtolower($tokens[$stackPtr]['content'])); $nextClass = $phpcsFile->findNext(array(T_CLASS, T_INTERFACE, T_TRAIT), $tokens[$stackPtr]['scope_closer'] + 1); if ($nextClass !== false) { $error = 'Each %s must be in a file by itself'; $phpcsFile->addError($error, $nextClass, 'MultipleClasses', $errorData); $phpcsFile->recordMetric($stackPtr, 'One class per file', 'no'); } else { $phpcsFile->recordMetric($stackPtr, 'One class per file', 'yes'); } if ($this->_phpVersion >= 50300) { $namespace = $phpcsFile->findNext(array(T_NAMESPACE, T_CLASS, T_INTERFACE, T_TRAIT), 0); if ($tokens[$namespace]['code'] !== T_NAMESPACE) { $error = 'Each %s must be in a namespace of at least one level (a top-level vendor name)'; $phpcsFile->addError($error, $stackPtr, 'MissingNamespace', $errorData); $phpcsFile->recordMetric($stackPtr, 'Class defined in namespace', 'no'); } else { $phpcsFile->recordMetric($stackPtr, 'Class defined in namespace', 'yes'); } } }
/** * Processes the tokens that this sniff is interested in. * * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. * @param int $stackPtr The position in the stack where * the token was found. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $utils = Security_Sniffs_UtilsFactory::getInstance(); $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['content'] == 'preg_replace') { $s = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr); $closer = $tokens[$s]['parenthesis_closer']; $s = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $s + 1, $closer, true); if ($tokens[$s]['code'] == T_CONSTANT_ENCAPSED_STRING) { $pattern = $tokens[$s]['content']; if (substr($pattern, 1, 1) === '/') { // $pattern is a regex if (preg_match('/(\\/|\\))\\w*e\\w*"$/', $pattern)) { $phpcsFile->addWarning("Usage of preg_replace with /e modifier is not recommended.", $stackPtr, 'PregReplaceE'); $s = $phpcsFile->findNext(array(T_COMMA, T_WHITESPACE, T_COMMENT, T_DOC_COMMENT), $s + 1, $closer, true); if ($utils::is_token_user_input($tokens[$s])) { $phpcsFile->addError("User input and /e modifier found in preg_replace, remote code execution possible.", $stackPtr, 'PregReplaceUserInputE'); } } } else { $phpcsFile->addWarning("Weird usage of preg_replace, please check manually for /e modifier.", $stackPtr, 'PregReplaceWeird'); } } elseif ($tokens[$s]['code'] == T_VARIABLE && $utils::is_token_user_input($tokens[$s])) { $phpcsFile->addError("User input found in preg_replace, /e modifier could be used for malicious intent.", $stackPtr, 'PregReplaceUserInput'); } else { $phpcsFile->addWarning("Dynamic usage of preg_replace, please check manually for /e modifier or user input.", $stackPtr, 'PregReplaceDyn'); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $php_tag_token = $tokens[$stackPtr]; $php_tag_code = $php_tag_token['code']; if (T_OPEN_TAG === $php_tag_code) { // opening php tag should be the first token. // any whitespace beofre an opening php tag is tokenized // as T_INLINE_HTML, so no need to check the content of the token. $isFirst = 0 === $stackPtr; if (!$isFirst) { $error = 'Any char before the opening PHP tag is prohibited. Please remove newline or indentation before the opening PHP tag.'; $phpcsFile->addError($error, $stackPtr); } } else { // if (T_CLOSE_TAG === $php_tag_code) // closing php tag should be the last token // and it must not contain any whitespace. $php_tag_string = $php_tag_token['content']; $isLast = count($tokens) - 1 === $stackPtr; // both of the two closing php tags contains 2 chars exactly. $containsEndTagOnly = strlen($php_tag_string) > 2; if (!$isLast || !$containsEndTagOnly) { $error = 'Any char after the closing PHP tag is prohibited. Please removes newline or spaces after the closing PHP tag.'; $phpcsFile->addError($error, $stackPtr); } } }
/** * Processes this sniff, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Check there is one space before the operator. if ($tokens[$stackPtr - 1]['code'] !== T_WHITESPACE) { $error = 'Expected 1 space before logical operator; 0 found'; $phpcsFile->addError($error, $stackPtr, 'NoSpaceBefore'); } else { $prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if ($tokens[$stackPtr]['line'] === $tokens[$prev]['line'] && strlen($tokens[$stackPtr - 1]['content']) !== 1) { $found = strlen($tokens[$stackPtr - 1]['content']); $error = 'Expected 1 space before logical operator; %s found'; $data = array($found); $phpcsFile->addError($error, $stackPtr, 'TooMuchSpaceBefore', $data); } } // Check there is one space after the operator. if ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) { $error = 'Expected 1 space after logical operator; 0 found'; $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfter'); } else { $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr - 1, null, true); if ($tokens[$stackPtr]['line'] === $tokens[$next]['line'] && strlen($tokens[$stackPtr + 1]['content']) !== 1) { $found = strlen($tokens[$stackPtr + 1]['content']); $error = 'Expected 1 space after logical operator; %s found'; $data = array($found); $phpcsFile->addError($error, $stackPtr, 'TooMuchSpaceAfter', $data); } } }
/** * Processes the tokens that this sniff is interested in. * * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. * @param int $stackPtr The position in the stack where * the token was found. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr - 1]['code'] === T_WHITESPACE) { $error = 'There must be no space before a colon in a style definition'; $phpcsFile->addError($error, $stackPtr); } if ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) { if ($tokens[$stackPtr + 1]['content'] == "link" || $tokens[$stackPtr + 1]['content'] == "visited" || $tokens[$stackPtr + 1]['content'] == "active" || $tokens[$stackPtr + 1]['content'] == "hover") { return; } $error = 'Expected 1 space after colon in style definition; 0 found'; $phpcsFile->addError($error, $stackPtr); } else { $content = $tokens[$stackPtr + 1]['content']; if (strpos($content, $phpcsFile->eolChar) === false) { $length = strlen($content); if ($length !== 1) { $error = "Expected 1 space after colon in style definition; {$length} found"; $phpcsFile->addError($error, $stackPtr); } } else { $error = 'Expected 1 space after colon in style definition; newline found'; $phpcsFile->addError($error, $stackPtr); } } //end if }
/** * Processes class member variables. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $memberProps = $phpcsFile->getMemberProperties($stackPtr); if (empty($memberProps) === true) { return; } $memberName = ltrim($tokens[$stackPtr]['content'], '$'); $isPublic = $memberProps['scope'] === 'private' ? false : true; $scope = $memberProps['scope']; $scopeSpecified = $memberProps['scope_specified']; // If it's a private member, it must have an underscore on the front. if ($isPublic === false && $memberName[0] !== '_') { $error = 'Private member variable "%s" must be prefixed with an underscore'; $data = array($memberName); $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $data); return; } // If it's not a private member, it must not have an underscore on the front. if ($isPublic === true && $scopeSpecified === true && $memberName[0] === '_') { $error = '%s member variable "%s" must not be prefixed with an underscore'; $data = array(ucfirst($scope), $memberName); $phpcsFile->addError($error, $stackPtr, 'PublicUnderscore', $data); return; } }
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $nameIndex = $phpcsFile->findNext(T_VARIABLE, $stackPtr + 1); $semicolonIndex = $phpcsFile->findNext(T_SEMICOLON, $stackPtr + 1); while ($nameIndex < $semicolonIndex) { if ($tokens[$nameIndex]['code'] !== T_WHITESPACE && $tokens[$nameIndex]['code'] !== T_COMMA) { $globalName = $tokens[$nameIndex]['content']; if (in_array($globalName, $this->ignoreList) || in_array($globalName, self::$PHPReserved)) { return; } // Skip '$' and forge a valid global variable name $expected = '$wg' . ucfirst(substr($globalName, 1)); // Verify global is prefixed with wg if (strpos($globalName, '$wg') !== 0) { $phpcsFile->addError('Global variable "%s" is lacking \'wg\' prefix. Should be "%s".', $stackPtr, 'wgPrefix', array($globalName, $expected)); } else { // Verify global is probably CamelCase $val = ord(substr($globalName, 3, 1)); if (!($val >= 65 && $val <= 90)) { $phpcsFile->addError('Global variable "%s" should use CamelCase: "%s"', $stackPtr, 'CamelCase', array($globalName, $expected)); } } } $nameIndex++; } }
/** * Processes the tokens that this sniff is interested in. * * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. * @param int $stackPtr The position in the stack where * the token was found. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr - 1, null, true); if ($tokens[$prev]['code'] !== T_STYLE) { // The colon is not part of a style definition. return; } if ($tokens[$prev]['content'] === 'progid') { // Special case for IE filters. return; } if ($tokens[$stackPtr - 1]['code'] === T_WHITESPACE) { $error = 'There must be no space before a colon in a style definition'; $phpcsFile->addError($error, $stackPtr, 'Before'); } if ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) { $error = 'Expected 1 space after colon in style definition; 0 found'; $phpcsFile->addError($error, $stackPtr, 'NoneAfter'); } else { $content = $tokens[$stackPtr + 1]['content']; if (strpos($content, $phpcsFile->eolChar) === false) { $length = strlen($content); if ($length !== 1) { $error = 'Expected 1 space after colon in style definition; %s found'; $data = array($length); $phpcsFile->addError($error, $stackPtr, 'After', $data); } } else { $error = 'Expected 1 space after colon in style definition; newline found'; $phpcsFile->addError($error, $stackPtr, 'AfterNewline'); } } //end if }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr + 1]['code'] != T_WHITESPACE) { // space after $message = 'Concat operator must be followed by one space'; $phpcsFile->addError($message, $stackPtr, 'Missing'); } else { if (strpos($tokens[$stackPtr + 2]['content'], $phpcsFile->eolChar) !== false && strpos($tokens[$stackPtr + 2]['content'], $phpcsFile->eolChar) == 0 || strpos($tokens[$stackPtr + 1]['content'], $phpcsFile->eolChar) !== false && strpos($tokens[$stackPtr + 1]['content'], $phpcsFile->eolChar) == 0) { // the period is followed by a new line return; } $found = strlen($tokens[$stackPtr + 1]['content']); if ($found > 1) { $error = sprintf('Expected 1 space after concat operator; %s found', $found); $phpcsFile->addError($error, $stackPtr, 'Too much'); } } if ($tokens[$stackPtr - 1]['code'] != T_WHITESPACE) { // space before $message = 'Concat operator must be preceded by one space'; $phpcsFile->addError($message, $stackPtr, 'Missing'); } else { if (strpos($tokens[$stackPtr - 2]['content'], $phpcsFile->eolChar) !== false || strpos($tokens[$stackPtr - 1]['content'], $phpcsFile->eolChar) !== false) { // the period is on a new line return; } $found = strlen($tokens[$stackPtr - 1]['content']); if ($found > 1) { $error = sprintf('Expected 1 space before concat operator; %s found', $found); $phpcsFile->addError($error, $stackPtr, 'Too much'); } } }
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { if (false !== strpos($phpcsFile->getFilename(), 'model') || false !== strpos($phpcsFile->getFilename(), 'form') || false !== strpos($phpcsFile->getFilename(), 'filter')) { return null; } $tokens = $phpcsFile->getTokens(); $className = $phpcsFile->findNext(T_STRING, $stackPtr); $name = trim($tokens[$className]['content']); // "op" prefix if (0 !== strpos($name, 'op')) { $error = ucfirst($tokens[$stackPtr]['content']) . ' name must begin with "op" prefix'; $phpcsFile->addError($error, $stackPtr); } // "Interface" suffix if ($tokens[$stackPtr]['code'] === T_INTERFACE && !preg_match('/Interface$/', $name)) { $error = ucfirst($tokens[$stackPtr]['content']) . ' name must end with "Interface"'; $phpcsFile->addError($error, $stackPtr); } // stripped prefix if (0 === strpos($name, 'op')) { $name = substr($name, 2); } if (!PHP_CodeSniffer::isCamelCaps($name, true, true, false)) { $error = ucfirst($tokens[$stackPtr]['content']) . ' name is not in camel caps format'; $phpcsFile->addError($error, $stackPtr); } }
/** * Processes this sniff, when one of its tokens is encountered * * @param PHP_CodeSniffer_File $phpcsFile The current file being checked * @param integer $stackPtr The position of the current token in the stack passed in $tokens * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Array keyword should be lower case if (strtolower($tokens[$stackPtr]['content']) !== $tokens[$stackPtr]['content']) { $error = 'Array keyword should be lower case; expected "array" but found "' . $tokens[$stackPtr]['content'] . '"'; $phpcsFile->addError($error, $stackPtr, 'ArrayKeywordLowerCase'); } $arrayStart = $tokens[$stackPtr]['parenthesis_opener']; $arrayEnd = $tokens[$arrayStart]['parenthesis_closer']; $keywordStart = $tokens[$stackPtr]['column']; if ($arrayStart !== $stackPtr + 1) { $error = 'There must be no space between the Array keyword and the opening parenthesis'; $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeParenthesisArray'); } // Check for empty arrays $content = $phpcsFile->findNext(array(T_WHITESPACE), $arrayStart + 1, $arrayEnd + 1, true); if ($content === $arrayEnd) { // Empty array, but if the brackets aren't together, there's a problem if ($arrayEnd - $arrayStart !== 1) { $error = 'Empty array declaration must have no space between the parentheses'; $phpcsFile->addError($error, $stackPtr, 'NoSpaceBetweenParenthesisEmptyArray'); // We can return here because there is nothing else to check. All code // below can assume that the array is not empty return; } } // @todo: Deeper Array checking }