18
18
*/
19
19
class ProperEscapingFunctionSniff extends Sniff {
20
20
21
+ /**
22
+ * Regular expression to match the end of HTML attributes.
23
+ *
24
+ * @var string
25
+ */
26
+ const ATTR_END_REGEX = '`(?<attrname>href|src|url|(^|\s+)action)?=(?: \\\\)?[" \']*$`i ' ;
27
+
21
28
/**
22
29
* List of escaping functions which are being tested.
23
30
*
@@ -46,13 +53,16 @@ class ProperEscapingFunctionSniff extends Sniff {
46
53
T_OPEN_TAG => T_OPEN_TAG ,
47
54
T_OPEN_TAG_WITH_ECHO => T_OPEN_TAG_WITH_ECHO ,
48
55
T_STRING_CONCAT => T_STRING_CONCAT ,
49
- T_COMMA => T_COMMA ,
50
56
T_NS_SEPARATOR => T_NS_SEPARATOR ,
51
57
];
52
58
53
59
/**
54
60
* List of attributes associated with url outputs.
55
61
*
62
+ * @deprecated 2.3.1 Currently unused by the sniff, but needed for
63
+ * for public methods which extending sniffs may be
64
+ * relying on.
65
+ *
56
66
* @var array
57
67
*/
58
68
private $ url_attrs = [
@@ -65,6 +75,10 @@ class ProperEscapingFunctionSniff extends Sniff {
65
75
/**
66
76
* List of syntaxes for inside attribute detection.
67
77
*
78
+ * @deprecated 2.3.1 Currently unused by the sniff, but needed for
79
+ * for public methods which extending sniffs may be
80
+ * relying on.
81
+ *
68
82
* @var array
69
83
*/
70
84
private $ attr_endings = [
@@ -75,6 +89,14 @@ class ProperEscapingFunctionSniff extends Sniff {
75
89
'= \\" ' ,
76
90
];
77
91
92
+ /**
93
+ * Keep track of whether or not we're currently in the first statement of a short open echo tag.
94
+ *
95
+ * @var int|false Integer stack pointer to the end of the first statement in the current
96
+ * short open echo tag or false when not in a short open echo tag.
97
+ */
98
+ private $ in_short_echo = false ;
99
+
78
100
/**
79
101
* Returns an array of tokens this test wants to listen for.
80
102
*
@@ -83,7 +105,10 @@ class ProperEscapingFunctionSniff extends Sniff {
83
105
public function register () {
84
106
$ this ->echo_or_concat_tokens += Tokens::$ emptyTokens ;
85
107
86
- return [ T_STRING ];
108
+ return [
109
+ T_STRING ,
110
+ T_OPEN_TAG_WITH_ECHO ,
111
+ ];
87
112
}
88
113
89
114
/**
@@ -94,6 +119,35 @@ public function register() {
94
119
* @return void
95
120
*/
96
121
public function process_token ( $ stackPtr ) {
122
+ /*
123
+ * Short open echo tags will act as an echo for the first expression and
124
+ * allow for passing multiple comma-separated parameters.
125
+ * However, short open echo tags also allow for additional statements after, but
126
+ * those have to be full PHP statements, not expressions.
127
+ *
128
+ * This snippet of code will keep track of whether or not we're in the first
129
+ * expression in a short open echo tag.
130
+ * $phpcsFile->findStartOfStatement() unfortunately is useless, as it will return
131
+ * the first token in the statement, which can be anything - variable, text string -
132
+ * without any indication of whether this is the start of a normal statement or
133
+ * a short open echo expression.
134
+ * So, if we used that, we'd need to walk back from every start of statement to
135
+ * the previous non-empty to see if it is the short open echo tag.
136
+ */
137
+ if ( $ this ->tokens [ $ stackPtr ]['code ' ] === T_OPEN_TAG_WITH_ECHO ) {
138
+ $ end_of_echo = $ this ->phpcsFile ->findNext ( [ T_SEMICOLON , T_CLOSE_TAG ], ( $ stackPtr + 1 ) );
139
+ if ( $ end_of_echo === false ) {
140
+ $ this ->in_short_echo = $ this ->phpcsFile ->numTokens ;
141
+ } else {
142
+ $ this ->in_short_echo = $ end_of_echo ;
143
+ }
144
+
145
+ return ;
146
+ }
147
+
148
+ if ( $ this ->in_short_echo !== false && $ this ->in_short_echo < $ stackPtr ) {
149
+ $ this ->in_short_echo = false ;
150
+ }
97
151
98
152
$ function_name = strtolower ( $ this ->tokens [ $ stackPtr ]['content ' ] );
99
153
@@ -107,7 +161,17 @@ public function process_token( $stackPtr ) {
107
161
return ;
108
162
}
109
163
110
- $ html = $ this ->phpcsFile ->findPrevious ( $ this ->echo_or_concat_tokens , $ stackPtr - 1 , null , true );
164
+ $ ignore = $ this ->echo_or_concat_tokens ;
165
+ if ( $ this ->in_short_echo !== false ) {
166
+ $ ignore [ T_COMMA ] = T_COMMA ;
167
+ } else {
168
+ $ start_of_statement = $ this ->phpcsFile ->findStartOfStatement ( $ stackPtr , T_COMMA );
169
+ if ( $ this ->tokens [ $ start_of_statement ]['code ' ] === T_ECHO ) {
170
+ $ ignore [ T_COMMA ] = T_COMMA ;
171
+ }
172
+ }
173
+
174
+ $ html = $ this ->phpcsFile ->findPrevious ( $ ignore , $ stackPtr - 1 , null , true );
111
175
112
176
// Use $textStringTokens b/c heredoc and nowdoc tokens will never be encountered in this context anyways..
113
177
if ( $ html === false || isset ( Tokens::$ textStringTokens [ $ this ->tokens [ $ html ]['code ' ] ] ) === false ) {
@@ -129,13 +193,17 @@ public function process_token( $stackPtr ) {
129
193
return ;
130
194
}
131
195
132
- if ( $ escaping_type !== 'url ' && $ this ->attr_expects_url ( $ content ) ) {
196
+ if ( preg_match ( self ::ATTR_END_REGEX , $ content , $ matches ) !== 1 ) {
197
+ return ;
198
+ }
199
+
200
+ if ( $ escaping_type !== 'url ' && empty ( $ matches ['attrname ' ] ) === false ) {
133
201
$ message = 'Wrong escaping function. href, src, and action attributes should be escaped by `esc_url()`, not by `%s()`. ' ;
134
202
$ this ->phpcsFile ->addError ( $ message , $ stackPtr , 'hrefSrcEscUrl ' , $ data );
135
203
return ;
136
204
}
137
205
138
- if ( $ escaping_type === 'html ' && $ this -> is_html_attr ( $ content ) ) {
206
+ if ( $ escaping_type === 'html ' ) {
139
207
$ message = 'Wrong escaping function. HTML attributes should be escaped by `esc_attr()`, not by `%s()`. ' ;
140
208
$ this ->phpcsFile ->addError ( $ message , $ stackPtr , 'htmlAttrNotByEscHTML ' , $ data );
141
209
return ;
@@ -145,6 +213,8 @@ public function process_token( $stackPtr ) {
145
213
/**
146
214
* Tests whether provided string ends with open attribute which expects a URL value.
147
215
*
216
+ * @deprecated 2.3.1
217
+ *
148
218
* @param string $content Haystack in which we look for an open attribute which exects a URL value.
149
219
*
150
220
* @return bool True if string ends with open attribute which expects a URL value.
@@ -165,6 +235,8 @@ public function attr_expects_url( $content ) {
165
235
/**
166
236
* Tests whether provided string ends with open HMTL attribute.
167
237
*
238
+ * @deprecated 2.3.1
239
+ *
168
240
* @param string $content Haystack in which we look for open HTML attribute.
169
241
*
170
242
* @return bool True if string ends with open HTML attribute.
0 commit comments