prepareForOutput() public static method

Replaces invisible characters so they are visible. On non-Windows OSes it will also colour the invisible characters.
public static prepareForOutput ( string $content ) : string
$content string The content to prepare.
return string
Example #1
0
 /**
  * Creates an array of tokens when given some CSS code.
  *
  * Uses the PHP tokenizer to do all the tricky work
  *
  * @param string $string  The string to tokenize.
  * @param string $eolChar The EOL character to use for splitting strings.
  *
  * @return array
  */
 public function tokenizeString($string, $eolChar = '\\n')
 {
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t*** START CSS TOKENIZING ***" . PHP_EOL;
     }
     // If the content doesn't have an EOL char on the end, add one so
     // the open and close tags we add are parsed correctly.
     $eolAdded = false;
     if (substr($string, strlen($eolChar) * -1) !== $eolChar) {
         $string .= $eolChar;
         $eolAdded = true;
     }
     $string = str_replace('<?php', '^PHPCS_CSS_T_OPEN_TAG^', $string);
     $string = str_replace('?>', '^PHPCS_CSS_T_CLOSE_TAG^', $string);
     $tokens = parent::tokenizeString('<?php ' . $string . '?>', $eolChar);
     $finalTokens = array();
     $finalTokens[0] = array('code' => T_OPEN_TAG, 'type' => 'T_OPEN_TAG', 'content' => '');
     $newStackPtr = 1;
     $numTokens = count($tokens);
     $multiLineComment = false;
     for ($stackPtr = 1; $stackPtr < $numTokens; $stackPtr++) {
         $token = $tokens[$stackPtr];
         // CSS files don't have lists, breaks etc, so convert these to
         // standard strings early so they can be converted into T_STYLE
         // tokens and joined with other strings if needed.
         if ($token['code'] === T_BREAK || $token['code'] === T_LIST || $token['code'] === T_DEFAULT) {
             $token['type'] = 'T_STRING';
             $token['code'] = T_STRING;
         }
         if (PHP_CODESNIFFER_VERBOSITY > 1) {
             $type = $token['type'];
             $content = PHP_CodeSniffer::prepareForOutput($token['content']);
             echo "\tProcess token {$stackPtr}: {$type} => {$content}" . PHP_EOL;
         }
         if ($token['code'] === T_POWER && $tokens[$stackPtr + 1]['content'] === 'PHPCS_CSS_T_OPEN_TAG') {
             $content = '<?php';
             for ($stackPtr = $stackPtr + 3; $stackPtr < $numTokens; $stackPtr++) {
                 if ($tokens[$stackPtr]['code'] === T_POWER && $tokens[$stackPtr + 1]['content'] === 'PHPCS_CSS_T_CLOSE_TAG') {
                     // Add the end tag and ignore the * we put at the end.
                     $content .= '?>';
                     $stackPtr += 2;
                     break;
                 } else {
                     $content .= $tokens[$stackPtr]['content'];
                 }
             }
             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                 echo "\t\t=> Found embedded PHP code: ";
                 $cleanContent = PHP_CodeSniffer::prepareForOutput($content);
                 echo $cleanContent . PHP_EOL;
             }
             $finalTokens[$newStackPtr] = array('type' => 'T_EMBEDDED_PHP', 'code' => T_EMBEDDED_PHP, 'content' => $content);
             $newStackPtr++;
             continue;
         }
         //end if
         if ($token['code'] === T_GOTO_LABEL) {
             // Convert these back to T_STRING followed by T_COLON so we can
             // more easily process style definitions.
             $finalTokens[$newStackPtr] = array('type' => 'T_STRING', 'code' => T_STRING, 'content' => substr($token['content'], 0, -1));
             $newStackPtr++;
             $finalTokens[$newStackPtr] = array('type' => 'T_COLON', 'code' => T_COLON, 'content' => ':');
             $newStackPtr++;
             continue;
         }
         if ($token['code'] === T_FUNCTION) {
             // There are no functions in CSS, so convert this to a string.
             $finalTokens[$newStackPtr] = array('type' => 'T_STRING', 'code' => T_STRING, 'content' => $token['content']);
             $newStackPtr++;
             continue;
         }
         if ($token['code'] === T_COMMENT && substr($token['content'], 0, 2) === '/*') {
             // Multi-line comment. Record it so we can ignore other
             // comment tags until we get out of this one.
             $multiLineComment = true;
         }
         if ($token['code'] === T_COMMENT && $multiLineComment === false && (substr($token['content'], 0, 2) === '//' || $token['content'][0] === '#')) {
             $content = ltrim($token['content'], '#/');
             // Guard against PHP7+ syntax errors by stripping
             // leading zeros so the content doesn't look like an invalid int.
             $leadingZero = false;
             if ($content[0] === '0') {
                 $content = '1' . $content;
                 $leadingZero = false;
             }
             $commentTokens = parent::tokenizeString('<?php ' . $content . '?>', $eolChar);
             // The first and last tokens are the open/close tags.
             array_shift($commentTokens);
             array_pop($commentTokens);
             if ($leadingZero === true) {
                 $commentTokens[0]['content'] = substr($commentTokens[0]['content'], 1);
                 $content = substr($content, 1);
             }
             if ($token['content'][0] === '#') {
                 // The # character is not a comment in CSS files, so
                 // determine what it means in this context.
                 $firstContent = $commentTokens[0]['content'];
                 // If the first content is just a number, it is probably a
                 // colour like 8FB7DB, which PHP splits into 8 and FB7DB.
                 if (($commentTokens[0]['code'] === T_LNUMBER || $commentTokens[0]['code'] === T_DNUMBER) && $commentTokens[1]['code'] === T_STRING) {
                     $firstContent .= $commentTokens[1]['content'];
                     array_shift($commentTokens);
                 }
                 // If the first content looks like a colour and not a class
                 // definition, join the tokens together.
                 if (preg_match('/^[ABCDEF0-9]+$/i', $firstContent) === 1 && $commentTokens[1]['content'] !== '-') {
                     array_shift($commentTokens);
                     // Work out what we trimmed off above and remember to re-add it.
                     $trimmed = substr($token['content'], 0, strlen($token['content']) - strlen($content));
                     $finalTokens[$newStackPtr] = array('type' => 'T_COLOUR', 'code' => T_COLOUR, 'content' => $trimmed . $firstContent);
                 } else {
                     $finalTokens[$newStackPtr] = array('type' => 'T_HASH', 'code' => T_HASH, 'content' => '#');
                 }
             } else {
                 $finalTokens[$newStackPtr] = array('type' => 'T_STRING', 'code' => T_STRING, 'content' => '//');
             }
             //end if
             $newStackPtr++;
             foreach ($commentTokens as $tokenData) {
                 if ($tokenData['code'] === T_COMMENT && (substr($tokenData['content'], 0, 2) === '//' || $tokenData['content'][0] === '#')) {
                     // This is a comment in a comment, so it needs
                     // to go through the whole process again.
                     $tokens[$stackPtr]['content'] = $tokenData['content'];
                     $stackPtr--;
                     break;
                 }
                 $finalTokens[$newStackPtr] = $tokenData;
                 $newStackPtr++;
             }
             continue;
         }
         //end if
         if ($token['code'] === T_COMMENT && substr($token['content'], -2) === '*/') {
             // Multi-line comment is done.
             $multiLineComment = false;
         }
         $finalTokens[$newStackPtr] = $token;
         $newStackPtr++;
     }
     //end for
     // A flag to indicate if we are inside a style definition,
     // which is defined using curly braces.
     $inStyleDef = false;
     // A flag to indicate if an At-rule like "@media" is used, which will result
     // in nested curly brackets.
     $asperandStart = false;
     $numTokens = count($finalTokens);
     for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) {
         $token = $finalTokens[$stackPtr];
         switch ($token['code']) {
             case T_OPEN_CURLY_BRACKET:
                 // Opening curly brackets for an At-rule do not start a style
                 // definition. We also reset the asperand flag here because the next
                 // opening curly bracket could be indeed the start of a style
                 // definition.
                 if ($asperandStart === true) {
                     $inStyleDef = false;
                     $asperandStart = false;
                 } else {
                     $inStyleDef = true;
                 }
                 break;
             case T_CLOSE_CURLY_BRACKET:
                 $inStyleDef = false;
                 $asperandStart = false;
                 break;
             case T_MINUS:
                 // Minus signs are often used instead of spaces inside
                 // class names, IDs and styles.
                 if ($finalTokens[$stackPtr + 1]['code'] === T_STRING) {
                     if ($finalTokens[$stackPtr - 1]['code'] === T_STRING) {
                         $newContent = $finalTokens[$stackPtr - 1]['content'] . '-' . $finalTokens[$stackPtr + 1]['content'];
                         $finalTokens[$stackPtr + 1]['content'] = $newContent;
                         unset($finalTokens[$stackPtr]);
                         unset($finalTokens[$stackPtr - 1]);
                     } else {
                         $newContent = '-' . $finalTokens[$stackPtr + 1]['content'];
                         $finalTokens[$stackPtr + 1]['content'] = $newContent;
                         unset($finalTokens[$stackPtr]);
                     }
                 } else {
                     if ($finalTokens[$stackPtr + 1]['code'] === T_LNUMBER) {
                         // They can also be used to provide negative numbers.
                         $finalTokens[$stackPtr + 1]['content'] = '-' . $finalTokens[$stackPtr + 1]['content'];
                         unset($finalTokens[$stackPtr]);
                     }
                 }
                 //end if
                 break;
             case T_COLON:
                 // Only interested in colons that are defining styles.
                 if ($inStyleDef === false) {
                     break;
                 }
                 for ($x = $stackPtr - 1; $x >= 0; $x--) {
                     if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$finalTokens[$x]['code']]) === false) {
                         break;
                     }
                 }
                 $finalTokens[$x]['type'] = 'T_STYLE';
                 $finalTokens[$x]['code'] = T_STYLE;
                 break;
             case T_STRING:
                 if (strtolower($token['content']) === 'url') {
                     // Find the next content.
                     for ($x = $stackPtr + 1; $x < $numTokens; $x++) {
                         if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$finalTokens[$x]['code']]) === false) {
                             break;
                         }
                     }
                     // Needs to be in the format "url(" for it to be a URL.
                     if ($finalTokens[$x]['code'] !== T_OPEN_PARENTHESIS) {
                         continue;
                     }
                     // Make sure the content isn't empty.
                     for ($y = $x + 1; $y < $numTokens; $y++) {
                         if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$finalTokens[$y]['code']]) === false) {
                             break;
                         }
                     }
                     if ($finalTokens[$y]['code'] === T_CLOSE_PARENTHESIS) {
                         continue;
                     }
                     // Join all the content together inside the url() statement.
                     $newContent = '';
                     for ($i = $x + 2; $i < $numTokens; $i++) {
                         if ($finalTokens[$i]['code'] === T_CLOSE_PARENTHESIS) {
                             break;
                         }
                         $newContent .= $finalTokens[$i]['content'];
                         unset($finalTokens[$i]);
                     }
                     // If the content inside the "url()" is in double quotes
                     // there will only be one token and so we don't have to do
                     // anything except change its type. If it is not empty,
                     // we need to do some token merging.
                     $finalTokens[$x + 1]['type'] = 'T_URL';
                     $finalTokens[$x + 1]['code'] = T_URL;
                     if ($newContent !== '') {
                         $finalTokens[$x + 1]['content'] .= $newContent;
                         $finalTokens = array_values($finalTokens);
                         $numTokens = count($finalTokens);
                     }
                 }
                 //end if
                 break;
             case T_ASPERAND:
                 $asperandStart = true;
                 break;
             default:
                 // Nothing special to be done with this token.
                 break;
         }
         //end switch
     }
     //end for
     // Reset the array keys to avoid gaps.
     $finalTokens = array_values($finalTokens);
     $numTokens = count($finalTokens);
     // Blank out the content of the end tag.
     $finalTokens[$numTokens - 1]['content'] = '';
     if ($eolAdded === true) {
         // Strip off the extra EOL char we added for tokenizing.
         $finalTokens[$numTokens - 2]['content'] = substr($finalTokens[$numTokens - 2]['content'], 0, strlen($eolChar) * -1);
         if ($finalTokens[$numTokens - 2]['content'] === '') {
             unset($finalTokens[$numTokens - 2]);
             $finalTokens = array_values($finalTokens);
             $numTokens = count($finalTokens);
         }
     }
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t*** END CSS TOKENIZING ***" . PHP_EOL;
     }
     return $finalTokens;
 }
