@@ -22,13 +22,26 @@ class HTMLExecutingFunctionsSniff extends Sniff {
2222 /**
2323 * List of HTML executing functions.
2424 *
25+ * Name of function => content or target.
26+ * Value indicates whether the function's arg is the content to be inserted, or the target where the inserted
27+ * content is to be inserted before/after/replaced. For the latter, the content is in the preceding method's arg.
28+ *
2529 * @var array
2630 */
2731 public $ HTMLExecutingFunctions = [
28- 'html ' ,
29- 'append ' ,
30- 'write ' ,
31- 'writeln ' ,
32+ 'after ' => 'content ' , // jQuery.
33+ 'append ' => 'content ' , // jQuery.
34+ 'appendTo ' => 'target ' , // jQuery.
35+ 'before ' => 'content ' , // jQuery.
36+ 'html ' => 'content ' , // jQuery.
37+ 'insertAfter ' => 'target ' , // jQuery.
38+ 'insertBefore ' => 'target ' , // jQuery.
39+ 'prepend ' => 'content ' , // jQuery.
40+ 'prependTo ' => 'target ' , // jQuery.
41+ 'replaceAll ' => 'target ' , // jQuery.
42+ 'replaceWith ' => 'content ' , // jQuery.
43+ 'write ' => 'content ' ,
44+ 'writeln ' => 'content ' ,
3245 ];
3346
3447 /**
@@ -58,29 +71,56 @@ public function register() {
5871 */
5972 public function process_token ( $ stackPtr ) {
6073
61- if ( false === in_array ( $ this ->tokens [ $ stackPtr ]['content ' ], $ this -> HTMLExecutingFunctions , true ) ) {
74+ if ( ! isset ( $ this ->HTMLExecutingFunctions [ $ this -> tokens [ $ stackPtr ]['content ' ] ] ) ) {
6275 // Looking for specific functions only.
6376 return ;
6477 }
6578
66- $ nextToken = $ this ->phpcsFile ->findNext ( Tokens::$ emptyTokens , $ stackPtr + 1 , null , true , null , true );
79+ if ( 'content ' === $ this ->HTMLExecutingFunctions [ $ this ->tokens [ $ stackPtr ]['content ' ] ] ) {
80+ $ nextToken = $ this ->phpcsFile ->findNext ( Tokens::$ emptyTokens , $ stackPtr + 1 , null , true , null , true );
6781
68- if ( T_OPEN_PARENTHESIS !== $ this ->tokens [ $ nextToken ]['code ' ] ) {
69- // Not a function.
70- return ;
71- }
82+ if ( T_OPEN_PARENTHESIS !== $ this ->tokens [ $ nextToken ]['code ' ] ) {
83+ // Not a function.
84+ return ;
85+ }
86+
87+ $ parenthesis_closer = $ this ->tokens [ $ nextToken ]['parenthesis_closer ' ];
7288
73- $ parenthesis_closer = $ this ->tokens [ $ nextToken ]['parenthesis_closer ' ];
89+ while ( $ nextToken < $ parenthesis_closer ) {
90+ $ nextToken = $ this ->phpcsFile ->findNext ( Tokens::$ emptyTokens , $ nextToken + 1 , null , true , null , true );
91+ if ( T_STRING === $ this ->tokens [ $ nextToken ]['code ' ] ) { // Contains a variable.
92+ $ message = 'Any HTML passed to `%s` gets executed. Make sure it \'s properly escaped. ' ;
93+ $ data = [ $ this ->tokens [ $ stackPtr ]['content ' ] ];
94+ $ this ->phpcsFile ->addWarning ( $ message , $ stackPtr , $ this ->tokens [ $ stackPtr ]['content ' ], $ data );
7495
75- while ( $ nextToken < $ parenthesis_closer ) {
76- $ nextToken = $ this ->phpcsFile ->findNext ( Tokens::$ emptyTokens , $ nextToken + 1 , null , true , null , true );
77- if ( T_STRING === $ this ->tokens [ $ nextToken ]['code ' ] ) {
78- $ message = 'Any HTML passed to `%s` gets executed. Make sure it \'s properly escaped. ' ;
79- $ data = [ $ this ->tokens [ $ stackPtr ]['content ' ] ];
80- $ this ->phpcsFile ->addWarning ( $ message , $ stackPtr , $ this ->tokens [ $ stackPtr ]['content ' ], $ data );
96+ return ;
97+ }
98+ }
99+ } elseif ( 'target ' === $ this ->HTMLExecutingFunctions [ $ this ->tokens [ $ stackPtr ]['content ' ] ] ) {
100+ $ prevToken = $ this ->phpcsFile ->findPrevious ( Tokens::$ emptyTokens , $ stackPtr - 1 , null , true , null , true );
81101
102+ if ( T_OBJECT_OPERATOR !== $ this ->tokens [ $ prevToken ]['code ' ] ) {
82103 return ;
83104 }
105+
106+ $ prevPrevToken = $ this ->phpcsFile ->findPrevious ( Tokens::$ emptyTokens , $ prevToken - 1 , null , true , null , true );
107+
108+ if ( T_CLOSE_PARENTHESIS !== $ this ->tokens [ $ prevPrevToken ]['code ' ] ) {
109+ return ;
110+ }
111+
112+ $ parenthesis_opener = $ this ->tokens [ $ prevPrevToken ]['parenthesis_opener ' ];
113+
114+ while ( $ prevPrevToken > $ parenthesis_opener ) {
115+ $ prevPrevToken = $ this ->phpcsFile ->findPrevious ( Tokens::$ emptyTokens , $ prevPrevToken - 1 , null , true , null , true );
116+ if ( T_STRING === $ this ->tokens [ $ prevPrevToken ]['code ' ] ) { // Contains a variable.
117+ $ message = 'Any HTML used with `%s` gets executed. Make sure it \'s properly escaped. ' ;
118+ $ data = [ $ this ->tokens [ $ stackPtr ]['content ' ] ];
119+ $ this ->phpcsFile ->addWarning ( $ message , $ stackPtr , $ this ->tokens [ $ stackPtr ]['content ' ], $ data );
120+
121+ return ;
122+ }
123+ }
84124 }
85125 }
86126
0 commit comments