This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Class for generating SQL clauses that filter a primary query according to date. |
||
4 | * |
||
5 | * WP_Date_Query is a helper that allows primary query classes, such as WP_Query, to filter |
||
6 | * their results by date columns, by generating `WHERE` subclauses to be attached to the |
||
7 | * primary SQL query string. |
||
8 | * |
||
9 | * Attempting to filter by an invalid date value (eg month=13) will generate SQL that will |
||
10 | * return no results. In these cases, a _doing_it_wrong() error notice is also thrown. |
||
11 | * See WP_Date_Query::validate_date_values(). |
||
12 | * |
||
13 | * @link https://codex.wordpress.org/Function_Reference/WP_Query Codex page. |
||
14 | * |
||
15 | * @since 3.7.0 |
||
16 | */ |
||
17 | class WP_Date_Query { |
||
18 | /** |
||
19 | * Array of date queries. |
||
20 | * |
||
21 | * See WP_Date_Query::__construct() for information on date query arguments. |
||
22 | * |
||
23 | * @since 3.7.0 |
||
24 | * @access public |
||
25 | * @var array |
||
26 | */ |
||
27 | public $queries = array(); |
||
28 | |||
29 | /** |
||
30 | * The default relation between top-level queries. Can be either 'AND' or 'OR'. |
||
31 | * |
||
32 | * @since 3.7.0 |
||
33 | * @access public |
||
34 | * @var string |
||
35 | */ |
||
36 | public $relation = 'AND'; |
||
37 | |||
38 | /** |
||
39 | * The column to query against. Can be changed via the query arguments. |
||
40 | * |
||
41 | * @since 3.7.0 |
||
42 | * @access public |
||
43 | * @var string |
||
44 | */ |
||
45 | public $column = 'post_date'; |
||
46 | |||
47 | /** |
||
48 | * The value comparison operator. Can be changed via the query arguments. |
||
49 | * |
||
50 | * @since 3.7.0 |
||
51 | * @access public |
||
52 | * @var array |
||
53 | */ |
||
54 | public $compare = '='; |
||
55 | |||
56 | /** |
||
57 | * Supported time-related parameter keys. |
||
58 | * |
||
59 | * @since 4.1.0 |
||
60 | * @access public |
||
61 | * @var array |
||
62 | */ |
||
63 | public $time_keys = array( 'after', 'before', 'year', 'month', 'monthnum', 'week', 'w', 'dayofyear', 'day', 'dayofweek', 'dayofweek_iso', 'hour', 'minute', 'second' ); |
||
64 | |||
65 | /** |
||
66 | * Constructor. |
||
67 | * |
||
68 | * Time-related parameters that normally require integer values ('year', 'month', 'week', 'dayofyear', 'day', |
||
69 | * 'dayofweek', 'dayofweek_iso', 'hour', 'minute', 'second') accept arrays of integers for some values of |
||
70 | * 'compare'. When 'compare' is 'IN' or 'NOT IN', arrays are accepted; when 'compare' is 'BETWEEN' or 'NOT |
||
71 | * BETWEEN', arrays of two valid values are required. See individual argument descriptions for accepted values. |
||
72 | * |
||
73 | * @since 3.7.0 |
||
74 | * @since 4.0.0 The $inclusive logic was updated to include all times within the date range. |
||
75 | * @since 4.1.0 Introduced 'dayofweek_iso' time type parameter. |
||
76 | * @access public |
||
77 | * |
||
78 | * @param array $date_query { |
||
79 | * Array of date query clauses. |
||
80 | * |
||
81 | * @type array { |
||
82 | * @type string $column Optional. The column to query against. If undefined, inherits the value of |
||
83 | * the `$default_column` parameter. Accepts 'post_date', 'post_date_gmt', |
||
84 | * 'post_modified','post_modified_gmt', 'comment_date', 'comment_date_gmt'. |
||
85 | * Default 'post_date'. |
||
86 | * @type string $compare Optional. The comparison operator. Accepts '=', '!=', '>', '>=', '<', '<=', |
||
87 | * 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'. Default '='. |
||
88 | * @type string $relation Optional. The boolean relationship between the date queries. Accepts 'OR' or 'AND'. |
||
89 | * Default 'OR'. |
||
90 | * @type array { |
||
91 | * Optional. An array of first-order clause parameters, or another fully-formed date query. |
||
92 | * |
||
93 | * @type string|array $before { |
||
94 | * Optional. Date to retrieve posts before. Accepts `strtotime()`-compatible string, |
||
95 | * or array of 'year', 'month', 'day' values. |
||
96 | * |
||
97 | * @type string $year The four-digit year. Default empty. Accepts any four-digit year. |
||
98 | * @type string $month Optional when passing array.The month of the year. |
||
99 | * Default (string:empty)|(array:1). Accepts numbers 1-12. |
||
100 | * @type string $day Optional when passing array.The day of the month. |
||
101 | * Default (string:empty)|(array:1). Accepts numbers 1-31. |
||
102 | * } |
||
103 | * @type string|array $after { |
||
104 | * Optional. Date to retrieve posts after. Accepts `strtotime()`-compatible string, |
||
105 | * or array of 'year', 'month', 'day' values. |
||
106 | * |
||
107 | * @type string $year The four-digit year. Accepts any four-digit year. Default empty. |
||
108 | * @type string $month Optional when passing array. The month of the year. Accepts numbers 1-12. |
||
109 | * Default (string:empty)|(array:12). |
||
110 | * @type string $day Optional when passing array.The day of the month. Accepts numbers 1-31. |
||
111 | * Default (string:empty)|(array:last day of month). |
||
112 | * } |
||
113 | * @type string $column Optional. Used to add a clause comparing a column other than the |
||
114 | * column specified in the top-level `$column` parameter. Accepts |
||
115 | * 'post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt', |
||
116 | * 'comment_date', 'comment_date_gmt'. Default is the value of |
||
117 | * top-level `$column`. |
||
118 | * @type string $compare Optional. The comparison operator. Accepts '=', '!=', '>', '>=', |
||
119 | * '<', '<=', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'. 'IN', |
||
120 | * 'NOT IN', 'BETWEEN', and 'NOT BETWEEN'. Comparisons support |
||
121 | * arrays in some time-related parameters. Default '='. |
||
122 | * @type bool $inclusive Optional. Include results from dates specified in 'before' or |
||
123 | * 'after'. Default false. |
||
124 | * @type int|array $year Optional. The four-digit year number. Accepts any four-digit year |
||
125 | * or an array of years if `$compare` supports it. Default empty. |
||
126 | * @type int|array $month Optional. The two-digit month number. Accepts numbers 1-12 or an |
||
127 | * array of valid numbers if `$compare` supports it. Default empty. |
||
128 | * @type int|array $week Optional. The week number of the year. Accepts numbers 0-53 or an |
||
129 | * array of valid numbers if `$compare` supports it. Default empty. |
||
130 | * @type int|array $dayofyear Optional. The day number of the year. Accepts numbers 1-366 or an |
||
131 | * array of valid numbers if `$compare` supports it. |
||
132 | * @type int|array $day Optional. The day of the month. Accepts numbers 1-31 or an array |
||
133 | * of valid numbers if `$compare` supports it. Default empty. |
||
134 | * @type int|array $dayofweek Optional. The day number of the week. Accepts numbers 1-7 (1 is |
||
135 | * Sunday) or an array of valid numbers if `$compare` supports it. |
||
136 | * Default empty. |
||
137 | * @type int|array $dayofweek_iso Optional. The day number of the week (ISO). Accepts numbers 1-7 |
||
138 | * (1 is Monday) or an array of valid numbers if `$compare` supports it. |
||
139 | * Default empty. |
||
140 | * @type int|array $hour Optional. The hour of the day. Accepts numbers 0-23 or an array |
||
141 | * of valid numbers if `$compare` supports it. Default empty. |
||
142 | * @type int|array $minute Optional. The minute of the hour. Accepts numbers 0-60 or an array |
||
143 | * of valid numbers if `$compare` supports it. Default empty. |
||
144 | * @type int|array $second Optional. The second of the minute. Accepts numbers 0-60 or an |
||
145 | * array of valid numbers if `$compare` supports it. Default empty. |
||
146 | * } |
||
147 | * } |
||
148 | * } |
||
149 | * @param array $default_column Optional. Default column to query against. Default 'post_date'. |
||
0 ignored issues
–
show
|
|||
150 | * Accepts 'post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt', |
||
151 | * 'comment_date', 'comment_date_gmt'. |
||
152 | */ |
||
153 | public function __construct( $date_query, $default_column = 'post_date' ) { |
||
154 | View Code Duplication | if ( isset( $date_query['relation'] ) && 'OR' === strtoupper( $date_query['relation'] ) ) { |
|
155 | $this->relation = 'OR'; |
||
156 | } else { |
||
157 | $this->relation = 'AND'; |
||
158 | } |
||
159 | |||
160 | if ( ! is_array( $date_query ) ) { |
||
161 | return; |
||
162 | } |
||
163 | |||
164 | // Support for passing time-based keys in the top level of the $date_query array. |
||
165 | if ( ! isset( $date_query[0] ) && ! empty( $date_query ) ) { |
||
166 | $date_query = array( $date_query ); |
||
167 | } |
||
168 | |||
169 | if ( empty( $date_query ) ) { |
||
170 | return; |
||
171 | } |
||
172 | |||
173 | if ( ! empty( $date_query['column'] ) ) { |
||
174 | $date_query['column'] = esc_sql( $date_query['column'] ); |
||
175 | } else { |
||
176 | $date_query['column'] = esc_sql( $default_column ); |
||
177 | } |
||
178 | |||
179 | $this->column = $this->validate_column( $this->column ); |
||
180 | |||
181 | $this->compare = $this->get_compare( $date_query ); |
||
0 ignored issues
–
show
It seems like
$this->get_compare($date_query) can also be of type string . However, the property $compare is declared as type array . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
182 | |||
183 | $this->queries = $this->sanitize_query( $date_query ); |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Recursive-friendly query sanitizer. |
||
188 | * |
||
189 | * Ensures that each query-level clause has a 'relation' key, and that |
||
190 | * each first-order clause contains all the necessary keys from |
||
191 | * `$defaults`. |
||
192 | * |
||
193 | * @since 4.1.0 |
||
194 | * @access public |
||
195 | * |
||
196 | * @param array $queries |
||
197 | * @param array $parent_query |
||
0 ignored issues
–
show
Should the type for parameter
$parent_query not be array|null ? Also, consider making the array more specific, something like array<String> , or String[] .
This check looks for It makes a suggestion as to what type it considers more descriptive. In addition it
looks for parameters that have the generic type Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
198 | * |
||
199 | * @return array Sanitized queries. |
||
200 | */ |
||
201 | public function sanitize_query( $queries, $parent_query = null ) { |
||
202 | $cleaned_query = array(); |
||
203 | |||
204 | $defaults = array( |
||
205 | 'column' => 'post_date', |
||
206 | 'compare' => '=', |
||
207 | 'relation' => 'AND', |
||
208 | ); |
||
209 | |||
210 | // Numeric keys should always have array values. |
||
211 | foreach ( $queries as $qkey => $qvalue ) { |
||
212 | if ( is_numeric( $qkey ) && ! is_array( $qvalue ) ) { |
||
213 | unset( $queries[ $qkey ] ); |
||
214 | } |
||
215 | } |
||
216 | |||
217 | // Each query should have a value for each default key. Inherit from the parent when possible. |
||
218 | foreach ( $defaults as $dkey => $dvalue ) { |
||
219 | if ( isset( $queries[ $dkey ] ) ) { |
||
220 | continue; |
||
221 | } |
||
222 | |||
223 | if ( isset( $parent_query[ $dkey ] ) ) { |
||
224 | $queries[ $dkey ] = $parent_query[ $dkey ]; |
||
225 | } else { |
||
226 | $queries[ $dkey ] = $dvalue; |
||
227 | } |
||
228 | } |
||
229 | |||
230 | // Validate the dates passed in the query. |
||
231 | if ( $this->is_first_order_clause( $queries ) ) { |
||
232 | $this->validate_date_values( $queries ); |
||
233 | } |
||
234 | |||
235 | foreach ( $queries as $key => $q ) { |
||
236 | if ( ! is_array( $q ) || in_array( $key, $this->time_keys, true ) ) { |
||
237 | // This is a first-order query. Trust the values and sanitize when building SQL. |
||
238 | $cleaned_query[ $key ] = $q; |
||
239 | } else { |
||
240 | // Any array without a time key is another query, so we recurse. |
||
241 | $cleaned_query[] = $this->sanitize_query( $q, $queries ); |
||
242 | } |
||
243 | } |
||
244 | |||
245 | return $cleaned_query; |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * Determine whether this is a first-order clause. |
||
250 | * |
||
251 | * Checks to see if the current clause has any time-related keys. |
||
252 | * If so, it's first-order. |
||
253 | * |
||
254 | * @since 4.1.0 |
||
255 | * @access protected |
||
256 | * |
||
257 | * @param array $query Query clause. |
||
258 | * @return bool True if this is a first-order clause. |
||
259 | */ |
||
260 | protected function is_first_order_clause( $query ) { |
||
261 | $time_keys = array_intersect( $this->time_keys, array_keys( $query ) ); |
||
262 | return ! empty( $time_keys ); |
||
263 | } |
||
264 | |||
265 | /** |
||
266 | * Determines and validates what comparison operator to use. |
||
267 | * |
||
268 | * @since 3.7.0 |
||
269 | * @access public |
||
270 | * |
||
271 | * @param array $query A date query or a date subquery. |
||
272 | * @return string The comparison operator. |
||
0 ignored issues
–
show
Should the return type not be
string|array ? Also, consider making the array more specific, something like array<String> , or String[] .
This check compares the return type specified in the If the return type contains the type array, this check recommends the use of
a more specific type like ![]() |
|||
273 | */ |
||
274 | public function get_compare( $query ) { |
||
275 | if ( ! empty( $query['compare'] ) && in_array( $query['compare'], array( '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) |
||
276 | return strtoupper( $query['compare'] ); |
||
277 | |||
278 | return $this->compare; |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * Validates the given date_query values and triggers errors if something is not valid. |
||
283 | * |
||
284 | * Note that date queries with invalid date ranges are allowed to |
||
285 | * continue (though of course no items will be found for impossible dates). |
||
286 | * This method only generates debug notices for these cases. |
||
287 | * |
||
288 | * @since 4.1.0 |
||
289 | * @access public |
||
290 | * |
||
291 | * @param array $date_query The date_query array. |
||
292 | * @return bool True if all values in the query are valid, false if one or more fail. |
||
293 | */ |
||
294 | public function validate_date_values( $date_query = array() ) { |
||
295 | if ( empty( $date_query ) ) { |
||
296 | return false; |
||
297 | } |
||
298 | |||
299 | $valid = true; |
||
300 | |||
301 | /* |
||
302 | * Validate 'before' and 'after' up front, then let the |
||
303 | * validation routine continue to be sure that all invalid |
||
304 | * values generate errors too. |
||
305 | */ |
||
306 | View Code Duplication | if ( array_key_exists( 'before', $date_query ) && is_array( $date_query['before'] ) ){ |
|
307 | $valid = $this->validate_date_values( $date_query['before'] ); |
||
308 | } |
||
309 | |||
310 | View Code Duplication | if ( array_key_exists( 'after', $date_query ) && is_array( $date_query['after'] ) ){ |
|
311 | $valid = $this->validate_date_values( $date_query['after'] ); |
||
312 | } |
||
313 | |||
314 | // Array containing all min-max checks. |
||
315 | $min_max_checks = array(); |
||
316 | |||
317 | // Days per year. |
||
318 | if ( array_key_exists( 'year', $date_query ) ) { |
||
319 | /* |
||
320 | * If a year exists in the date query, we can use it to get the days. |
||
321 | * If multiple years are provided (as in a BETWEEN), use the first one. |
||
322 | */ |
||
323 | if ( is_array( $date_query['year'] ) ) { |
||
324 | $_year = reset( $date_query['year'] ); |
||
325 | } else { |
||
326 | $_year = $date_query['year']; |
||
327 | } |
||
328 | |||
329 | $max_days_of_year = date( 'z', mktime( 0, 0, 0, 12, 31, $_year ) ) + 1; |
||
330 | } else { |
||
331 | // otherwise we use the max of 366 (leap-year) |
||
332 | $max_days_of_year = 366; |
||
333 | } |
||
334 | |||
335 | $min_max_checks['dayofyear'] = array( |
||
336 | 'min' => 1, |
||
337 | 'max' => $max_days_of_year |
||
338 | ); |
||
339 | |||
340 | // Days per week. |
||
341 | $min_max_checks['dayofweek'] = array( |
||
342 | 'min' => 1, |
||
343 | 'max' => 7 |
||
344 | ); |
||
345 | |||
346 | // Days per week. |
||
347 | $min_max_checks['dayofweek_iso'] = array( |
||
348 | 'min' => 1, |
||
349 | 'max' => 7 |
||
350 | ); |
||
351 | |||
352 | // Months per year. |
||
353 | $min_max_checks['month'] = array( |
||
354 | 'min' => 1, |
||
355 | 'max' => 12 |
||
356 | ); |
||
357 | |||
358 | // Weeks per year. |
||
359 | if ( isset( $_year ) ) { |
||
360 | /* |
||
361 | * If we have a specific year, use it to calculate number of weeks. |
||
362 | * Note: the number of weeks in a year is the date in which Dec 28 appears. |
||
363 | */ |
||
364 | $week_count = date( 'W', mktime( 0, 0, 0, 12, 28, $_year ) ); |
||
365 | |||
366 | } else { |
||
367 | // Otherwise set the week-count to a maximum of 53. |
||
368 | $week_count = 53; |
||
369 | } |
||
370 | |||
371 | $min_max_checks['week'] = array( |
||
372 | 'min' => 1, |
||
373 | 'max' => $week_count |
||
374 | ); |
||
375 | |||
376 | // Days per month. |
||
377 | $min_max_checks['day'] = array( |
||
378 | 'min' => 1, |
||
379 | 'max' => 31 |
||
380 | ); |
||
381 | |||
382 | // Hours per day. |
||
383 | $min_max_checks['hour'] = array( |
||
384 | 'min' => 0, |
||
385 | 'max' => 23 |
||
386 | ); |
||
387 | |||
388 | // Minutes per hour. |
||
389 | $min_max_checks['minute'] = array( |
||
390 | 'min' => 0, |
||
391 | 'max' => 59 |
||
392 | ); |
||
393 | |||
394 | // Seconds per minute. |
||
395 | $min_max_checks['second'] = array( |
||
396 | 'min' => 0, |
||
397 | 'max' => 59 |
||
398 | ); |
||
399 | |||
400 | // Concatenate and throw a notice for each invalid value. |
||
401 | foreach ( $min_max_checks as $key => $check ) { |
||
402 | if ( ! array_key_exists( $key, $date_query ) ) { |
||
403 | continue; |
||
404 | } |
||
405 | |||
406 | // Throw a notice for each failing value. |
||
407 | foreach ( (array) $date_query[ $key ] as $_value ) { |
||
408 | $is_between = $_value >= $check['min'] && $_value <= $check['max']; |
||
409 | |||
410 | if ( ! is_numeric( $_value ) || ! $is_between ) { |
||
411 | $error = sprintf( |
||
412 | /* translators: Date query invalid date message: 1: invalid value, 2: type of value, 3: minimum valid value, 4: maximum valid value */ |
||
413 | __( 'Invalid value %1$s for %2$s. Expected value should be between %3$s and %4$s.' ), |
||
414 | '<code>' . esc_html( $_value ) . '</code>', |
||
415 | '<code>' . esc_html( $key ) . '</code>', |
||
416 | '<code>' . esc_html( $check['min'] ) . '</code>', |
||
417 | '<code>' . esc_html( $check['max'] ) . '</code>' |
||
418 | ); |
||
419 | |||
420 | _doing_it_wrong( __CLASS__, $error, '4.1.0' ); |
||
421 | |||
422 | $valid = false; |
||
423 | } |
||
424 | } |
||
425 | } |
||
426 | |||
427 | // If we already have invalid date messages, don't bother running through checkdate(). |
||
428 | if ( ! $valid ) { |
||
429 | return $valid; |
||
430 | } |
||
431 | |||
432 | $day_month_year_error_msg = ''; |
||
433 | |||
434 | $day_exists = array_key_exists( 'day', $date_query ) && is_numeric( $date_query['day'] ); |
||
435 | $month_exists = array_key_exists( 'month', $date_query ) && is_numeric( $date_query['month'] ); |
||
436 | $year_exists = array_key_exists( 'year', $date_query ) && is_numeric( $date_query['year'] ); |
||
437 | |||
438 | if ( $day_exists && $month_exists && $year_exists ) { |
||
439 | // 1. Checking day, month, year combination. |
||
440 | if ( ! wp_checkdate( $date_query['month'], $date_query['day'], $date_query['year'], sprintf( '%s-%s-%s', $date_query['year'], $date_query['month'], $date_query['day'] ) ) ) { |
||
441 | /* translators: 1: year, 2: month, 3: day of month */ |
||
442 | $day_month_year_error_msg = sprintf( |
||
443 | __( 'The following values do not describe a valid date: year %1$s, month %2$s, day %3$s.' ), |
||
444 | '<code>' . esc_html( $date_query['year'] ) . '</code>', |
||
445 | '<code>' . esc_html( $date_query['month'] ) . '</code>', |
||
446 | '<code>' . esc_html( $date_query['day'] ) . '</code>' |
||
447 | ); |
||
448 | |||
449 | $valid = false; |
||
450 | } |
||
451 | |||
452 | } elseif ( $day_exists && $month_exists ) { |
||
453 | /* |
||
454 | * 2. checking day, month combination |
||
455 | * We use 2012 because, as a leap year, it's the most permissive. |
||
456 | */ |
||
457 | if ( ! wp_checkdate( $date_query['month'], $date_query['day'], 2012, sprintf( '2012-%s-%s', $date_query['month'], $date_query['day'] ) ) ) { |
||
458 | /* translators: 1: month, 2: day of month */ |
||
459 | $day_month_year_error_msg = sprintf( |
||
460 | __( 'The following values do not describe a valid date: month %1$s, day %2$s.' ), |
||
461 | '<code>' . esc_html( $date_query['month'] ) . '</code>', |
||
462 | '<code>' . esc_html( $date_query['day'] ) . '</code>' |
||
463 | ); |
||
464 | |||
465 | $valid = false; |
||
466 | } |
||
467 | } |
||
468 | |||
469 | if ( ! empty( $day_month_year_error_msg ) ) { |
||
470 | _doing_it_wrong( __CLASS__, $day_month_year_error_msg, '4.1.0' ); |
||
471 | } |
||
472 | |||
473 | return $valid; |
||
474 | } |
||
475 | |||
476 | /** |
||
477 | * Validates a column name parameter. |
||
478 | * |
||
479 | * Column names without a table prefix (like 'post_date') are checked against a whitelist of |
||
480 | * known tables, and then, if found, have a table prefix (such as 'wp_posts.') prepended. |
||
481 | * Prefixed column names (such as 'wp_posts.post_date') bypass this whitelist check, |
||
482 | * and are only sanitized to remove illegal characters. |
||
483 | * |
||
484 | * @since 3.7.0 |
||
485 | * @access public |
||
486 | * |
||
487 | * @param string $column The user-supplied column name. |
||
488 | * @return string A validated column name value. |
||
489 | */ |
||
490 | public function validate_column( $column ) { |
||
491 | global $wpdb; |
||
492 | |||
493 | $valid_columns = array( |
||
494 | 'post_date', 'post_date_gmt', 'post_modified', |
||
495 | 'post_modified_gmt', 'comment_date', 'comment_date_gmt', |
||
496 | 'user_registered', 'registered', 'last_updated', |
||
497 | ); |
||
498 | |||
499 | // Attempt to detect a table prefix. |
||
500 | if ( false === strpos( $column, '.' ) ) { |
||
501 | /** |
||
502 | * Filters the list of valid date query columns. |
||
503 | * |
||
504 | * @since 3.7.0 |
||
505 | * @since 4.1.0 Added 'user_registered' to the default recognized columns. |
||
506 | * |
||
507 | * @param array $valid_columns An array of valid date query columns. Defaults |
||
508 | * are 'post_date', 'post_date_gmt', 'post_modified', |
||
509 | * 'post_modified_gmt', 'comment_date', 'comment_date_gmt', |
||
510 | * 'user_registered' |
||
511 | */ |
||
512 | if ( ! in_array( $column, apply_filters( 'date_query_valid_columns', $valid_columns ) ) ) { |
||
513 | $column = 'post_date'; |
||
514 | } |
||
515 | |||
516 | $known_columns = array( |
||
517 | $wpdb->posts => array( |
||
518 | 'post_date', |
||
519 | 'post_date_gmt', |
||
520 | 'post_modified', |
||
521 | 'post_modified_gmt', |
||
522 | ), |
||
523 | $wpdb->comments => array( |
||
524 | 'comment_date', |
||
525 | 'comment_date_gmt', |
||
526 | ), |
||
527 | $wpdb->users => array( |
||
528 | 'user_registered', |
||
529 | ), |
||
530 | $wpdb->blogs => array( |
||
531 | 'registered', |
||
532 | 'last_updated', |
||
533 | ), |
||
534 | ); |
||
535 | |||
536 | // If it's a known column name, add the appropriate table prefix. |
||
537 | foreach ( $known_columns as $table_name => $table_columns ) { |
||
538 | if ( in_array( $column, $table_columns ) ) { |
||
539 | $column = $table_name . '.' . $column; |
||
540 | break; |
||
541 | } |
||
542 | } |
||
543 | |||
544 | } |
||
545 | |||
546 | // Remove unsafe characters. |
||
547 | return preg_replace( '/[^a-zA-Z0-9_$\.]/', '', $column ); |
||
548 | } |
||
549 | |||
550 | /** |
||
551 | * Generate WHERE clause to be appended to a main query. |
||
552 | * |
||
553 | * @since 3.7.0 |
||
554 | * @access public |
||
555 | * |
||
556 | * @return string MySQL WHERE clause. |
||
557 | */ |
||
558 | public function get_sql() { |
||
559 | $sql = $this->get_sql_clauses(); |
||
560 | |||
561 | $where = $sql['where']; |
||
562 | |||
563 | /** |
||
564 | * Filters the date query WHERE clause. |
||
565 | * |
||
566 | * @since 3.7.0 |
||
567 | * |
||
568 | * @param string $where WHERE clause of the date query. |
||
569 | * @param WP_Date_Query $this The WP_Date_Query instance. |
||
570 | */ |
||
571 | return apply_filters( 'get_date_sql', $where, $this ); |
||
572 | } |
||
573 | |||
574 | /** |
||
575 | * Generate SQL clauses to be appended to a main query. |
||
576 | * |
||
577 | * Called by the public WP_Date_Query::get_sql(), this method is abstracted |
||
578 | * out to maintain parity with the other Query classes. |
||
579 | * |
||
580 | * @since 4.1.0 |
||
581 | * @access protected |
||
582 | * |
||
583 | * @return array { |
||
0 ignored issues
–
show
|
|||
584 | * Array containing JOIN and WHERE SQL clauses to append to the main query. |
||
585 | * |
||
586 | * @type string $join SQL fragment to append to the main JOIN clause. |
||
587 | * @type string $where SQL fragment to append to the main WHERE clause. |
||
588 | * } |
||
589 | */ |
||
590 | View Code Duplication | protected function get_sql_clauses() { |
|
591 | $sql = $this->get_sql_for_query( $this->queries ); |
||
592 | |||
593 | if ( ! empty( $sql['where'] ) ) { |
||
594 | $sql['where'] = ' AND ' . $sql['where']; |
||
595 | } |
||
596 | |||
597 | return $sql; |
||
598 | } |
||
599 | |||
600 | /** |
||
601 | * Generate SQL clauses for a single query array. |
||
602 | * |
||
603 | * If nested subqueries are found, this method recurses the tree to |
||
604 | * produce the properly nested SQL. |
||
605 | * |
||
606 | * @since 4.1.0 |
||
607 | * @access protected |
||
608 | * |
||
609 | * @param array $query Query to parse. |
||
610 | * @param int $depth Optional. Number of tree levels deep we currently are. |
||
611 | * Used to calculate indentation. Default 0. |
||
612 | * @return array { |
||
0 ignored issues
–
show
|
|||
613 | * Array containing JOIN and WHERE SQL clauses to append to a single query array. |
||
614 | * |
||
615 | * @type string $join SQL fragment to append to the main JOIN clause. |
||
616 | * @type string $where SQL fragment to append to the main WHERE clause. |
||
617 | * } |
||
618 | */ |
||
619 | View Code Duplication | protected function get_sql_for_query( $query, $depth = 0 ) { |
|
620 | $sql_chunks = array( |
||
621 | 'join' => array(), |
||
622 | 'where' => array(), |
||
623 | ); |
||
624 | |||
625 | $sql = array( |
||
626 | 'join' => '', |
||
627 | 'where' => '', |
||
628 | ); |
||
629 | |||
630 | $indent = ''; |
||
631 | for ( $i = 0; $i < $depth; $i++ ) { |
||
632 | $indent .= " "; |
||
633 | } |
||
634 | |||
635 | foreach ( $query as $key => $clause ) { |
||
636 | if ( 'relation' === $key ) { |
||
637 | $relation = $query['relation']; |
||
638 | } elseif ( is_array( $clause ) ) { |
||
639 | |||
640 | // This is a first-order clause. |
||
641 | if ( $this->is_first_order_clause( $clause ) ) { |
||
642 | $clause_sql = $this->get_sql_for_clause( $clause, $query ); |
||
643 | |||
644 | $where_count = count( $clause_sql['where'] ); |
||
645 | if ( ! $where_count ) { |
||
646 | $sql_chunks['where'][] = ''; |
||
647 | } elseif ( 1 === $where_count ) { |
||
648 | $sql_chunks['where'][] = $clause_sql['where'][0]; |
||
649 | } else { |
||
650 | $sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )'; |
||
651 | } |
||
652 | |||
653 | $sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] ); |
||
654 | // This is a subquery, so we recurse. |
||
655 | } else { |
||
656 | $clause_sql = $this->get_sql_for_query( $clause, $depth + 1 ); |
||
657 | |||
658 | $sql_chunks['where'][] = $clause_sql['where']; |
||
659 | $sql_chunks['join'][] = $clause_sql['join']; |
||
660 | } |
||
661 | } |
||
662 | } |
||
663 | |||
664 | // Filter to remove empties. |
||
665 | $sql_chunks['join'] = array_filter( $sql_chunks['join'] ); |
||
666 | $sql_chunks['where'] = array_filter( $sql_chunks['where'] ); |
||
667 | |||
668 | if ( empty( $relation ) ) { |
||
669 | $relation = 'AND'; |
||
670 | } |
||
671 | |||
672 | // Filter duplicate JOIN clauses and combine into a single string. |
||
673 | if ( ! empty( $sql_chunks['join'] ) ) { |
||
674 | $sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) ); |
||
675 | } |
||
676 | |||
677 | // Generate a single WHERE clause with proper brackets and indentation. |
||
678 | if ( ! empty( $sql_chunks['where'] ) ) { |
||
679 | $sql['where'] = '( ' . "\n " . $indent . implode( ' ' . "\n " . $indent . $relation . ' ' . "\n " . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')'; |
||
680 | } |
||
681 | |||
682 | return $sql; |
||
683 | } |
||
684 | |||
685 | /** |
||
686 | * Turns a single date clause into pieces for a WHERE clause. |
||
687 | * |
||
688 | * A wrapper for get_sql_for_clause(), included here for backward |
||
689 | * compatibility while retaining the naming convention across Query classes. |
||
690 | * |
||
691 | * @since 3.7.0 |
||
692 | * @access protected |
||
693 | * |
||
694 | * @param array $query Date query arguments. |
||
695 | * @return array { |
||
0 ignored issues
–
show
|
|||
696 | * Array containing JOIN and WHERE SQL clauses to append to the main query. |
||
697 | * |
||
698 | * @type string $join SQL fragment to append to the main JOIN clause. |
||
699 | * @type string $where SQL fragment to append to the main WHERE clause. |
||
700 | * } |
||
701 | */ |
||
702 | protected function get_sql_for_subquery( $query ) { |
||
703 | return $this->get_sql_for_clause( $query, '' ); |
||
704 | } |
||
705 | |||
706 | /** |
||
707 | * Turns a first-order date query into SQL for a WHERE clause. |
||
708 | * |
||
709 | * @since 4.1.0 |
||
710 | * @access protected |
||
711 | * |
||
712 | * @param array $query Date query clause. |
||
713 | * @param array $parent_query Parent query of the current date query. |
||
714 | * @return array { |
||
0 ignored issues
–
show
|
|||
715 | * Array containing JOIN and WHERE SQL clauses to append to the main query. |
||
716 | * |
||
717 | * @type string $join SQL fragment to append to the main JOIN clause. |
||
718 | * @type string $where SQL fragment to append to the main WHERE clause. |
||
719 | * } |
||
720 | */ |
||
721 | protected function get_sql_for_clause( $query, $parent_query ) { |
||
0 ignored issues
–
show
|
|||
722 | global $wpdb; |
||
723 | |||
724 | // The sub-parts of a $where part. |
||
725 | $where_parts = array(); |
||
726 | |||
727 | $column = ( ! empty( $query['column'] ) ) ? esc_sql( $query['column'] ) : $this->column; |
||
728 | |||
729 | $column = $this->validate_column( $column ); |
||
0 ignored issues
–
show
It seems like
$column can also be of type array ; however, WP_Date_Query::validate_column() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
730 | |||
731 | $compare = $this->get_compare( $query ); |
||
732 | |||
733 | $inclusive = ! empty( $query['inclusive'] ); |
||
734 | |||
735 | // Assign greater- and less-than values. |
||
736 | $lt = '<'; |
||
737 | $gt = '>'; |
||
738 | |||
739 | if ( $inclusive ) { |
||
740 | $lt .= '='; |
||
741 | $gt .= '='; |
||
742 | } |
||
743 | |||
744 | // Range queries. |
||
745 | if ( ! empty( $query['after'] ) ) { |
||
746 | $where_parts[] = $wpdb->prepare( "$column $gt %s", $this->build_mysql_datetime( $query['after'], ! $inclusive ) ); |
||
747 | } |
||
748 | if ( ! empty( $query['before'] ) ) { |
||
749 | $where_parts[] = $wpdb->prepare( "$column $lt %s", $this->build_mysql_datetime( $query['before'], $inclusive ) ); |
||
750 | } |
||
751 | // Specific value queries. |
||
752 | |||
753 | if ( isset( $query['year'] ) && $value = $this->build_value( $compare, $query['year'] ) ) |
||
754 | $where_parts[] = "YEAR( $column ) $compare $value"; |
||
755 | |||
756 | if ( isset( $query['month'] ) && $value = $this->build_value( $compare, $query['month'] ) ) { |
||
757 | $where_parts[] = "MONTH( $column ) $compare $value"; |
||
758 | View Code Duplication | } elseif ( isset( $query['monthnum'] ) && $value = $this->build_value( $compare, $query['monthnum'] ) ) { |
|
759 | $where_parts[] = "MONTH( $column ) $compare $value"; |
||
760 | } |
||
761 | if ( isset( $query['week'] ) && false !== ( $value = $this->build_value( $compare, $query['week'] ) ) ) { |
||
762 | $where_parts[] = _wp_mysql_week( $column ) . " $compare $value"; |
||
763 | View Code Duplication | } elseif ( isset( $query['w'] ) && false !== ( $value = $this->build_value( $compare, $query['w'] ) ) ) { |
|
764 | $where_parts[] = _wp_mysql_week( $column ) . " $compare $value"; |
||
765 | } |
||
766 | if ( isset( $query['dayofyear'] ) && $value = $this->build_value( $compare, $query['dayofyear'] ) ) |
||
767 | $where_parts[] = "DAYOFYEAR( $column ) $compare $value"; |
||
768 | |||
769 | if ( isset( $query['day'] ) && $value = $this->build_value( $compare, $query['day'] ) ) |
||
770 | $where_parts[] = "DAYOFMONTH( $column ) $compare $value"; |
||
771 | |||
772 | if ( isset( $query['dayofweek'] ) && $value = $this->build_value( $compare, $query['dayofweek'] ) ) |
||
773 | $where_parts[] = "DAYOFWEEK( $column ) $compare $value"; |
||
774 | |||
775 | if ( isset( $query['dayofweek_iso'] ) && $value = $this->build_value( $compare, $query['dayofweek_iso'] ) ) |
||
776 | $where_parts[] = "WEEKDAY( $column ) + 1 $compare $value"; |
||
777 | |||
778 | if ( isset( $query['hour'] ) || isset( $query['minute'] ) || isset( $query['second'] ) ) { |
||
779 | // Avoid notices. |
||
780 | foreach ( array( 'hour', 'minute', 'second' ) as $unit ) { |
||
781 | if ( ! isset( $query[ $unit ] ) ) { |
||
782 | $query[ $unit ] = null; |
||
783 | } |
||
784 | } |
||
785 | |||
786 | if ( $time_query = $this->build_time_query( $column, $compare, $query['hour'], $query['minute'], $query['second'] ) ) { |
||
787 | $where_parts[] = $time_query; |
||
788 | } |
||
789 | } |
||
790 | |||
791 | /* |
||
792 | * Return an array of 'join' and 'where' for compatibility |
||
793 | * with other query classes. |
||
794 | */ |
||
795 | return array( |
||
796 | 'where' => $where_parts, |
||
797 | 'join' => array(), |
||
798 | ); |
||
799 | } |
||
800 | |||
801 | /** |
||
802 | * Builds and validates a value string based on the comparison operator. |
||
803 | * |
||
804 | * @since 3.7.0 |
||
805 | * @access public |
||
806 | * |
||
807 | * @param string $compare The compare operator to use |
||
808 | * @param string|array $value The value |
||
809 | * @return string|false|int The value to be used in SQL or false on error. |
||
810 | */ |
||
811 | public function build_value( $compare, $value ) { |
||
812 | if ( ! isset( $value ) ) |
||
813 | return false; |
||
814 | |||
815 | switch ( $compare ) { |
||
816 | case 'IN': |
||
817 | case 'NOT IN': |
||
818 | $value = (array) $value; |
||
819 | |||
820 | // Remove non-numeric values. |
||
821 | $value = array_filter( $value, 'is_numeric' ); |
||
822 | |||
823 | if ( empty( $value ) ) { |
||
824 | return false; |
||
825 | } |
||
826 | |||
827 | return '(' . implode( ',', array_map( 'intval', $value ) ) . ')'; |
||
828 | |||
829 | case 'BETWEEN': |
||
830 | case 'NOT BETWEEN': |
||
831 | if ( ! is_array( $value ) || 2 != count( $value ) ) { |
||
832 | $value = array( $value, $value ); |
||
833 | } else { |
||
834 | $value = array_values( $value ); |
||
835 | } |
||
836 | |||
837 | // If either value is non-numeric, bail. |
||
838 | foreach ( $value as $v ) { |
||
839 | if ( ! is_numeric( $v ) ) { |
||
840 | return false; |
||
841 | } |
||
842 | } |
||
843 | |||
844 | $value = array_map( 'intval', $value ); |
||
845 | |||
846 | return $value[0] . ' AND ' . $value[1]; |
||
847 | |||
848 | default; |
||
849 | if ( ! is_numeric( $value ) ) { |
||
850 | return false; |
||
851 | } |
||
852 | |||
853 | return (int) $value; |
||
854 | } |
||
855 | } |
||
856 | |||
857 | /** |
||
858 | * Builds a MySQL format date/time based on some query parameters. |
||
859 | * |
||
860 | * You can pass an array of values (year, month, etc.) with missing parameter values being defaulted to |
||
861 | * either the maximum or minimum values (controlled by the $default_to parameter). Alternatively you can |
||
862 | * pass a string that will be run through strtotime(). |
||
863 | * |
||
864 | * @since 3.7.0 |
||
865 | * @access public |
||
866 | * |
||
867 | * @param string|array $datetime An array of parameters or a strotime() string |
||
868 | * @param bool $default_to_max Whether to round up incomplete dates. Supported by values |
||
869 | * of $datetime that are arrays, or string values that are a |
||
870 | * subset of MySQL date format ('Y', 'Y-m', 'Y-m-d', 'Y-m-d H:i'). |
||
871 | * Default: false. |
||
872 | * @return string|false A MySQL format date/time or false on failure |
||
873 | */ |
||
874 | public function build_mysql_datetime( $datetime, $default_to_max = false ) { |
||
875 | $now = current_time( 'timestamp' ); |
||
876 | |||
877 | if ( ! is_array( $datetime ) ) { |
||
878 | |||
879 | /* |
||
880 | * Try to parse some common date formats, so we can detect |
||
881 | * the level of precision and support the 'inclusive' parameter. |
||
882 | */ |
||
883 | if ( preg_match( '/^(\d{4})$/', $datetime, $matches ) ) { |
||
884 | // Y |
||
885 | $datetime = array( |
||
886 | 'year' => intval( $matches[1] ), |
||
887 | ); |
||
888 | |||
889 | } elseif ( preg_match( '/^(\d{4})\-(\d{2})$/', $datetime, $matches ) ) { |
||
890 | // Y-m |
||
891 | $datetime = array( |
||
892 | 'year' => intval( $matches[1] ), |
||
893 | 'month' => intval( $matches[2] ), |
||
894 | ); |
||
895 | |||
896 | } elseif ( preg_match( '/^(\d{4})\-(\d{2})\-(\d{2})$/', $datetime, $matches ) ) { |
||
897 | // Y-m-d |
||
898 | $datetime = array( |
||
899 | 'year' => intval( $matches[1] ), |
||
900 | 'month' => intval( $matches[2] ), |
||
901 | 'day' => intval( $matches[3] ), |
||
902 | ); |
||
903 | |||
904 | } elseif ( preg_match( '/^(\d{4})\-(\d{2})\-(\d{2}) (\d{2}):(\d{2})$/', $datetime, $matches ) ) { |
||
905 | // Y-m-d H:i |
||
906 | $datetime = array( |
||
907 | 'year' => intval( $matches[1] ), |
||
908 | 'month' => intval( $matches[2] ), |
||
909 | 'day' => intval( $matches[3] ), |
||
910 | 'hour' => intval( $matches[4] ), |
||
911 | 'minute' => intval( $matches[5] ), |
||
912 | ); |
||
913 | } |
||
914 | |||
915 | // If no match is found, we don't support default_to_max. |
||
916 | if ( ! is_array( $datetime ) ) { |
||
917 | // @todo Timezone issues here possibly |
||
918 | return gmdate( 'Y-m-d H:i:s', strtotime( $datetime, $now ) ); |
||
919 | } |
||
920 | } |
||
921 | |||
922 | $datetime = array_map( 'absint', $datetime ); |
||
923 | |||
924 | if ( ! isset( $datetime['year'] ) ) |
||
925 | $datetime['year'] = gmdate( 'Y', $now ); |
||
926 | |||
927 | if ( ! isset( $datetime['month'] ) ) |
||
928 | $datetime['month'] = ( $default_to_max ) ? 12 : 1; |
||
929 | |||
930 | if ( ! isset( $datetime['day'] ) ) |
||
931 | $datetime['day'] = ( $default_to_max ) ? (int) date( 't', mktime( 0, 0, 0, $datetime['month'], 1, $datetime['year'] ) ) : 1; |
||
932 | |||
933 | if ( ! isset( $datetime['hour'] ) ) |
||
934 | $datetime['hour'] = ( $default_to_max ) ? 23 : 0; |
||
935 | |||
936 | if ( ! isset( $datetime['minute'] ) ) |
||
937 | $datetime['minute'] = ( $default_to_max ) ? 59 : 0; |
||
938 | |||
939 | if ( ! isset( $datetime['second'] ) ) |
||
940 | $datetime['second'] = ( $default_to_max ) ? 59 : 0; |
||
941 | |||
942 | return sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $datetime['year'], $datetime['month'], $datetime['day'], $datetime['hour'], $datetime['minute'], $datetime['second'] ); |
||
943 | } |
||
944 | |||
945 | /** |
||
946 | * Builds a query string for comparing time values (hour, minute, second). |
||
947 | * |
||
948 | * If just hour, minute, or second is set than a normal comparison will be done. |
||
949 | * However if multiple values are passed, a pseudo-decimal time will be created |
||
950 | * in order to be able to accurately compare against. |
||
951 | * |
||
952 | * @since 3.7.0 |
||
953 | * @access public |
||
954 | * |
||
955 | * @param string $column The column to query against. Needs to be pre-validated! |
||
956 | * @param string $compare The comparison operator. Needs to be pre-validated! |
||
957 | * @param int|null $hour Optional. An hour value (0-23). |
||
958 | * @param int|null $minute Optional. A minute value (0-59). |
||
959 | * @param int|null $second Optional. A second value (0-59). |
||
960 | * @return string|false A query part or false on failure. |
||
961 | */ |
||
962 | public function build_time_query( $column, $compare, $hour = null, $minute = null, $second = null ) { |
||
963 | global $wpdb; |
||
964 | |||
965 | // Have to have at least one |
||
966 | if ( ! isset( $hour ) && ! isset( $minute ) && ! isset( $second ) ) |
||
967 | return false; |
||
968 | |||
969 | // Complex combined queries aren't supported for multi-value queries |
||
970 | if ( in_array( $compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) { |
||
971 | $return = array(); |
||
972 | |||
973 | View Code Duplication | if ( isset( $hour ) && false !== ( $value = $this->build_value( $compare, $hour ) ) ) |
|
974 | $return[] = "HOUR( $column ) $compare $value"; |
||
975 | |||
976 | View Code Duplication | if ( isset( $minute ) && false !== ( $value = $this->build_value( $compare, $minute ) ) ) |
|
977 | $return[] = "MINUTE( $column ) $compare $value"; |
||
978 | |||
979 | View Code Duplication | if ( isset( $second ) && false !== ( $value = $this->build_value( $compare, $second ) ) ) |
|
980 | $return[] = "SECOND( $column ) $compare $value"; |
||
981 | |||
982 | return implode( ' AND ', $return ); |
||
983 | } |
||
984 | |||
985 | // Cases where just one unit is set |
||
986 | if ( isset( $hour ) && ! isset( $minute ) && ! isset( $second ) && false !== ( $value = $this->build_value( $compare, $hour ) ) ) { |
||
987 | return "HOUR( $column ) $compare $value"; |
||
988 | } elseif ( ! isset( $hour ) && isset( $minute ) && ! isset( $second ) && false !== ( $value = $this->build_value( $compare, $minute ) ) ) { |
||
989 | return "MINUTE( $column ) $compare $value"; |
||
990 | } elseif ( ! isset( $hour ) && ! isset( $minute ) && isset( $second ) && false !== ( $value = $this->build_value( $compare, $second ) ) ) { |
||
991 | return "SECOND( $column ) $compare $value"; |
||
992 | } |
||
993 | |||
994 | // Single units were already handled. Since hour & second isn't allowed, minute must to be set. |
||
995 | if ( ! isset( $minute ) ) |
||
996 | return false; |
||
997 | |||
998 | $format = $time = ''; |
||
999 | |||
1000 | // Hour |
||
1001 | if ( null !== $hour ) { |
||
1002 | $format .= '%H.'; |
||
1003 | $time .= sprintf( '%02d', $hour ) . '.'; |
||
1004 | } else { |
||
1005 | $format .= '0.'; |
||
1006 | $time .= '0.'; |
||
1007 | } |
||
1008 | |||
1009 | // Minute |
||
1010 | $format .= '%i'; |
||
1011 | $time .= sprintf( '%02d', $minute ); |
||
1012 | |||
1013 | if ( isset( $second ) ) { |
||
1014 | $format .= '%s'; |
||
1015 | $time .= sprintf( '%02d', $second ); |
||
1016 | } |
||
1017 | |||
1018 | return $wpdb->prepare( "DATE_FORMAT( $column, %s ) $compare %f", $format, $time ); |
||
1019 | } |
||
1020 | } |
||
1021 |
This check looks for
@param
annotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type
array
and suggests a stricter type likearray<String>
.Most often this is a case of a parameter that can be null in addition to its declared types.