Example #2
0
 /**
  * Creates an array of tokens when given some PHP code.
  *
  * Starts by using token_get_all() but does a lot of extra processing
  * to insert information about the context of the token.
  *
  * @param string $string  The string to tokenize.
  * @param string $eolChar The EOL character to use for splitting strings.
  *
  * @return array
  */
 public function tokenizeString($string, $eolChar = '\\n')
 {
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t*** START PHP TOKENIZING ***" . PHP_EOL;
         $isWin = false;
         if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
             $isWin = true;
         }
     }
     $tokens = @token_get_all($string);
     $finalTokens = array();
     $newStackPtr = 0;
     $numTokens = count($tokens);
     $lastNotEmptyToken = 0;
     $insideInlineIf = array();
     $commentTokenizer = new PHP_CodeSniffer_Tokenizers_Comment();
     for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) {
         $token = (array) $tokens[$stackPtr];
         $tokenIsArray = isset($token[1]);
         if (PHP_CODESNIFFER_VERBOSITY > 1) {
             if ($tokenIsArray === true) {
                 $type = token_name($token[0]);
                 $content = PHP_CodeSniffer::prepareForOutput($token[1]);
             } else {
                 $newToken = self::resolveSimpleToken($token[0]);
                 $type = $newToken['type'];
                 $content = PHP_CodeSniffer::prepareForOutput($token[0]);
             }
             echo "\tProcess token ";
             if ($tokenIsArray === true) {
                 echo "[{$stackPtr}]";
             } else {
                 echo " {$stackPtr} ";
             }
             echo ": {$type} => {$content}";
         }
         //end if
         if ($newStackPtr > 0 && $finalTokens[$newStackPtr - 1]['code'] !== T_WHITESPACE) {
             $lastNotEmptyToken = $newStackPtr - 1;
         }
         /*
             If we are using \r\n newline characters, the \r and \n are sometimes
             split over two tokens. This normally occurs after comments. We need
             to merge these two characters together so that our line endings are
             consistent for all lines.
         */
         if ($tokenIsArray === true && substr($token[1], -1) === "\r") {
             if (isset($tokens[$stackPtr + 1]) === true && is_array($tokens[$stackPtr + 1]) === true && $tokens[$stackPtr + 1][1][0] === "\n") {
                 $token[1] .= "\n";
                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
                     if ($isWin === true) {
                         echo '\\n';
                     } else {
                         echo "\\n";
                     }
                 }
                 if ($tokens[$stackPtr + 1][1] === "\n") {
                     // This token's content has been merged into the previous,
                     // so we can skip it.
                     $tokens[$stackPtr + 1] = '';
                 } else {
                     $tokens[$stackPtr + 1][1] = substr($tokens[$stackPtr + 1][1], 1);
                 }
             }
         }
         //end if
         if (PHP_CODESNIFFER_VERBOSITY > 1) {
             echo PHP_EOL;
         }
         /*
             Parse doc blocks into something that can be easily iterated over.
         */
         if ($tokenIsArray === true && $token[0] === T_DOC_COMMENT) {
             $commentTokens = $commentTokenizer->tokenizeString($token[1], $eolChar, $newStackPtr);
             foreach ($commentTokens as $commentToken) {
                 $finalTokens[$newStackPtr] = $commentToken;
                 $newStackPtr++;
             }
             continue;
         }
         /*
             If this is a double quoted string, PHP will tokenize the whole
             thing which causes problems with the scope map when braces are
             within the string. So we need to merge the tokens together to
             provide a single string.
         */
         if ($tokenIsArray === false && ($token[0] === '"' || $token[0] === 'b"')) {
             // Binary casts need a special token.
             if ($token[0] === 'b"') {
                 $finalTokens[$newStackPtr] = array('code' => T_BINARY_CAST, 'type' => 'T_BINARY_CAST', 'content' => 'b');
                 $newStackPtr++;
             }
             $tokenContent = '"';
             $nestedVars = array();
             for ($i = $stackPtr + 1; $i < $numTokens; $i++) {
                 $subToken = (array) $tokens[$i];
                 $subTokenIsArray = isset($subToken[1]);
                 if ($subTokenIsArray === true) {
                     $tokenContent .= $subToken[1];
                     if ($subToken[1] === '{' && $subToken[0] !== T_ENCAPSED_AND_WHITESPACE) {
                         $nestedVars[] = $i;
                     }
                 } else {
                     $tokenContent .= $subToken[0];
                     if ($subToken[0] === '}') {
                         array_pop($nestedVars);
                     }
                 }
                 if ($subTokenIsArray === false && $subToken[0] === '"' && empty($nestedVars) === true) {
                     // We found the other end of the double quoted string.
                     break;
                 }
             }
             //end for
             $stackPtr = $i;
             // Convert each line within the double quoted string to a
             // new token, so it conforms with other multiple line tokens.
             $tokenLines = explode($eolChar, $tokenContent);
             $numLines = count($tokenLines);
             $newToken = array();
             for ($j = 0; $j < $numLines; $j++) {
                 $newToken['content'] = $tokenLines[$j];
                 if ($j === $numLines - 1) {
                     if ($tokenLines[$j] === '') {
                         break;
                     }
                 } else {
                     $newToken['content'] .= $eolChar;
                 }
                 $newToken['code'] = T_DOUBLE_QUOTED_STRING;
                 $newToken['type'] = 'T_DOUBLE_QUOTED_STRING';
                 $finalTokens[$newStackPtr] = $newToken;
                 $newStackPtr++;
             }
             // Continue, as we're done with this token.
             continue;
         }
         //end if
         /*
             If this is a heredoc, PHP will tokenize the whole
             thing which causes problems when heredocs don't
             contain real PHP code, which is almost never.
             We want to leave the start and end heredoc tokens
             alone though.
         */
         if ($tokenIsArray === true && $token[0] === T_START_HEREDOC) {
             // Add the start heredoc token to the final array.
             $finalTokens[$newStackPtr] = self::standardiseToken($token);
             // Check if this is actually a nowdoc and use a different token
             // to help the sniffs.
             $nowdoc = false;
             if ($token[1][3] === "'") {
                 $finalTokens[$newStackPtr]['code'] = T_START_NOWDOC;
                 $finalTokens[$newStackPtr]['type'] = 'T_START_NOWDOC';
                 $nowdoc = true;
             }
             $newStackPtr++;
             $tokenContent = '';
             for ($i = $stackPtr + 1; $i < $numTokens; $i++) {
                 $subTokenIsArray = is_array($tokens[$i]);
                 if ($subTokenIsArray === true && $tokens[$i][0] === T_END_HEREDOC) {
                     // We found the other end of the heredoc.
                     break;
                 }
                 if ($subTokenIsArray === true) {
                     $tokenContent .= $tokens[$i][1];
                 } else {
                     $tokenContent .= $tokens[$i];
                 }
             }
             $stackPtr = $i;
             // Convert each line within the heredoc to a
             // new token, so it conforms with other multiple line tokens.
             $tokenLines = explode($eolChar, $tokenContent);
             $numLines = count($tokenLines);
             $newToken = array();
             for ($j = 0; $j < $numLines; $j++) {
                 $newToken['content'] = $tokenLines[$j];
                 if ($j === $numLines - 1) {
                     if ($tokenLines[$j] === '') {
                         break;
                     }
                 } else {
                     $newToken['content'] .= $eolChar;
                 }
                 if ($nowdoc === true) {
                     $newToken['code'] = T_NOWDOC;
                     $newToken['type'] = 'T_NOWDOC';
                 } else {
                     $newToken['code'] = T_HEREDOC;
                     $newToken['type'] = 'T_HEREDOC';
                 }
                 $finalTokens[$newStackPtr] = $newToken;
                 $newStackPtr++;
             }
             //end for
             // Add the end heredoc token to the final array.
             $finalTokens[$newStackPtr] = self::standardiseToken($tokens[$stackPtr]);
             if ($nowdoc === true) {
                 $finalTokens[$newStackPtr]['code'] = T_END_NOWDOC;
                 $finalTokens[$newStackPtr]['type'] = 'T_END_NOWDOC';
                 $nowdoc = true;
             }
             $newStackPtr++;
             // Continue, as we're done with this token.
             continue;
         }
         //end if
         /*
             Before PHP 5.6, the ... operator was tokenized as three
             T_STRING_CONCAT tokens in a row. So look for and combine
             these tokens in earlier versions.
         */
         if ($tokenIsArray === false && $token[0] === '.' && isset($tokens[$stackPtr + 1]) === true && isset($tokens[$stackPtr + 2]) === true && $tokens[$stackPtr + 1] === '.' && $tokens[$stackPtr + 2] === '.') {
             $newToken = array();
             $newToken['code'] = T_ELLIPSIS;
             $newToken['type'] = 'T_ELLIPSIS';
             $newToken['content'] = '...';
             $finalTokens[$newStackPtr] = $newToken;
             $newStackPtr++;
             $stackPtr += 2;
             continue;
         }
         /*
             PHP doesn't assign a token to goto labels, so we have to.
             These are just string tokens with a single colon after them. Double
             colons are already tokenized and so don't interfere with this check.
             But we do have to account for CASE statements, that look just like
             goto labels.
         */
         if ($tokenIsArray === true && $token[0] === T_STRING && $tokens[$stackPtr + 1] === ':' && $tokens[$stackPtr - 1][0] !== T_PAAMAYIM_NEKUDOTAYIM) {
             $stopTokens = array(T_CASE => true, T_SEMICOLON => true, T_OPEN_CURLY_BRACKET => true, T_INLINE_THEN => true);
             for ($x = $newStackPtr - 1; $x > 0; $x--) {
                 if (isset($stopTokens[$finalTokens[$x]['code']]) === true) {
                     break;
                 }
             }
             if ($finalTokens[$x]['code'] !== T_CASE && $finalTokens[$x]['code'] !== T_INLINE_THEN) {
                 $finalTokens[$newStackPtr] = array('content' => $token[1] . ':', 'code' => T_GOTO_LABEL, 'type' => 'T_GOTO_LABEL');
                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
                     echo "\t\t* token {$stackPtr} changed from T_STRING to T_GOTO_LABEL" . PHP_EOL;
                     echo "\t\t* skipping T_COLON token " . ($stackPtr + 1) . PHP_EOL;
                 }
                 $newStackPtr++;
                 $stackPtr++;
                 continue;
             }
         }
         //end if
         /*
             HHVM 3.5 tokenizes "else[\s]+if" as a T_ELSEIF token while PHP
             proper only tokenizes "elseif" as a T_ELSEIF token. So split
             up the HHVM token to make it looks like proper PHP.
         */
         if ($tokenIsArray === true && $token[0] === T_ELSEIF && strtolower($token[1]) !== 'elseif') {
             $finalTokens[$newStackPtr] = array('content' => substr($token[1], 0, 4), 'code' => T_ELSE, 'type' => 'T_ELSE');
             $newStackPtr++;
             $finalTokens[$newStackPtr] = array('content' => substr($token[1], 4, -2), 'code' => T_WHITESPACE, 'type' => 'T_WHITESPACE');
             $newStackPtr++;
             $finalTokens[$newStackPtr] = array('content' => substr($token[1], -2), 'code' => T_IF, 'type' => 'T_IF');
             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                 echo "\t\t* token {$stackPtr} changed from T_ELSEIF to T_ELSE/T_WHITESPACE/T_IF" . PHP_EOL;
             }
             $newStackPtr++;
             continue;
         }
         //end if
         /*
             If this token has newlines in its content, split each line up
             and create a new token for each line. We do this so it's easier
             to ascertain where errors occur on a line.
             Note that $token[1] is the token's content.
         */
         if ($tokenIsArray === true && strpos($token[1], $eolChar) !== false) {
             $tokenLines = explode($eolChar, $token[1]);
             $numLines = count($tokenLines);
             $newToken = array('type' => token_name($token[0]), 'code' => $token[0], 'content' => '');
             for ($i = 0; $i < $numLines; $i++) {
                 $newToken['content'] = $tokenLines[$i];
                 if ($i === $numLines - 1) {
                     if ($tokenLines[$i] === '') {
                         break;
                     }
                 } else {
                     $newToken['content'] .= $eolChar;
                 }
                 $finalTokens[$newStackPtr] = $newToken;
                 $newStackPtr++;
             }
         } else {
             if ($tokenIsArray === true && $token[0] === T_STRING) {
                 // Some T_STRING tokens should remain that way
                 // due to their context.
                 $context = array(T_OBJECT_OPERATOR => true, T_FUNCTION => true, T_CLASS => true, T_EXTENDS => true, T_IMPLEMENTS => true, T_NEW => true, T_CONST => true, T_NS_SEPARATOR => true, T_USE => true, T_NAMESPACE => true, T_PAAMAYIM_NEKUDOTAYIM => true);
                 if (isset($context[$finalTokens[$lastNotEmptyToken]['code']]) === true) {
                     $finalTokens[$newStackPtr] = array('content' => $token[1], 'code' => T_STRING, 'type' => 'T_STRING');
                     $newStackPtr++;
                     continue;
                 }
             }
             //end if
             $newToken = null;
             if ($tokenIsArray === false) {
                 if (isset(self::$_resolveTokenCache[$token[0]]) === true) {
                     $newToken = self::$_resolveTokenCache[$token[0]];
                 }
             } else {
                 $cacheKey = null;
                 if ($token[0] === T_STRING) {
                     $cacheKey = strtolower($token[1]);
                 } else {
                     if ($token[0] !== T_CURLY_OPEN) {
                         $cacheKey = $token[0];
                     }
                 }
                 if ($cacheKey !== null && isset(self::$_resolveTokenCache[$cacheKey]) === true) {
                     $newToken = self::$_resolveTokenCache[$cacheKey];
                     $newToken['content'] = $token[1];
                 }
             }
             if ($newToken === null) {
                 $newToken = self::standardiseToken($token);
             }
             // Convert colons that are actually the ELSE component of an
             // inline IF statement.
             if ($newToken['code'] === T_INLINE_THEN) {
                 $insideInlineIf[] = $stackPtr;
             } else {
                 if (empty($insideInlineIf) === false && $newToken['code'] === T_COLON) {
                     array_pop($insideInlineIf);
                     $newToken['code'] = T_INLINE_ELSE;
                     $newToken['type'] = 'T_INLINE_ELSE';
                 }
             }
             // This is a special condition for T_ARRAY tokens used for
             // type hinting function arguments as being arrays. We want to keep
             // the parenthesis map clean, so let's tag these tokens as
             // T_ARRAY_HINT.
             if ($newToken['code'] === T_ARRAY) {
                 // Recalculate number of tokens.
                 for ($i = $stackPtr; $i < $numTokens; $i++) {
                     if ($tokens[$i] === '(') {
                         break;
                     } else {
                         if ($tokens[$i][0] === T_VARIABLE) {
                             $newToken['code'] = T_ARRAY_HINT;
                             $newToken['type'] = 'T_ARRAY_HINT';
                             break;
                         }
                     }
                 }
             }
             // This is a special case for the PHP 5.5 classname::class syntax
             // where "class" should be T_STRING instead of T_CLASS.
             if ($newToken['code'] === T_CLASS && $finalTokens[$newStackPtr - 1]['code'] === T_DOUBLE_COLON) {
                 $newToken['code'] = T_STRING;
                 $newToken['type'] = 'T_STRING';
             }
             // This is a special case for PHP 5.6 use function and use const
             // where "function" and "const" should be T_STRING instead of T_FUNCTION
             // and T_CONST.
             if (($newToken['code'] === T_FUNCTION || $newToken['code'] === T_CONST) && $finalTokens[$lastNotEmptyToken]['code'] === T_USE) {
                 $newToken['code'] = T_STRING;
                 $newToken['type'] = 'T_STRING';
             }
             $finalTokens[$newStackPtr] = $newToken;
             $newStackPtr++;
         }
         //end if
     }
     //end for
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t*** END PHP TOKENIZING ***" . PHP_EOL;
     }
     return $finalTokens;
 }
