diff --git a/Sniffs/VIP/ValidatedSanitizedInputSniff.php b/Sniffs/VIP/ValidatedSanitizedInputSniff.php new file mode 100644 index 0000000000..5599c6e5fe --- /dev/null +++ b/Sniffs/VIP/ValidatedSanitizedInputSniff.php @@ -0,0 +1,143 @@ + + * @link https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/issues/69 + */ +class WordPress_Sniffs_VIP_ValidatedSanitizedInputSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_VARIABLE, + ); + + }//end register() + + + /** + * 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(); + + // Check for $wpdb variable + if ( ! in_array( $tokens[$stackPtr]['content'], array( '$_GET', '$_POST', '$_REQUEST', '$_SERVER' ) ) ) + return; + + $instance = $tokens[$stackPtr]; + $varName = $instance['content']; + + $nested = $instance['nested_parenthesis']; + + // Ignore if wrapped inside ISSET + end( $nested ); // Get closest parenthesis + if ( in_array( $tokens[ key( $nested ) - 1 ]['code'], array( T_ISSET, T_EMPTY ) ) ) + return; + + $varKey = $this->getArrayIndexKey( $phpcsFile, $tokens, $stackPtr ); + + if ( empty( $varKey ) ) { + $phpcsFile->addWarning( 'Detected access of super global var %s without targeting a member variable.', $stackPtr, null, array( $varName ) ); + return; + } + + // Check for validation first + $is_validated = false; + + // Wrapped in a condition? check existence of isset with the variable as an argument + if ( ! empty( $tokens[$stackPtr]['conditions'] ) ) { + $conditionPtr = key( $tokens[$stackPtr]['conditions'] ); + $condition = $tokens[$conditionPtr]; + + $issetPtr = $phpcsFile->findNext( array( T_ISSET, T_EMPTY ), $condition['parenthesis_opener'], $condition['parenthesis_closer'] ); + if ( ! empty( $issetPtr ) ) { + $isset = $tokens[$issetPtr]; + $issetOpener = $issetPtr + 1; + $issetCloser = $tokens[$issetOpener]['parenthesis_closer']; + + // Check that it is the same variable name + if ( $validated = $phpcsFile->findNext( array( T_VARIABLE ), $issetOpener, $issetCloser, null, $varName ) ) { + // Double check the $varKey inside the variable, ex: 'hello' in $_POST['hello'] + + $varKeyValidated = $this->getArrayIndexKey( $phpcsFile, $tokens, $validated ); + + if ( $varKeyValidated == $varKey ) { + // everything matches, variable IS validated afterall .. + $is_validated = true; + } + } + } + } + + if ( ! $is_validated ) { + $phpcsFile->addError( 'Detected usage of a non-validated input variable: %s', $stackPtr, null, array( $tokens[$stackPtr]['content'] ) ); + // return; // Should we just return and not look for sanitizing functions ? + } + + // Now look for sanitizing functions + $is_sanitized = false; + + $functionPtr = key( $nested ) - 1; + $function = $tokens[$functionPtr]; + if ( T_STRING === $function['code'] ) { + $functionName = $function['content']; + if ( + in_array( $functionName, WordPress_Sniffs_XSS_EscapeOutputSniff::$autoEscapedFunctions ) + || + in_array( $functionName, WordPress_Sniffs_XSS_EscapeOutputSniff::$sanitizingFunctions ) + ) { + $is_sanitized = true; + } + } + + if ( ! $is_sanitized ) { + $phpcsFile->addError( 'Detected usage of a non-sanitized input variable: %s', $stackPtr, null, array( $tokens[$stackPtr]['content'] ) ); + } + + + return; + }//end process() + + /** + * Get array index key of the variable requested + * @param [type] $phpcsFile [description] + * @param [type] $tokens [description] + * @param [type] $stackPtr [description] + * @return [type] [description] + */ + public function getArrayIndexKey( $phpcsFile, $tokens, $stackPtr ) { + // Find next bracket + $bracketOpener = $phpcsFile->findNext( array( T_OPEN_SQUARE_BRACKET ), $stackPtr, $stackPtr + 3 ); + + // If no brackets, exit with a warning, this is a non-typical usage of super globals + if ( empty ( $bracketOpener ) ) { + return false; + } + + $bracketCloser = $tokens[$bracketOpener]['bracket_closer']; + + $varKey = trim( $phpcsFile->getTokensAsString( $bracketOpener + 1, $bracketCloser - $bracketOpener - 1 ) ); // aka 'hello' in $_POST['hello'] + + return $varKey; + } + +}//end class diff --git a/Sniffs/XSS/EscapeOutputSniff.php b/Sniffs/XSS/EscapeOutputSniff.php index 033820455e..5fdb569fbb 100644 --- a/Sniffs/XSS/EscapeOutputSniff.php +++ b/Sniffs/XSS/EscapeOutputSniff.php @@ -20,375 +20,375 @@ class WordPress_Sniffs_XSS_EscapeOutputSniff implements PHP_CodeSniffer_Sniff { - public $autoEscapedFunctions = array( - 'get_header', - 'get_footer', - 'get_sidebar', - 'get_template_part', - 'get_search_form', - 'wp_loginout', - 'wp_logout_url', - 'wp_login_url', - 'wp_login_form', - 'wp_lostpassword_url', - 'wp_register', - 'wp_meta', - 'bloginfo', - 'get_bloginfo', - 'get_current_blog_id', - 'wp_title', - 'single_post_title', - 'post_type_archive_title', - 'single_cat_title', - 'single_tag_title', - 'single_term_title', - 'single_month_title', - 'get_archives_link', - 'wp_get_archives', - 'calendar_week_mod', - 'get_calendar', - 'delete_get_calendar_cache', - 'allowed_tags', - 'wp_enqueue_script', - 'the_author', - 'get_the_author', - 'the_author_link', - 'get_the_author_link', - 'the_author_meta', - 'the_author_posts', - 'the_author_posts_link', - 'wp_dropdown_users', - 'wp_list_authors', - 'get_author_posts_url', - 'wp_list_bookmarks', - 'get_bookmark', - 'get_bookmark_field', - 'get_bookmarks', - 'category_description', - 'single_cat_title', - 'the_category', - 'the_category_rss', - 'wp_dropdown_categories', - 'wp_list_categories', - 'single_tag_title', - 'tag_description', - 'the_tags', - 'wp_generate_tag_cloud', - 'wp_tag_cloud', - 'term_description', - 'single_term_title', - 'get_the_term_list', - 'the_terms', - 'the_taxonomies', - 'cancel_comment_reply_link', - 'comment_author', - 'comment_author_email', - 'comment_author_email_link', - 'comment_author_IP', - 'comment_author_link', - 'comment_author_rss', - 'comment_author_url', - 'comment_author_url_link', - 'comment_class', - 'comment_date', - 'comment_excerpt', - 'comment_form_title', - 'comment_form', - 'comment_ID', - 'comment_id_fields', - 'comment_reply_link', - 'comment_text', - 'comment_text_rss', - 'comment_time', - 'comment_type', - 'comments_link', - 'comments_number', - 'comments_popup_link', - 'comments_popup_script', - 'comments_rss_link', - 'get_avatar', - 'next_comments_link', - 'paginate_comments_links', - 'permalink_comments_rss', - 'previous_comments_link', - 'wp_list_comments', - 'the_permalink', - 'user_trailingslashit', - 'permalink_anchor', - 'get_permalink', - 'get_post_permalink', - 'post_permalink', - 'get_page_link', - 'get_attachment_link', - 'wp_shortlink_header', - 'wp_shortlink_wp_head', - 'edit_bookmark_link', - 'edit_comment_link', - 'edit_post_link', - 'get_edit_post_link', - 'get_delete_post_link', - 'edit_tag_link', - 'get_admin_url', - 'get_home_url', - 'get_site_url', - 'home_url', - 'site_url', - 'get_search_link', - 'get_search_query', - 'the_feed_link', - 'body_class', - 'next_image_link', - 'next_post_link', - 'next_posts_link', - 'post_class', - 'post_password_required', - 'posts_nav_link', - 'previous_image_link', - 'previous_post_link', - 'previous_posts_link', - 'single_post_title', - 'sticky_class', - 'the_category', - 'the_category_rss', - 'the_content', - 'the_content_rss', - 'the_excerpt', - 'the_excerpt_rss', - 'the_ID', - 'the_meta', - 'the_shortlink', - 'the_tags', - 'the_title', - 'the_title_attribute', - 'the_title_rss', - 'wp_link_pages', - 'get_attachment_link', - 'wp_get_attachment_link', - 'the_attachment_link', - 'the_search_query', - 'is_attachment', - 'wp_attachment_is_image', - 'wp_get_attachment_image', - 'wp_get_attachment_image_src', - 'wp_get_attachment_metadata', - 'get_the_date', - 'single_month_title', - 'the_date', - 'the_date_xml', - 'the_modified_author', - 'the_modified_date', - 'the_modified_time', - 'the_time', - 'the_shortlink', - 'wp_get_shortlink', - 'has_post_thumbnail', - 'get_post_thumbnail_id', - 'the_post_thumbnail', - 'get_the_post_thumbnail', - 'wp_nav_menu', - 'walk_nav_menu_tree', - 'get_term_link', - 'get_category_link', - 'get_the_title', - 'get_comment_author_link', - 'get_comment_date', - 'get_comment_time', - 'do_shortcode_tag', - ); - - public $sanitizingFunctions = array( - 'wp_kses_post', - 'wp_kses_data', - 'wp_kses_allowed_html', - 'esc_sql', - 'like_escape', - 'validate_file', - 'wp_redirect', - 'wp_safe_redirect', - 'sanitize_title', - 'sanitize_user', - 'balanceTags', - 'sanitize_html_class', - 'is_email', - 'intval', - 'absint', - 'wp_kses', - 'wp_rel_nofollow', - 'esc_html', - 'esc_html__', - 'esc_html_e', - 'esc_textarea', - 'sanitize_text_field', - 'esc_attr', - 'esc_attr__', - 'esc_attr_e', - 'esc_js', - 'json_encode', - 'esc_url', - 'esc_url_raw', - 'urlencode', - 'urlencode_deep', - 'sanitize_title', - 'sanitize_user', - 'tag_escape', - //other - 'sanitize_email', - 'sanitize_file_name', - 'sanitize_html_class', - 'sanitize_key', - 'sanitize_mime_type', - 'sanitize_option', - 'sanitize_sql_orderby', - 'sanitize_text_field', - 'sanitize_title_for_query', - 'sanitize_title_with_dashes', - 'sanitize_user', - 'sanitize_meta', - 'sanitize_term', - 'sanitize_term_field', - 'filter_var', - 'filter_input', - ); - - public $needSanitizingFunctions = array( // Mostly locatization functions: http://codex.wordpress.org/Function_Reference#Localization - '__', - '_x', - '_n', - '_nx', - '_e', - '_ex', - '_ngettext', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_ECHO, - T_PRINT, - T_STRING, - ); - - }//end register() - - - /** - * 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. - * - * @todo Allow T_CONSTANT_ENCAPSED_STRING? - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // If function, not T_ECHO nor T_PRINT - if ( $tokens[$stackPtr]['code'] == T_STRING ) { - // Skip if it is a function but is not of the printing functions ( self::needSanitizingFunctions ) - if ( ! in_array( $tokens[$stackPtr]['content'], $this->needSanitizingFunctions ) ) { - return; - } - - $stackPtr++; // Ignore the starting bracket - } - - // Ensure that the next token is a whitespace. - $stackPtr++; - if ($tokens[$stackPtr]['code'] === T_WHITESPACE) { - $stackPtr++; - } - - // Checking for the ignore comment, ex: //xss ok - $isAtEndOfStatement = false; - $commentOkRegex = '/xss\W*(ok|pass|clear|whitelist)/i'; - $tokensCount = count($tokens); - for ($i = $stackPtr; $i < $tokensCount; $i++) { - if ($tokens[$i]['code'] === T_SEMICOLON) { - $isAtEndOfStatement = true; - } - - if ($isAtEndOfStatement === true && in_array($tokens[$i]['code'], array(T_SEMICOLON, T_WHITESPACE, T_COMMENT)) === false) { - break; - } - - preg_match($commentOkRegex, $tokens[$i]['content'], $matches); - if (($tokens[$i]['code'] === T_COMMENT) && (empty($matches) === false)) { - return; - } - } - - - // looping through echo'd components - $watch = true; - for( $i = $stackPtr; $i < count( $tokens ); $i++ ) { - - // End processing if found the end of statement - if ( $tokens[$i]['code'] == T_SEMICOLON ) { - return; - } - - // Ignore whitespaces - if ( $tokens[$i]['code'] == T_WHITESPACE ) - continue; - - // Wake up on concatenation characters, another part to check - if ( in_array( $tokens[$i]['code'], array( T_STRING_CONCAT ) ) ) { - $watch = true; - continue; - } - - if ( $watch === false ) - continue; - - $watch = false; - - // Allow T_CONSTANT_ENCAPSED_STRING eg: echo 'Some String'; - if ( in_array( $tokens[$i]['code'], array( T_CONSTANT_ENCAPSED_STRING ) ) ) { - continue; - } - - // Allow int/double/bool casted variables - if ( in_array( $tokens[$i]['code'], array( T_INT_CAST, T_DOUBLE_CAST, T_BOOL_CAST ) ) ) { - continue; - } - - // Now check that next token is a function call. - if ( in_array($tokens[$i]['code'], array(T_STRING)) === false ) { - $phpcsFile->addError( "Expected next thing to be a escaping function, not '%s'", $i, null, $tokens[$i]['content'] ); - continue; - } - - // This is a function - else { - $functionName = $tokens[$i]['content']; - if ( - in_array($functionName, $this->autoEscapedFunctions) === false - && - in_array($functionName, $this->sanitizingFunctions) === false - ) { - - $phpcsFile->addError( "Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw '%s'", $i, null, $tokens[$i]['content'] ); - } - - // Skip pointer to after the function - if ( $_pos = $phpcsFile->findNext( array( T_OPEN_PARENTHESIS ), $i, null, null, null, true ) ) { - $i = $tokens[$_pos]['parenthesis_closer']; - } - continue; - } - } - - }//end process() + public static $autoEscapedFunctions = array( + 'get_header', + 'get_footer', + 'get_sidebar', + 'get_template_part', + 'get_search_form', + 'wp_loginout', + 'wp_logout_url', + 'wp_login_url', + 'wp_login_form', + 'wp_lostpassword_url', + 'wp_register', + 'wp_meta', + 'bloginfo', + 'get_bloginfo', + 'get_current_blog_id', + 'wp_title', + 'single_post_title', + 'post_type_archive_title', + 'single_cat_title', + 'single_tag_title', + 'single_term_title', + 'single_month_title', + 'get_archives_link', + 'wp_get_archives', + 'calendar_week_mod', + 'get_calendar', + 'delete_get_calendar_cache', + 'allowed_tags', + 'wp_enqueue_script', + 'the_author', + 'get_the_author', + 'the_author_link', + 'get_the_author_link', + 'the_author_meta', + 'the_author_posts', + 'the_author_posts_link', + 'wp_dropdown_users', + 'wp_list_authors', + 'get_author_posts_url', + 'wp_list_bookmarks', + 'get_bookmark', + 'get_bookmark_field', + 'get_bookmarks', + 'category_description', + 'single_cat_title', + 'the_category', + 'the_category_rss', + 'wp_dropdown_categories', + 'wp_list_categories', + 'single_tag_title', + 'tag_description', + 'the_tags', + 'wp_generate_tag_cloud', + 'wp_tag_cloud', + 'term_description', + 'single_term_title', + 'get_the_term_list', + 'the_terms', + 'the_taxonomies', + 'cancel_comment_reply_link', + 'comment_author', + 'comment_author_email', + 'comment_author_email_link', + 'comment_author_IP', + 'comment_author_link', + 'comment_author_rss', + 'comment_author_url', + 'comment_author_url_link', + 'comment_class', + 'comment_date', + 'comment_excerpt', + 'comment_form_title', + 'comment_form', + 'comment_ID', + 'comment_id_fields', + 'comment_reply_link', + 'comment_text', + 'comment_text_rss', + 'comment_time', + 'comment_type', + 'comments_link', + 'comments_number', + 'comments_popup_link', + 'comments_popup_script', + 'comments_rss_link', + 'get_avatar', + 'next_comments_link', + 'paginate_comments_links', + 'permalink_comments_rss', + 'previous_comments_link', + 'wp_list_comments', + 'the_permalink', + 'user_trailingslashit', + 'permalink_anchor', + 'get_permalink', + 'get_post_permalink', + 'post_permalink', + 'get_page_link', + 'get_attachment_link', + 'wp_shortlink_header', + 'wp_shortlink_wp_head', + 'edit_bookmark_link', + 'edit_comment_link', + 'edit_post_link', + 'get_edit_post_link', + 'get_delete_post_link', + 'edit_tag_link', + 'get_admin_url', + 'get_home_url', + 'get_site_url', + 'home_url', + 'site_url', + 'get_search_link', + 'get_search_query', + 'the_feed_link', + 'body_class', + 'next_image_link', + 'next_post_link', + 'next_posts_link', + 'post_class', + 'post_password_required', + 'posts_nav_link', + 'previous_image_link', + 'previous_post_link', + 'previous_posts_link', + 'single_post_title', + 'sticky_class', + 'the_category', + 'the_category_rss', + 'the_content', + 'the_content_rss', + 'the_excerpt', + 'the_excerpt_rss', + 'the_ID', + 'the_meta', + 'the_shortlink', + 'the_tags', + 'the_title', + 'the_title_attribute', + 'the_title_rss', + 'wp_link_pages', + 'get_attachment_link', + 'wp_get_attachment_link', + 'the_attachment_link', + 'the_search_query', + 'is_attachment', + 'wp_attachment_is_image', + 'wp_get_attachment_image', + 'wp_get_attachment_image_src', + 'wp_get_attachment_metadata', + 'get_the_date', + 'single_month_title', + 'the_date', + 'the_date_xml', + 'the_modified_author', + 'the_modified_date', + 'the_modified_time', + 'the_time', + 'the_shortlink', + 'wp_get_shortlink', + 'has_post_thumbnail', + 'get_post_thumbnail_id', + 'the_post_thumbnail', + 'get_the_post_thumbnail', + 'wp_nav_menu', + 'walk_nav_menu_tree', + 'get_term_link', + 'get_category_link', + 'get_the_title', + 'get_comment_author_link', + 'get_comment_date', + 'get_comment_time', + 'do_shortcode_tag', + ); + + public static $sanitizingFunctions = array( + 'wp_kses_post', + 'wp_kses_data', + 'wp_kses_allowed_html', + 'esc_sql', + 'like_escape', + 'validate_file', + 'wp_redirect', + 'wp_safe_redirect', + 'sanitize_title', + 'sanitize_user', + 'balanceTags', + 'sanitize_html_class', + 'is_email', + 'intval', + 'absint', + 'wp_kses', + 'wp_rel_nofollow', + 'esc_html', + 'esc_html__', + 'esc_html_e', + 'esc_textarea', + 'sanitize_text_field', + 'esc_attr', + 'esc_attr__', + 'esc_attr_e', + 'esc_js', + 'json_encode', + 'esc_url', + 'esc_url_raw', + 'urlencode', + 'urlencode_deep', + 'sanitize_title', + 'sanitize_user', + 'tag_escape', + //other + 'sanitize_email', + 'sanitize_file_name', + 'sanitize_html_class', + 'sanitize_key', + 'sanitize_mime_type', + 'sanitize_option', + 'sanitize_sql_orderby', + 'sanitize_text_field', + 'sanitize_title_for_query', + 'sanitize_title_with_dashes', + 'sanitize_user', + 'sanitize_meta', + 'sanitize_term', + 'sanitize_term_field', + 'filter_var', + 'filter_input', + ); + + public $needSanitizingFunctions = array( // Mostly locatization functions: http://codex.wordpress.org/Function_Reference#Localization + '__', + '_x', + '_n', + '_nx', + '_e', + '_ex', + '_ngettext', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_ECHO, + T_PRINT, + T_STRING, + ); + + }//end register() + + + /** + * 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. + * + * @todo Allow T_CONSTANT_ENCAPSED_STRING? + * + * @return void + */ + public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) + { + $tokens = $phpcsFile->getTokens(); + + // If function, not T_ECHO nor T_PRINT + if ( $tokens[$stackPtr]['code'] == T_STRING ) { + // Skip if it is a function but is not of the printing functions ( self::needSanitizingFunctions ) + if ( ! in_array( $tokens[$stackPtr]['content'], $this->needSanitizingFunctions ) ) { + return; + } + + $stackPtr++; // Ignore the starting bracket + } + + // Ensure that the next token is a whitespace. + $stackPtr++; + if ( $tokens[$stackPtr]['code'] === T_WHITESPACE ) { + $stackPtr++; + } + + // Checking for the ignore comment, ex: //xss ok + $isAtEndOfStatement = false; + $commentOkRegex = '/xss\W*(ok|pass|clear|whitelist)/i'; + $tokensCount = count( $tokens ); + for ( $i = $stackPtr; $i < $tokensCount; $i++ ) { + if ( $tokens[$i]['code'] === T_SEMICOLON ) { + $isAtEndOfStatement = true; + } + + if ( $isAtEndOfStatement === true && in_array( $tokens[$i]['code'], array( T_SEMICOLON, T_WHITESPACE, T_COMMENT ) ) === false ) { + break; + } + + preg_match( $commentOkRegex, $tokens[$i]['content'], $matches ); + if ( ( $tokens[$i]['code'] === T_COMMENT ) && ( empty( $matches ) === false ) ) { + return; + } + } + + + // looping through echo'd components + $watch = true; + for ( $i = $stackPtr; $i < count( $tokens ); $i++ ) { + + // End processing if found the end of statement + if ( $tokens[$i]['code'] == T_SEMICOLON ) { + return; + } + + // Ignore whitespaces + if ( $tokens[$i]['code'] == T_WHITESPACE ) + continue; + + // Wake up on concatenation characters, another part to check + if ( in_array( $tokens[$i]['code'], array( T_STRING_CONCAT ) ) ) { + $watch = true; + continue; + } + + if ( $watch === false ) + continue; + + $watch = false; + + // Allow T_CONSTANT_ENCAPSED_STRING eg: echo 'Some String'; + if ( in_array( $tokens[$i]['code'], array( T_CONSTANT_ENCAPSED_STRING ) ) ) { + continue; + } + + // Allow int/double/bool casted variables + if ( in_array( $tokens[$i]['code'], array( T_INT_CAST, T_DOUBLE_CAST, T_BOOL_CAST ) ) ) { + continue; + } + + // Now check that next token is a function call. + if ( in_array( $tokens[$i]['code'], array( T_STRING ) ) === false ) { + $phpcsFile->addError( "Expected next thing to be a escaping function, not '%s'", $i, null, $tokens[$i]['content'] ); + continue; + } + + // This is a function + else { + $functionName = $tokens[$i]['content']; + if ( + in_array( $functionName, self::$autoEscapedFunctions ) === false + && + in_array( $functionName, self::$sanitizingFunctions ) === false + ) { + + $phpcsFile->addError( "Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw '%s'", $i, null, $tokens[$i]['content'] ); + } + + // Skip pointer to after the function + if ( $_pos = $phpcsFile->findNext( array( T_OPEN_PARENTHESIS ), $i, null, null, null, true ) ) { + $i = $tokens[$_pos]['parenthesis_closer']; + } + continue; + } + } + + }//end process() }//end class diff --git a/Tests/VIP/ValidatedSanitizedInputUnitTest.inc b/Tests/VIP/ValidatedSanitizedInputUnitTest.inc new file mode 100644 index 0000000000..9b34e8321a --- /dev/null +++ b/Tests/VIP/ValidatedSanitizedInputUnitTest.inc @@ -0,0 +1,31 @@ + + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +class WordPress_Tests_VIP_ValidatedSanitizedInputUnitTest extends AbstractSniffUnitTest +{ + + + /** + * Returns the lines where errors should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of errors that should occur on that line. + * + * @return array(int => int) + */ + public function getErrorList() + { + return array( + 5 => 2, + 7 => 1, + 10 => 1, + 20 => 1, + ); + + }//end getErrorList() + + + /** + * Returns the lines where warnings should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of warnings that should occur on that line. + * + * @return array(int => int) + */ + public function getWarningList() + { + return array( + 3 => 1, + ); + + }//end getWarningList() + + +}//end class + +?>