1<?php 2/** 3 * Ensures that values submitted via JS are not compared to NULL. 4 * 5 * PHP version 5 6 * 7 * @category PHP 8 * @package PHP_CodeSniffer_MySource 9 * @author Greg Sherwood <gsherwood@squiz.net> 10 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 11 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 12 * @link http://pear.php.net/package/PHP_CodeSniffer 13 */ 14 15/** 16 * Ensures that values submitted via JS are not compared to NULL. 17 * 18 * With jQuery 1.8, the behaviour of ajax requests changed so that null values are 19 * submitted as null= instead of null=null. 20 * 21 * @category PHP 22 * @package PHP_CodeSniffer_MySource 23 * @author Greg Sherwood <gsherwood@squiz.net> 24 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 25 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 26 * @version Release: @package_version@ 27 * @link http://pear.php.net/package/PHP_CodeSniffer 28 */ 29class MySource_Sniffs_PHP_AjaxNullComparisonSniff implements PHP_CodeSniffer_Sniff 30{ 31 32 33 /** 34 * Returns an array of tokens this test wants to listen for. 35 * 36 * @return array 37 */ 38 public function register() 39 { 40 return array(T_FUNCTION); 41 42 }//end register() 43 44 45 /** 46 * Processes this sniff, when one of its tokens is encountered. 47 * 48 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 49 * @param int $stackPtr The position of the current token in 50 * the stack passed in $tokens. 51 * 52 * @return void 53 */ 54 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 55 { 56 $tokens = $phpcsFile->getTokens(); 57 58 // Make sure it is an API function. We know this by the doc comment. 59 $commentEnd = $phpcsFile->findPrevious(T_DOC_COMMENT_CLOSE_TAG, $stackPtr); 60 $commentStart = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, ($commentEnd - 1)); 61 $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart)); 62 if (strpos($comment, '* @api') === false) { 63 return; 64 } 65 66 // Find all the vars passed in as we are only interested in comparisons 67 // to NULL for these specific variables. 68 $foundVars = array(); 69 $open = $tokens[$stackPtr]['parenthesis_opener']; 70 $close = $tokens[$stackPtr]['parenthesis_closer']; 71 for ($i = ($open + 1); $i < $close; $i++) { 72 if ($tokens[$i]['code'] === T_VARIABLE) { 73 $foundVars[$tokens[$i]['content']] = true; 74 } 75 } 76 77 if (empty($foundVars) === true) { 78 return; 79 } 80 81 $start = $tokens[$stackPtr]['scope_opener']; 82 $end = $tokens[$stackPtr]['scope_closer']; 83 for ($i = ($start + 1); $i < $end; $i++) { 84 if ($tokens[$i]['code'] !== T_VARIABLE 85 || isset($foundVars[$tokens[$i]['content']]) === false 86 ) { 87 continue; 88 } 89 90 $operator = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true); 91 if ($tokens[$operator]['code'] !== T_IS_IDENTICAL 92 && $tokens[$operator]['code'] !== T_IS_NOT_IDENTICAL 93 ) { 94 continue; 95 } 96 97 $nullValue = $phpcsFile->findNext(T_WHITESPACE, ($operator + 1), null, true); 98 if ($tokens[$nullValue]['code'] !== T_NULL) { 99 continue; 100 } 101 102 $error = 'Values submitted via Ajax requests should not be compared directly to NULL; use empty() instead'; 103 $phpcsFile->addWarning($error, $nullValue, 'Found'); 104 }//end for 105 106 }//end process() 107 108 109}//end class 110