Example #3
0
 /**
  * Reverts the previous fix made to a token.
  *
  * @param int $stackPtr The position of the token in the token stack.
  *
  * @return bool If a change was reverted.
  */
 public function revertToken($stackPtr)
 {
     if (isset($this->_fixedTokens[$stackPtr]) === false) {
         return false;
     }
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         $bt = debug_backtrace();
         if ($bt[1]['class'] === 'PHP_CodeSniffer_Fixer') {
             $sniff = $bt[2]['class'];
             $line = $bt[1]['line'];
         } else {
             $sniff = $bt[1]['class'];
             $line = $bt[0]['line'];
         }
         $tokens = $this->_currentFile->getTokens();
         $type = $tokens[$stackPtr]['type'];
         $oldContent = PHP_CodeSniffer::prepareForOutput($this->_tokens[$stackPtr]);
         $newContent = PHP_CodeSniffer::prepareForOutput($this->_fixedTokens[$stackPtr]);
         if (trim($this->_tokens[$stackPtr]) === '' && isset($tokens[$stackPtr + 1]) === true) {
             // Add some context for whitespace only changes.
             $append = PHP_CodeSniffer::prepareForOutput($this->_tokens[$stackPtr + 1]);
             $oldContent .= $append;
             $newContent .= $append;
         }
     }
     //end if
     $this->_tokens[$stackPtr] = $this->_fixedTokens[$stackPtr];
     unset($this->_fixedTokens[$stackPtr]);
     $this->_numFixes--;
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         $indent = "\t";
         if (empty($this->_changeset) === false) {
             $indent .= "\tR: ";
         }
         @ob_end_clean();
         echo "{$indent}{$sniff} (line {$line}) reverted token {$stackPtr} ({$type}) \"{$oldContent}\" => \"{$newContent}\"" . PHP_EOL;
         ob_start();
     }
     return true;
 }
