These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * PHPCompatibility_Sniffs_PHP_ValidIntegersSniff. |
||
| 4 | * |
||
| 5 | * @category PHP |
||
| 6 | * @package PHPCompatibility |
||
| 7 | * @author Juliette Reinders Folmer <[email protected]> |
||
| 8 | */ |
||
| 9 | |||
| 10 | /** |
||
| 11 | * PHPCompatibility_Sniffs_PHP_ValidIntegersSniff. |
||
| 12 | * |
||
| 13 | * @category PHP |
||
| 14 | * @package PHPCompatibility |
||
| 15 | * @author Juliette Reinders Folmer <[email protected]> |
||
| 16 | */ |
||
| 17 | class PHPCompatibility_Sniffs_PHP_ValidIntegersSniff extends PHPCompatibility_Sniff |
||
| 18 | { |
||
| 19 | |||
| 20 | /** |
||
| 21 | * Whether PHPCS is run on a PHP < 5.4. |
||
| 22 | * |
||
| 23 | * @var bool |
||
| 24 | */ |
||
| 25 | protected $isLowPHPVersion = false; |
||
| 26 | |||
| 27 | /** |
||
| 28 | * Returns an array of tokens this test wants to listen for. |
||
| 29 | * |
||
| 30 | * @return array |
||
| 31 | */ |
||
| 32 | public function register() |
||
| 33 | { |
||
| 34 | $this->isLowPHPVersion = version_compare(phpversion(), '5.4', '<'); |
||
| 35 | |||
| 36 | return array( |
||
| 37 | T_LNUMBER, // Binary, octal integers. |
||
| 38 | T_CONSTANT_ENCAPSED_STRING, // Hex numeric string. |
||
| 39 | ); |
||
| 40 | |||
| 41 | }//end register() |
||
| 42 | |||
| 43 | |||
| 44 | /** |
||
| 45 | * Processes this test, when one of its tokens is encountered. |
||
| 46 | * |
||
| 47 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. |
||
| 48 | * @param int $stackPtr The position of the current token in |
||
| 49 | * the stack. |
||
| 50 | * |
||
| 51 | * @return void |
||
| 52 | */ |
||
| 53 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) |
||
| 54 | { |
||
| 55 | $tokens = $phpcsFile->getTokens(); |
||
| 56 | $token = $tokens[$stackPtr]; |
||
| 57 | |||
| 58 | if ($this->couldBeBinaryInteger($tokens, $stackPtr) === true) { |
||
| 59 | if ($this->supportsBelow('5.3')) { |
||
| 60 | $error = 'Binary integer literals were not present in PHP version 5.3 or earlier. Found: %s'; |
||
| 61 | if ($this->isLowPHPVersion === false) { |
||
| 62 | $data = array($token['content']); |
||
| 63 | } else { |
||
| 64 | $data = array($this->getBinaryInteger($phpcsFile, $tokens, $stackPtr)); |
||
| 65 | } |
||
| 66 | $phpcsFile->addError($error, $stackPtr, 'BinaryIntegerFound', $data); |
||
| 67 | } |
||
| 68 | |||
| 69 | if ($this->isInvalidBinaryInteger($tokens, $stackPtr) === true) { |
||
| 70 | $error = 'Invalid binary integer detected. Found: %s'; |
||
| 71 | $data = array($this->getBinaryInteger($phpcsFile, $tokens, $stackPtr)); |
||
| 72 | $phpcsFile->addWarning($error, $stackPtr, 'InvalidBinaryIntegerFound', $data); |
||
| 73 | } |
||
| 74 | return; |
||
| 75 | } |
||
| 76 | |||
| 77 | $isError = $this->supportsAbove('7.0'); |
||
| 78 | $data = array( $token['content'] ); |
||
| 79 | |||
| 80 | if ($this->isInvalidOctalInteger($tokens, $stackPtr) === true) { |
||
| 81 | $this->addMessage( |
||
| 82 | $phpcsFile, |
||
| 83 | 'Invalid octal integer detected. Prior to PHP 7 this would lead to a truncated number. From PHP 7 onwards this causes a parse error. Found: %s', |
||
| 84 | $stackPtr, |
||
| 85 | $isError, |
||
| 86 | 'InvalidOctalIntegerFound', |
||
| 87 | $data |
||
| 88 | ); |
||
| 89 | return; |
||
| 90 | } |
||
| 91 | |||
| 92 | if ($this->isHexidecimalNumericString($tokens, $stackPtr) === true) { |
||
| 93 | $this->addMessage( |
||
| 94 | $phpcsFile, |
||
| 95 | 'The behaviour of hexadecimal numeric strings was inconsistent prior to PHP 7 and support has been removed in PHP 7. Found: %s', |
||
| 96 | $stackPtr, |
||
| 97 | $isError, |
||
| 98 | 'HexNumericStringFound', |
||
| 99 | $data |
||
| 100 | ); |
||
| 101 | return; |
||
| 102 | } |
||
| 103 | |||
| 104 | }//end process() |
||
| 105 | |||
| 106 | |||
| 107 | /** |
||
| 108 | * Could the current token an potentially be a binary integer ? |
||
| 109 | * |
||
| 110 | * @param array $tokens Token stack. |
||
| 111 | * @param int $stackPtr The current position in the token stack. |
||
| 112 | * |
||
| 113 | * @return bool |
||
| 114 | */ |
||
| 115 | private function couldBeBinaryInteger($tokens, $stackPtr) |
||
| 116 | { |
||
| 117 | $token = $tokens[$stackPtr]; |
||
| 118 | |||
| 119 | if ($token['code'] !== T_LNUMBER) { |
||
| 120 | return false; |
||
| 121 | } |
||
| 122 | |||
| 123 | if ($this->isLowPHPVersion === false) { |
||
| 124 | return (preg_match('`^0b[0-1]+$`D', $token['content']) === 1); |
||
| 125 | } |
||
| 126 | // Pre-5.4, binary strings are tokenized as T_LNUMBER (0) + T_STRING ("b01010101"). |
||
| 127 | // At this point, we don't yet care whether it's a valid binary int, that's a separate check. |
||
| 128 | else { |
||
| 129 | return($token['content'] === '0' && $tokens[$stackPtr+1]['code'] === T_STRING && preg_match('`^b[0-9]+$`D', $tokens[$stackPtr+1]['content']) === 1); |
||
| 130 | } |
||
| 131 | } |
||
| 132 | |||
| 133 | /** |
||
| 134 | * Is the current token an invalid binary integer ? |
||
| 135 | * |
||
| 136 | * @param array $tokens Token stack. |
||
| 137 | * @param int $stackPtr The current position in the token stack. |
||
| 138 | * |
||
| 139 | * @return bool |
||
| 140 | */ |
||
| 141 | private function isInvalidBinaryInteger($tokens, $stackPtr) |
||
| 142 | { |
||
| 143 | if ($this->couldBeBinaryInteger($tokens, $stackPtr) === false) { |
||
| 144 | return false; |
||
| 145 | } |
||
| 146 | |||
| 147 | if ($this->isLowPHPVersion === false) { |
||
| 148 | // If it's an invalid binary int, the token will be split into two T_LNUMBER tokens. |
||
| 149 | return ($tokens[$stackPtr+1]['code'] === T_LNUMBER); |
||
| 150 | } else { |
||
| 151 | return (preg_match('`^b[0-1]+$`D', $tokens[$stackPtr+1]['content']) === 0); |
||
| 152 | } |
||
| 153 | } |
||
| 154 | |||
| 155 | /** |
||
| 156 | * Retrieve the content of the tokens which together look like a binary integer. |
||
| 157 | * |
||
| 158 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. |
||
| 159 | * @param array $tokens Token stack. |
||
| 160 | * @param int $stackPtr The position of the current token in |
||
| 161 | * the stack. |
||
| 162 | * |
||
| 163 | * @return string |
||
| 164 | */ |
||
| 165 | private function getBinaryInteger(PHP_CodeSniffer_File $phpcsFile, $tokens, $stackPtr) |
||
| 166 | { |
||
| 167 | $length = 2; // PHP < 5.4 T_LNUMBER + T_STRING. |
||
| 168 | |||
| 169 | if ($this->isLowPHPVersion === false) { |
||
| 170 | $i = $stackPtr; |
||
| 171 | while ($tokens[$i]['code'] === T_LNUMBER) { |
||
| 172 | $i++; |
||
| 173 | } |
||
| 174 | $length = ($i - $stackPtr); |
||
| 175 | } |
||
| 176 | |||
| 177 | return $phpcsFile->getTokensAsString($stackPtr, $length); |
||
| 178 | } |
||
| 179 | |||
| 180 | /** |
||
| 181 | * Is the current token an invalid octal integer ? |
||
| 182 | * |
||
| 183 | * @param array $tokens Token stack. |
||
| 184 | * @param int $stackPtr The current position in the token stack. |
||
| 185 | * |
||
| 186 | * @return bool |
||
| 187 | */ |
||
| 188 | View Code Duplication | private function isInvalidOctalInteger($tokens, $stackPtr) |
|
|
0 ignored issues
–
show
|
|||
| 189 | { |
||
| 190 | $token = $tokens[$stackPtr]; |
||
| 191 | |||
| 192 | if ($token['code'] === T_LNUMBER && preg_match('`^0[0-7]*[8-9]+[0-9]*$`D', $token['content']) === 1) { |
||
| 193 | return true; |
||
| 194 | } |
||
| 195 | |||
| 196 | return false; |
||
| 197 | } |
||
| 198 | |||
| 199 | /** |
||
| 200 | * Is the current token a hexidecimal numeric string ? |
||
| 201 | * |
||
| 202 | * @param array $tokens Token stack. |
||
| 203 | * @param int $stackPtr The current position in the token stack. |
||
| 204 | * |
||
| 205 | * @return bool |
||
| 206 | */ |
||
| 207 | View Code Duplication | private function isHexidecimalNumericString($tokens, $stackPtr) |
|
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 208 | { |
||
| 209 | $token = $tokens[$stackPtr]; |
||
| 210 | |||
| 211 | if ($token['code'] === T_CONSTANT_ENCAPSED_STRING && preg_match('`^0x[a-f0-9]+$`iD', $this->stripQuotes($token['content'])) === 1) { |
||
| 212 | return true; |
||
| 213 | } |
||
| 214 | |||
| 215 | return false; |
||
| 216 | } |
||
| 217 | |||
| 218 | }//end class |
||
| 219 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.