Example #4
0
 /**
  * Constructs the level map.
  *
  * The level map adds a 'level' index to each token which indicates the
  * depth that a token within a set of scope blocks. It also adds a
  * 'condition' index which is an array of the scope conditions that opened
  * each of the scopes - position 0 being the first scope opener.
  *
  * @param array  $tokens    The array of tokens to process.
  * @param object $tokenizer The tokenizer being used to process this file.
  * @param string $eolChar   The EOL character to use for splitting strings.
  *
  * @return void
  */
 private static function _createLevelMap(&$tokens, $tokenizer, $eolChar)
 {
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t*** START LEVEL MAP ***" . PHP_EOL;
     }
     $numTokens = count($tokens);
     $level = 0;
     $conditions = array();
     $lastOpener = null;
     $openers = array();
     for ($i = 0; $i < $numTokens; $i++) {
         if (PHP_CODESNIFFER_VERBOSITY > 1) {
             $type = $tokens[$i]['type'];
             $line = $tokens[$i]['line'];
             $len = $tokens[$i]['length'];
             $col = $tokens[$i]['column'];
             $content = PHP_CodeSniffer::prepareForOutput($tokens[$i]['content']);
             echo str_repeat("\t", $level + 1);
             echo "Process token {$i} on line {$line} [col:{$col};len:{$len};lvl:{$level};";
             if (empty($conditions) !== true) {
                 $condString = 'conds;';
                 foreach ($conditions as $condition) {
                     $condString .= token_name($condition) . ',';
                 }
                 echo rtrim($condString, ',') . ';';
             }
             echo "]: {$type} => {$content}" . PHP_EOL;
         }
         //end if
         $tokens[$i]['level'] = $level;
         $tokens[$i]['conditions'] = $conditions;
         if (isset($tokens[$i]['scope_condition']) === true) {
             // Check to see if this token opened the scope.
             if ($tokens[$i]['scope_opener'] === $i) {
                 $stackPtr = $tokens[$i]['scope_condition'];
                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
                     $type = $tokens[$stackPtr]['type'];
                     echo str_repeat("\t", $level + 1);
                     echo "=> Found scope opener for {$stackPtr}:{$type}" . PHP_EOL;
                 }
                 $stackPtr = $tokens[$i]['scope_condition'];
                 // If we find a scope opener that has a shared closer,
                 // then we need to go back over the condition map that we
                 // just created and fix ourselves as we just added some
                 // conditions where there was none. This happens for T_CASE
                 // statements that are using the same break statement.
                 if ($lastOpener !== null && $tokens[$lastOpener]['scope_closer'] === $tokens[$i]['scope_closer']) {
                     // This opener shares its closer with the previous opener,
                     // but we still need to check if the two openers share their
                     // closer with each other directly (like CASE and DEFAULT)
                     // or if they are just sharing because one doesn't have a
                     // closer (like CASE with no BREAK using a SWITCHes closer).
                     $thisType = $tokens[$tokens[$i]['scope_condition']]['code'];
                     $opener = $tokens[$lastOpener]['scope_condition'];
                     $isShared = isset($tokenizer->scopeOpeners[$thisType]['with'][$tokens[$opener]['code']]);
                     reset($tokenizer->scopeOpeners[$thisType]['end']);
                     reset($tokenizer->scopeOpeners[$tokens[$opener]['code']]['end']);
                     $sameEnd = current($tokenizer->scopeOpeners[$thisType]['end']) === current($tokenizer->scopeOpeners[$tokens[$opener]['code']]['end']);
                     if ($isShared === true && $sameEnd === true) {
                         $badToken = $opener;
                         if (PHP_CODESNIFFER_VERBOSITY > 1) {
                             $type = $tokens[$badToken]['type'];
                             echo str_repeat("\t", $level + 1);
                             echo "* shared closer, cleaning up {$badToken}:{$type} *" . PHP_EOL;
                         }
                         for ($x = $tokens[$i]['scope_condition']; $x <= $i; $x++) {
                             $oldConditions = $tokens[$x]['conditions'];
                             $oldLevel = $tokens[$x]['level'];
                             $tokens[$x]['level']--;
                             unset($tokens[$x]['conditions'][$badToken]);
                             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                                 $type = $tokens[$x]['type'];
                                 $oldConds = '';
                                 foreach ($oldConditions as $condition) {
                                     $oldConds .= token_name($condition) . ',';
                                 }
                                 $oldConds = rtrim($oldConds, ',');
                                 $newConds = '';
                                 foreach ($tokens[$x]['conditions'] as $condition) {
                                     $newConds .= token_name($condition) . ',';
                                 }
                                 $newConds = rtrim($newConds, ',');
                                 $newLevel = $tokens[$x]['level'];
                                 echo str_repeat("\t", $level + 1);
                                 echo "* cleaned {$x}:{$type} *" . PHP_EOL;
                                 echo str_repeat("\t", $level + 2);
                                 echo "=> level changed from {$oldLevel} to {$newLevel}" . PHP_EOL;
                                 echo str_repeat("\t", $level + 2);
                                 echo "=> conditions changed from {$oldConds} to {$newConds}" . PHP_EOL;
                             }
                             //end if
                         }
                         //end for
                         unset($conditions[$badToken]);
                         if (PHP_CODESNIFFER_VERBOSITY > 1) {
                             $type = $tokens[$badToken]['type'];
                             echo str_repeat("\t", $level + 1);
                             echo "* token {$badToken}:{$type} removed from conditions array *" . PHP_EOL;
                         }
                         unset($openers[$lastOpener]);
                         $level--;
                         if (PHP_CODESNIFFER_VERBOSITY > 1) {
                             echo str_repeat("\t", $level + 2);
                             echo '* level decreased *' . PHP_EOL;
                         }
                     }
                     //end if
                 }
                 //end if
                 $level++;
                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
                     echo str_repeat("\t", $level + 1);
                     echo '* level increased *' . PHP_EOL;
                 }
                 $conditions[$stackPtr] = $tokens[$stackPtr]['code'];
                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
                     $type = $tokens[$stackPtr]['type'];
                     echo str_repeat("\t", $level + 1);
                     echo "* token {$stackPtr}:{$type} added to conditions array *" . PHP_EOL;
                 }
                 $lastOpener = $tokens[$i]['scope_opener'];
                 if ($lastOpener !== null) {
                     $openers[$lastOpener] = $lastOpener;
                 }
             } else {
                 if ($lastOpener !== null && $tokens[$lastOpener]['scope_closer'] === $i) {
                     foreach (array_reverse($openers) as $opener) {
                         if ($tokens[$opener]['scope_closer'] === $i) {
                             $oldOpener = array_pop($openers);
                             if (empty($openers) === false) {
                                 $lastOpener = array_pop($openers);
                                 $openers[$lastOpener] = $lastOpener;
                             } else {
                                 $lastOpener = null;
                             }
                             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                                 $type = $tokens[$oldOpener]['type'];
                                 echo str_repeat("\t", $level + 1);
                                 echo "=> Found scope closer for {$oldOpener}:{$type}" . PHP_EOL;
                             }
                             $oldCondition = array_pop($conditions);
                             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                                 echo str_repeat("\t", $level + 1);
                                 echo '* token ' . token_name($oldCondition) . ' removed from conditions array *' . PHP_EOL;
                             }
                             // Make sure this closer actually belongs to us.
                             // Either the condition also has to think this is the
                             // closer, or it has to allow sharing with us.
                             $condition = $tokens[$tokens[$i]['scope_condition']]['code'];
                             if ($condition !== $oldCondition) {
                                 if (isset($tokenizer->scopeOpeners[$oldCondition]['with'][$condition]) === false) {
                                     $badToken = $tokens[$oldOpener]['scope_condition'];
                                     if (PHP_CODESNIFFER_VERBOSITY > 1) {
                                         $type = token_name($oldCondition);
                                         echo str_repeat("\t", $level + 1);
                                         echo "* scope closer was bad, cleaning up {$badToken}:{$type} *" . PHP_EOL;
                                     }
                                     for ($x = $oldOpener + 1; $x <= $i; $x++) {
                                         $oldConditions = $tokens[$x]['conditions'];
                                         $oldLevel = $tokens[$x]['level'];
                                         $tokens[$x]['level']--;
                                         unset($tokens[$x]['conditions'][$badToken]);
                                         if (PHP_CODESNIFFER_VERBOSITY > 1) {
                                             $type = $tokens[$x]['type'];
                                             $oldConds = '';
                                             foreach ($oldConditions as $condition) {
                                                 $oldConds .= token_name($condition) . ',';
                                             }
                                             $oldConds = rtrim($oldConds, ',');
                                             $newConds = '';
                                             foreach ($tokens[$x]['conditions'] as $condition) {
                                                 $newConds .= token_name($condition) . ',';
                                             }
                                             $newConds = rtrim($newConds, ',');
                                             $newLevel = $tokens[$x]['level'];
                                             echo str_repeat("\t", $level + 1);
                                             echo "* cleaned {$x}:{$type} *" . PHP_EOL;
                                             echo str_repeat("\t", $level + 2);
                                             echo "=> level changed from {$oldLevel} to {$newLevel}" . PHP_EOL;
                                             echo str_repeat("\t", $level + 2);
                                             echo "=> conditions changed from {$oldConds} to {$newConds}" . PHP_EOL;
                                         }
                                         //end if
                                     }
                                     //end for
                                 }
                                 //end if
                             }
                             //end if
                             $level--;
                             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                                 echo str_repeat("\t", $level + 2);
                                 echo '* level decreased *' . PHP_EOL;
                             }
                             $tokens[$i]['level'] = $level;
                             $tokens[$i]['conditions'] = $conditions;
                         }
                         //end if
                     }
                     //end foreach
                 }
             }
             //end if
         }
         //end if
     }
     //end for
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t*** END LEVEL MAP ***" . PHP_EOL;
     }
 }
Example #5
0
 /**
  * Performs additional processing after main tokenizing.
  *
  * This additional processing looks for properties, closures, labels and objects.
  *
  * @param array  $tokens  The array of tokens to process.
  * @param string $eolChar The EOL character to use for splitting strings.
  *
  * @return void
  */
 public function processAdditional(&$tokens, $eolChar)
 {
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t*** START ADDITIONAL JS PROCESSING ***" . PHP_EOL;
     }
     $numTokens = count($tokens);
     $classStack = array();
     for ($i = 0; $i < $numTokens; $i++) {
         if (PHP_CODESNIFFER_VERBOSITY > 1) {
             $type = $tokens[$i]['type'];
             $content = PHP_CodeSniffer::prepareForOutput($tokens[$i]['content']);
             echo str_repeat("\t", count($classStack));
             echo "\tProcess token {$i}: {$type} => {$content}" . PHP_EOL;
         }
         // Looking for functions that are actually closures.
         if ($tokens[$i]['code'] === T_FUNCTION && isset($tokens[$i]['scope_opener']) === true) {
             for ($x = $i + 1; $x < $numTokens; $x++) {
                 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
                     break;
                 }
             }
             if ($tokens[$x]['code'] === T_OPEN_PARENTHESIS) {
                 $tokens[$i]['code'] = T_CLOSURE;
                 $tokens[$i]['type'] = 'T_CLOSURE';
                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
                     $line = $tokens[$i]['line'];
                     echo str_repeat("\t", count($classStack));
                     echo "\t* token {$i} on line {$line} changed from T_FUNCTION to T_CLOSURE" . PHP_EOL;
                 }
                 for ($x = $tokens[$i]['scope_opener'] + 1; $x < $tokens[$i]['scope_closer']; $x++) {
                     if (isset($tokens[$x]['conditions'][$i]) === false) {
                         continue;
                     }
                     $tokens[$x]['conditions'][$i] = T_CLOSURE;
                     if (PHP_CODESNIFFER_VERBOSITY > 1) {
                         $type = $tokens[$x]['type'];
                         echo str_repeat("\t", count($classStack));
                         echo "\t\t* cleaned {$x} ({$type}) *" . PHP_EOL;
                     }
                 }
             }
             //end if
             continue;
         } else {
             if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET && isset($tokens[$i]['scope_condition']) === false) {
                 $classStack[] = $i;
                 $closer = $tokens[$i]['bracket_closer'];
                 $tokens[$i]['code'] = T_OBJECT;
                 $tokens[$i]['type'] = 'T_OBJECT';
                 $tokens[$closer]['code'] = T_CLOSE_OBJECT;
                 $tokens[$closer]['type'] = 'T_CLOSE_OBJECT';
                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
                     echo str_repeat("\t", count($classStack));
                     echo "\t* token {$i} converted from T_OPEN_CURLY_BRACKET to T_OBJECT *" . PHP_EOL;
                     echo str_repeat("\t", count($classStack));
                     echo "\t* token {$closer} converted from T_CLOSE_CURLY_BRACKET to T_CLOSE_OBJECT *" . PHP_EOL;
                 }
                 for ($x = $i + 1; $x < $closer; $x++) {
                     $tokens[$x]['conditions'][$i] = T_OBJECT;
                     ksort($tokens[$x]['conditions'], SORT_NUMERIC);
                     if (PHP_CODESNIFFER_VERBOSITY > 1) {
                         $type = $tokens[$x]['type'];
                         echo str_repeat("\t", count($classStack));
                         echo "\t\t* added T_OBJECT condition to {$x} ({$type}) *" . PHP_EOL;
                     }
                 }
             } else {
                 if ($tokens[$i]['code'] === T_CLOSE_OBJECT) {
                     $opener = array_pop($classStack);
                 } else {
                     if ($tokens[$i]['code'] === T_COLON) {
                         // If it is a scope opener, it belongs to a
                         // DEFAULT or CASE statement.
                         if (isset($tokens[$i]['scope_condition']) === true) {
                             continue;
                         }
                         // Make sure this is not part of an inline IF statement.
                         for ($x = $i - 1; $x >= 0; $x--) {
                             if ($tokens[$x]['code'] === T_INLINE_THEN) {
                                 $tokens[$i]['code'] = T_INLINE_ELSE;
                                 $tokens[$i]['type'] = 'T_INLINE_ELSE';
                                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
                                     echo str_repeat("\t", count($classStack));
                                     echo "\t* token {$i} converted from T_COLON to T_INLINE_THEN *" . PHP_EOL;
                                 }
                                 continue 2;
                             } else {
                                 if ($tokens[$x]['line'] < $tokens[$i]['line']) {
                                     break;
                                 }
                             }
                         }
                         // The string to the left of the colon is either a property or label.
                         for ($label = $i - 1; $label >= 0; $label--) {
                             if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$label]['code']]) === false) {
                                 break;
                             }
                         }
                         if ($tokens[$label]['code'] !== T_STRING && $tokens[$label]['code'] !== T_CONSTANT_ENCAPSED_STRING) {
                             continue;
                         }
                         if (empty($classStack) === false) {
                             $tokens[$label]['code'] = T_PROPERTY;
                             $tokens[$label]['type'] = 'T_PROPERTY';
                             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                                 echo str_repeat("\t", count($classStack));
                                 echo "\t* token {$label} converted from T_STRING to T_PROPERTY *" . PHP_EOL;
                             }
                         } else {
                             $tokens[$label]['code'] = T_LABEL;
                             $tokens[$label]['type'] = 'T_LABEL';
                             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                                 echo str_repeat("\t", count($classStack));
                                 echo "\t* token {$label} converted from T_STRING to T_LABEL *" . PHP_EOL;
                             }
                         }
                         //end if
                     }
                 }
             }
         }
         //end if
     }
     //end for
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t*** END ADDITIONAL JS PROCESSING ***" . PHP_EOL;
     }
 }
Example #6
0
 /**
  * Replace the entire contents of a token.
  *
  * @param int    $stackPtr The position of the token in the token stack.
  * @param string $content  The new content of the token.
  *
  * @return bool If the change was accepted.
  */
 public function replaceToken($stackPtr, $content)
 {
     if ($this->_inChangeset === false && isset($this->_fixedTokens[$stackPtr]) === true) {
         if (PHP_CODESNIFFER_VERBOSITY > 1) {
             @ob_end_clean();
             echo "\t* token {$stackPtr} has already been modified, skipping *" . PHP_EOL;
             ob_start();
         }
         return false;
     }
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         $bt = debug_backtrace();
         if ($bt[1]['class'] === 'PHP_CodeSniffer_Fixer') {
             $sniff = $bt[2]['class'];
             $line = $bt[1]['line'];
         } else {
             $sniff = $bt[1]['class'];
             $line = $bt[0]['line'];
         }
         $tokens = $this->_currentFile->getTokens();
         $type = $tokens[$stackPtr]['type'];
         $oldContent = PHP_CodeSniffer::prepareForOutput($tokens[$stackPtr]['content']);
         $newContent = PHP_CodeSniffer::prepareForOutput($content);
         if (trim($tokens[$stackPtr]['content']) === '' && isset($tokens[$stackPtr + 1]) === true) {
             // Add some context for whitespace only changes.
             $append = PHP_CodeSniffer::prepareForOutput($tokens[$stackPtr + 1]['content']);
             $oldContent .= $append;
             $newContent .= $append;
         }
     }
     //end if
     if ($this->_inChangeset === true) {
         $this->_changeset[$stackPtr] = $content;
         if (PHP_CODESNIFFER_VERBOSITY > 1) {
             @ob_end_clean();
             echo "\t\tQ: {$sniff} (line {$line}) replaced token {$stackPtr} ({$type}) \"{$oldContent}\" => \"{$newContent}\"" . PHP_EOL;
             ob_start();
         }
         return true;
     }
     if (isset($this->_oldTokenValues[$stackPtr]) === false) {
         $this->_oldTokenValues[$stackPtr] = array(1 => $content, 2 => $this->_tokens[$stackPtr]);
     } else {
         if ($this->_oldTokenValues[$stackPtr][2] === $content) {
             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                 $indent = "\t";
                 if (empty($this->_changeset) === false) {
                     $indent .= "\t";
                 }
                 @ob_end_clean();
                 echo "{$indent}**** {$sniff} (line {$line}) has possible conflict with another sniff; ignoring change ****" . PHP_EOL;
                 ob_start();
             }
             return false;
         }
         $this->_oldTokenValues[$stackPtr][2] = $this->_oldTokenValues[$stackPtr][1];
         $this->_oldTokenValues[$stackPtr][1] = $content;
     }
     //end if
     $this->_tokens[$stackPtr] = $content;
     $this->_numFixes++;
     $this->_fixedTokens[$stackPtr] = true;
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         $indent = "\t";
         if (empty($this->_changeset) === false) {
             $indent .= "\tA: ";
         }
         @ob_end_clean();
         echo "{$indent}{$sniff} (line {$line}) replaced token {$stackPtr} ({$type}) \"{$oldContent}\" => \"{$newContent}\"" . PHP_EOL;
         ob_start();
     }
     return true;
 }
Example #7
0
 /**
  * Creates an array of tokens when given some PHP code.
  *
  * Starts by using token_get_all() but does a lot of extra processing
  * to insert information about the context of the token.
  *
  * @param string $string   The string to tokenize.
  * @param string $eolChar  The EOL character to use for splitting strings.
  * @param int    $stackPtr The position of the first token in the file.
  *
  * @return array
  */
 public function tokenizeString($string, $eolChar, $stackPtr)
 {
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t\t*** START COMMENT TOKENIZING ***" . PHP_EOL;
     }
     $tokens = array();
     $numChars = strlen($string);
     /*
         Doc block comments start with /*, but typically contain an
         extra star when they are used for function and class comments.
     */
     for ($c = 0; $c < $numChars; $c++) {
         if ($string[$c] !== '/' && $string[$c] !== '*') {
             break;
         }
     }
     $openTag = substr($string, 0, $c);
     $tokens[$stackPtr] = array('content' => $openTag, 'code' => T_DOC_COMMENT_OPEN_TAG, 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'comment_tags' => array());
     $openPtr = $stackPtr;
     $stackPtr++;
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         $content = PHP_CodeSniffer::prepareForOutput($openTag);
         echo "\t\tCreate comment token: T_DOC_COMMENT_OPEN_TAG => {$content}" . PHP_EOL;
     }
     /*
         Strip off the close tag so it doesn't interfere with any
         of our comment line processing. The token will be added to the
         stack just before we return it.
     */
     for ($i = $numChars - 1; $i > $c; $i--) {
         if ($string[$i] !== '/' && $string[$i] !== '*') {
             break;
         }
     }
     $i++;
     $closeTag = array('content' => substr($string, $i), 'code' => T_DOC_COMMENT_CLOSE_TAG, 'type' => 'T_DOC_COMMENT_CLOSE_TAG', 'comment_opener' => $openPtr);
     $string = substr($string, 0, $i);
     $numChars = strlen($string);
     /*
         Process each line of the comment.
     */
     while ($c < $numChars) {
         $lineTokens = $this->_processLine($string, $eolChar, $c, $numChars);
         foreach ($lineTokens as $lineToken) {
             $tokens[$stackPtr] = $lineToken;
             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                 $content = PHP_CodeSniffer::prepareForOutput($lineToken['content']);
                 $type = $lineToken['type'];
                 echo "\t\tCreate comment token: {$type} => {$content}" . PHP_EOL;
             }
             if ($lineToken['code'] === T_DOC_COMMENT_TAG) {
                 $tokens[$openPtr]['comment_tags'][] = $stackPtr;
             }
             $c += strlen($lineToken['content']);
             $stackPtr++;
         }
         if ($c === $numChars) {
             break;
         }
         // We've started a new line, so process the indent.
         $space = $this->_collectWhitespace($string, $c, $numChars);
         if ($space !== null) {
             $tokens[$stackPtr] = $space;
             $stackPtr++;
             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                 $content = PHP_CodeSniffer::prepareForOutput($space['content']);
                 $type = $lineToken['type'];
                 echo "\t\tCreate comment token: T_DOC_COMMENT_WHITESPACE => {$content}" . PHP_EOL;
             }
             $c += strlen($space['content']);
             if ($c === $numChars) {
                 break;
             }
         }
         if ($string[$c] === '*') {
             // This is a function or class doc block line.
             $c++;
             $tokens[$stackPtr] = array('content' => '*', 'code' => T_DOC_COMMENT_STAR, 'type' => 'T_DOC_COMMENT_STAR');
             $stackPtr++;
             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                 echo "\t\tCreate comment token: T_DOC_COMMENT_STAR => *" . PHP_EOL;
             }
         }
         // Now we are ready to process the actual content of the line.
         // So round we go.
     }
     //end while
     $tokens[$stackPtr] = $closeTag;
     $tokens[$openPtr]['comment_closer'] = $stackPtr;
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         $content = PHP_CodeSniffer::prepareForOutput($closeTag['content']);
         echo "\t\tCreate comment token: T_DOC_COMMENT_CLOSE_TAG => {$content}" . PHP_EOL;
     }
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t\t*** END COMMENT TOKENIZING ***" . PHP_EOL;
     }
     return $tokens;
 }
Example #8
0
 /**
  * Performs additional processing after main tokenizing.
  *
  * This additional processing looks for properties, labels and objects.
  *
  * @param array  $tokens  The array of tokens to process.
  * @param string $eolChar The EOL character to use for splitting strings.
  *
  * @return void
  */
 public function processAdditional(&$tokens, $eolChar)
 {
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t*** START ADDITIONAL JS PROCESSING ***" . PHP_EOL;
     }
     $numTokens = count($tokens);
     $classStack = array();
     for ($i = 0; $i < $numTokens; $i++) {
         if (PHP_CODESNIFFER_VERBOSITY > 1) {
             $type = $tokens[$i]['type'];
             $content = PHP_CodeSniffer::prepareForOutput($tokens[$i]['content']);
             echo str_repeat("\t", count($classStack));
             echo "\tProcess token {$i}: {$type} => {$content}" . PHP_EOL;
         }
         if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET && isset($tokens[$i]['scope_condition']) === false) {
             $classStack[] = $i;
             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                 echo str_repeat("\t", count($classStack));
                 echo "\t=> Found property opener" . PHP_EOL;
             }
             // This could also be an object definition.
             for ($x = $i - 1; $x >= 0; $x--) {
                 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
                     // Non-whitespace content.
                     break;
                 }
             }
             if ($tokens[$x]['code'] === T_EQUAL) {
                 for ($x--; $x >= 0; $x--) {
                     if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
                         break;
                     }
                 }
                 if ($tokens[$x]['code'] === T_STRING || $tokens[$x]['code'] === T_PROTOTYPE) {
                     // Find the first string in this definition.
                     // E.g., WantedString.DontWantThis.prototype.
                     for ($x--; $x >= 0; $x--) {
                         if ($tokens[$x]['code'] !== T_STRING && $tokens[$x]['code'] !== T_PROTOTYPE && $tokens[$x]['code'] !== T_OBJECT_OPERATOR) {
                             $x++;
                             break;
                         }
                     }
                     $closer = $tokens[$i]['bracket_closer'];
                     $tokens[$i]['scope_condition'] = $x;
                     $tokens[$i]['scope_closer'] = $closer;
                     $tokens[$closer]['scope_condition'] = $x;
                     $tokens[$closer]['scope_opener'] = $i;
                     $tokens[$x]['scope_opener'] = $i;
                     $tokens[$x]['scope_closer'] = $closer;
                     $tokens[$x]['code'] = T_OBJECT;
                     $tokens[$x]['type'] = 'T_OBJECT';
                     if (PHP_CODESNIFFER_VERBOSITY > 1) {
                         echo str_repeat("\t", count($classStack));
                         echo "\t* token {$x} converted from T_STRING to T_OBJECT *" . PHP_EOL;
                         echo str_repeat("\t", count($classStack));
                         echo "\t* set scope opener ({$i}) and closer ({$closer}) for token {$x} *" . PHP_EOL;
                     }
                 }
                 //end if
             }
             //end if
         } else {
             if ($tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET && (isset($tokens[$i]['scope_condition']) === false || $tokens[$tokens[$i]['scope_condition']]['code'] === T_OBJECT)) {
                 $opener = array_pop($classStack);
                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
                     echo str_repeat("\t", count($classStack));
                     echo "\t\t=> Found property closer for {$opener}" . PHP_EOL;
                 }
             } else {
                 if ($tokens[$i]['code'] === T_COLON) {
                     // If it is a scope opener, it belongs to a
                     // DEFAULT or CASE statement.
                     if (isset($tokens[$i]['scope_condition']) === true) {
                         continue;
                     }
                     // Make sure this is not part of an inline IF statement.
                     for ($x = $i - 1; $x >= 0; $x--) {
                         if ($tokens[$x]['code'] === T_INLINE_THEN) {
                             $tokens[$i]['code'] = T_INLINE_ELSE;
                             $tokens[$i]['type'] = 'T_INLINE_ELSE';
                             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                                 echo str_repeat("\t", count($classStack));
                                 echo "\t* token {$i} converted from T_COLON to T_INLINE_THEN *" . PHP_EOL;
                             }
                             continue 2;
                         } else {
                             if ($tokens[$x]['line'] < $tokens[$i]['line']) {
                                 break;
                             }
                         }
                     }
                     // The string to the left of the colon is either a property or label.
                     for ($label = $i - 1; $label >= 0; $label--) {
                         if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$label]['code']]) === false) {
                             break;
                         }
                     }
                     if ($tokens[$label]['code'] !== T_STRING) {
                         continue;
                     }
                     if (empty($classStack) === false) {
                         $tokens[$label]['code'] = T_PROPERTY;
                         $tokens[$label]['type'] = 'T_PROPERTY';
                         if (PHP_CODESNIFFER_VERBOSITY > 1) {
                             echo str_repeat("\t", count($classStack));
                             echo "\t* token {$label} converted from T_STRING to T_PROPERTY *" . PHP_EOL;
                         }
                         // If the net token after the colon is a curly brace,
                         // this property is actually an object, so we can give it
                         // and opener and closer.
                         for ($x = $i + 1; $x < $numTokens; $x++) {
                             if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
                                 break;
                             }
                         }
                         if ($tokens[$x]['code'] === T_OPEN_CURLY_BRACKET) {
                             $closer = $tokens[$x]['bracket_closer'];
                             $tokens[$label]['scope_opener'] = $x;
                             $tokens[$label]['scope_closer'] = $closer;
                             $tokens[$x]['scope_condition'] = $label;
                             $tokens[$x]['scope_closer'] = $closer;
                             $tokens[$closer]['scope_condition'] = $label;
                             $tokens[$closer]['scope_opener'] = $x;
                             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                                 echo str_repeat("\t", count($classStack));
                                 echo "\t* set scope opener ({$x}) and closer ({$closer}) for token {$label} *" . PHP_EOL;
                             }
                         }
                     } else {
                         $tokens[$label]['code'] = T_LABEL;
                         $tokens[$label]['type'] = 'T_LABEL';
                         if (PHP_CODESNIFFER_VERBOSITY > 1) {
                             echo str_repeat("\t", count($classStack));
                             echo "\t* token {$label} converted from T_STRING to T_LABEL *" . PHP_EOL;
                         }
                     }
                     //end if
                 }
             }
         }
         //end if
     }
     //end for
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         echo "\t*** END ADDITIONAL JS PROCESSING ***" . PHP_EOL;
     }
 }