Issues (2010)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

wp-includes/class-wp-site-query.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Site API: WP_Site_Query class
4
 *
5
 * @package WordPress
6
 * @subpackage Sites
7
 * @since 4.6.0
8
 */
9
10
/**
11
 * Core class used for querying sites.
12
 *
13
 * @since 4.6.0
14
 *
15
 * @see WP_Site_Query::__construct() for accepted arguments.
16
 */
17
class WP_Site_Query {
18
19
	/**
20
	 * SQL for database query.
21
	 *
22
	 * @since 4.6.0
23
	 * @access public
24
	 * @var string
25
	 */
26
	public $request;
27
28
	/**
29
	 * SQL query clauses.
30
	 *
31
	 * @since 4.6.0
32
	 * @access protected
33
	 * @var array
34
	 */
35
	protected $sql_clauses = array(
36
		'select'  => '',
37
		'from'    => '',
38
		'where'   => array(),
39
		'groupby' => '',
40
		'orderby' => '',
41
		'limits'  => '',
42
	);
43
44
	/**
45
	 * Date query container.
46
	 *
47
	 * @since 4.6.0
48
	 * @access public
49
	 * @var object WP_Date_Query
50
	 */
51
	public $date_query = false;
52
53
	/**
54
	 * Query vars set by the user.
55
	 *
56
	 * @since 4.6.0
57
	 * @access public
58
	 * @var array
59
	 */
60
	public $query_vars;
61
62
	/**
63
	 * Default values for query vars.
64
	 *
65
	 * @since 4.6.0
66
	 * @access public
67
	 * @var array
68
	 */
69
	public $query_var_defaults;
70
71
	/**
72
	 * List of sites located by the query.
73
	 *
74
	 * @since 4.6.0
75
	 * @access public
76
	 * @var array
77
	 */
78
	public $sites;
79
80
	/**
81
	 * The amount of found sites for the current query.
82
	 *
83
	 * @since 4.6.0
84
	 * @access public
85
	 * @var int
86
	 */
87
	public $found_sites = 0;
88
89
	/**
90
	 * The number of pages.
91
	 *
92
	 * @since 4.6.0
93
	 * @access public
94
	 * @var int
95
	 */
96
	public $max_num_pages = 0;
97
98
	/**
99
	 * @since 4.7.0
100
	 * @access protected
101
	 * @var wpdb
102
	 */
103
	protected $db;
104
105
	/**
106
	 * Sets up the site query, based on the query vars passed.
107
	 *
108
	 * @since 4.6.0
109
	 * @access public
110
	 *
111
	 * @param string|array $query {
112
	 *     Optional. Array or query string of site query parameters. Default empty.
113
	 *
114
	 *     @type array        $site__in          Array of site IDs to include. Default empty.
115
	 *     @type array        $site__not_in      Array of site IDs to exclude. Default empty.
116
	 *     @type bool         $count             Whether to return a site count (true) or array of site objects.
117
	 *                                           Default false.
118
	 *     @type array        $date_query        Date query clauses to limit sites by. See WP_Date_Query.
119
	 *                                           Default null.
120
	 *     @type string       $fields            Site fields to return. Accepts 'ids' (returns an array of site IDs)
121
	 *                                           or empty (returns an array of complete site objects). Default empty.
122
	 *     @type int          $ID                A site ID to only return that site. Default empty.
123
	 *     @type int          $number            Maximum number of sites to retrieve. Default null (no limit).
124
	 *     @type int          $offset            Number of sites to offset the query. Used to build LIMIT clause.
125
	 *                                           Default 0.
126
	 *     @type bool         $no_found_rows     Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true.
127
	 *     @type string|array $orderby           Site status or array of statuses. Accepts 'id', 'domain', 'path',
128
	 *                                           'network_id', 'last_updated', 'registered', 'domain_length',
129
	 *                                           'path_length', 'site__in' and 'network__in'. Also accepts false,
130
	 *                                           an empty array, or 'none' to disable `ORDER BY` clause.
131
	 *                                           Default 'id'.
132
	 *     @type string       $order             How to order retrieved sites. Accepts 'ASC', 'DESC'. Default 'ASC'.
133
	 *     @type int          $network_id        Limit results to those affiliated with a given network ID. If 0,
134
	 *                                           include all networks. Default 0.
135
	 *     @type array        $network__in       Array of network IDs to include affiliated sites for. Default empty.
136
	 *     @type array        $network__not_in   Array of network IDs to exclude affiliated sites for. Default empty.
137
	 *     @type string       $domain            Limit results to those affiliated with a given domain.
138
	 *                                           Default empty.
139
	 *     @type array        $domain__in        Array of domains to include affiliated sites for. Default empty.
140
	 *     @type array        $domain__not_in    Array of domains to exclude affiliated sites for. Default empty.
141
	 *     @type string       $path              Limit results to those affiliated with a given path.
142
	 *                                           Default empty.
143
	 *     @type array        $path__in          Array of paths to include affiliated sites for. Default empty.
144
	 *     @type array        $path__not_in      Array of paths to exclude affiliated sites for. Default empty.
145
	 *     @type int          $public            Limit results to public sites. Accepts '1' or '0'. Default empty.
146
	 *     @type int          $archived          Limit results to archived sites. Accepts '1' or '0'. Default empty.
147
	 *     @type int          $mature            Limit results to mature sites. Accepts '1' or '0'. Default empty.
148
	 *     @type int          $spam              Limit results to spam sites. Accepts '1' or '0'. Default empty.
149
	 *     @type int          $deleted           Limit results to deleted sites. Accepts '1' or '0'. Default empty.
150
	 *     @type string       $search            Search term(s) to retrieve matching sites for. Default empty.
151
	 *     @type array        $search_columns    Array of column names to be searched. Accepts 'domain' and 'path'.
152
	 *                                           Default empty array.
153
	 *     @type bool         $update_site_cache Whether to prime the cache for found sites. Default false.
154
	 * }
155
	 */
156
	public function __construct( $query = '' ) {
157
		$this->db = $GLOBALS['wpdb'];
158
159
		$this->query_var_defaults = array(
160
			'fields'            => '',
161
			'ID'                => '',
162
			'site__in'          => '',
163
			'site__not_in'      => '',
164
			'number'            => 100,
165
			'offset'            => '',
166
			'no_found_rows'     => true,
167
			'orderby'           => 'id',
168
			'order'             => 'ASC',
169
			'network_id'        => 0,
170
			'network__in'       => '',
171
			'network__not_in'   => '',
172
			'domain'            => '',
173
			'domain__in'        => '',
174
			'domain__not_in'    => '',
175
			'path'              => '',
176
			'path__in'          => '',
177
			'path__not_in'      => '',
178
			'public'            => null,
179
			'archived'          => null,
180
			'mature'            => null,
181
			'spam'              => null,
182
			'deleted'           => null,
183
			'search'            => '',
184
			'search_columns'    => array(),
185
			'count'             => false,
186
			'date_query'        => null, // See WP_Date_Query
187
			'update_site_cache' => true,
188
		);
189
190
		if ( ! empty( $query ) ) {
191
			$this->query( $query );
192
		}
193
	}
194
195
	/**
196
	 * Parses arguments passed to the site query with default query parameters.
197
	 *
198
	 * @since 4.6.0
199
	 * @access public
200
	 *
201
	 * @see WP_Site_Query::__construct()
202
	 *
203
	 * @param string|array $query Array or string of WP_Site_Query arguments. See WP_Site_Query::__construct().
204
	 */
205 View Code Duplication
	public function parse_query( $query = '' ) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
206
		if ( empty( $query ) ) {
207
			$query = $this->query_vars;
208
		}
209
210
		$this->query_vars = wp_parse_args( $query, $this->query_var_defaults );
211
212
		/**
213
		 * Fires after the site query vars have been parsed.
214
		 *
215
		 * @since 4.6.0
216
		 *
217
		 * @param WP_Site_Query &$this The WP_Site_Query instance (passed by reference).
218
		 */
219
		do_action_ref_array( 'parse_site_query', array( &$this ) );
220
	}
221
222
	/**
223
	 * Sets up the WordPress query for retrieving sites.
224
	 *
225
	 * @since 4.6.0
226
	 * @access public
227
	 *
228
	 * @param string|array $query Array or URL query string of parameters.
229
	 * @return array|int List of sites, or number of sites when 'count' is passed as a query var.
230
	 */
231
	public function query( $query ) {
232
		$this->query_vars = wp_parse_args( $query );
233
234
		return $this->get_sites();
235
	}
236
237
	/**
238
	 * Retrieves a list of sites matching the query vars.
239
	 *
240
	 * @since 4.6.0
241
	 * @access public
242
	 *
243
	 * @return array|int List of sites, or number of sites when 'count' is passed as a query var.
244
	 */
245 View Code Duplication
	public function get_sites() {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
246
		$this->parse_query();
247
248
		/**
249
		 * Fires before sites are retrieved.
250
		 *
251
		 * @since 4.6.0
252
		 *
253
		 * @param WP_Site_Query &$this Current instance of WP_Site_Query, passed by reference.
254
		 */
255
		do_action_ref_array( 'pre_get_sites', array( &$this ) );
256
257
		// $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
258
		$key = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) );
259
		$last_changed = wp_cache_get( 'last_changed', 'sites' );
260
		if ( ! $last_changed ) {
261
			$last_changed = microtime();
262
			wp_cache_set( 'last_changed', $last_changed, 'sites' );
263
		}
264
265
		$cache_key = "get_sites:$key:$last_changed";
266
		$cache_value = wp_cache_get( $cache_key, 'sites' );
267
268
		if ( false === $cache_value ) {
269
			$site_ids = $this->get_site_ids();
270
			if ( $site_ids ) {
271
				$this->set_found_sites();
272
			}
273
274
			$cache_value = array(
275
				'site_ids' => $site_ids,
276
				'found_sites' => $this->found_sites,
277
			);
278
			wp_cache_add( $cache_key, $cache_value, 'sites' );
279
		} else {
280
			$site_ids = $cache_value['site_ids'];
281
			$this->found_sites = $cache_value['found_sites'];
282
		}
283
284
		if ( $this->found_sites && $this->query_vars['number'] ) {
285
			$this->max_num_pages = ceil( $this->found_sites / $this->query_vars['number'] );
0 ignored issues
show
Documentation Bug introduced by
The property $max_num_pages was declared of type integer, but ceil($this->found_sites ...->query_vars['number']) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
286
		}
287
288
		// If querying for a count only, there's nothing more to do.
289
		if ( $this->query_vars['count'] ) {
290
			// $site_ids is actually a count in this case.
291
			return intval( $site_ids );
292
		}
293
294
		$site_ids = array_map( 'intval', $site_ids );
295
296
		if ( 'ids' == $this->query_vars['fields'] ) {
297
			$this->sites = $site_ids;
298
299
			return $this->sites;
300
		}
301
302
		// Prime site network caches.
303
		if ( $this->query_vars['update_site_cache'] ) {
304
			_prime_site_caches( $site_ids );
305
		}
306
307
		// Fetch full site objects from the primed cache.
308
		$_sites = array();
309
		foreach ( $site_ids as $site_id ) {
310
			if ( $_site = get_site( $site_id ) ) {
311
				$_sites[] = $_site;
312
			}
313
		}
314
315
		/**
316
		 * Filters the site query results.
317
		 *
318
		 * @since 4.6.0
319
		 *
320
		 * @param array         $results An array of sites.
321
		 * @param WP_Site_Query &$this   Current instance of WP_Site_Query, passed by reference.
322
		 */
323
		$_sites = apply_filters_ref_array( 'the_sites', array( $_sites, &$this ) );
324
325
		// Convert to WP_Site instances.
326
		$this->sites = array_map( 'get_site', $_sites );
327
328
		return $this->sites;
329
	}
330
331
	/**
332
	 * Used internally to get a list of site IDs matching the query vars.
333
	 *
334
	 * @since 4.6.0
335
	 * @access protected
336
	 *
337
	 * @return int|array A single count of site IDs if a count query. An array of site IDs if a full query.
338
	 */
339
	protected function get_site_ids() {
340
		$order = $this->parse_order( $this->query_vars['order'] );
341
342
		// Disable ORDER BY with 'none', an empty array, or boolean false.
343 View Code Duplication
		if ( in_array( $this->query_vars['orderby'], array( 'none', array(), false ), true ) ) {
344
			$orderby = '';
345
		} elseif ( ! empty( $this->query_vars['orderby'] ) ) {
346
			$ordersby = is_array( $this->query_vars['orderby'] ) ?
347
				$this->query_vars['orderby'] :
348
				preg_split( '/[,\s]/', $this->query_vars['orderby'] );
349
350
			$orderby_array = array();
351
			foreach ( $ordersby as $_key => $_value ) {
352
				if ( ! $_value ) {
353
					continue;
354
				}
355
356
				if ( is_int( $_key ) ) {
357
					$_orderby = $_value;
358
					$_order = $order;
359
				} else {
360
					$_orderby = $_key;
361
					$_order = $_value;
362
				}
363
364
				$parsed = $this->parse_orderby( $_orderby );
365
366
				if ( ! $parsed ) {
367
					continue;
368
				}
369
370
				if ( 'site__in' === $_orderby || 'network__in' === $_orderby ) {
371
					$orderby_array[] = $parsed;
372
					continue;
373
				}
374
375
				$orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
376
			}
377
378
			$orderby = implode( ', ', $orderby_array );
379
		} else {
380
			$orderby = "blog_id $order";
381
		}
382
383
		$number = absint( $this->query_vars['number'] );
384
		$offset = absint( $this->query_vars['offset'] );
385
386 View Code Duplication
		if ( ! empty( $number ) ) {
387
			if ( $offset ) {
388
				$limits = 'LIMIT ' . $offset . ',' . $number;
389
			} else {
390
				$limits = 'LIMIT ' . $number;
391
			}
392
		}
393
394
		if ( $this->query_vars['count'] ) {
395
			$fields = 'COUNT(*)';
396
		} else {
397
			$fields = 'blog_id';
398
		}
399
400
		// Parse site IDs for an IN clause.
401
		$site_id = absint( $this->query_vars['ID'] );
402 View Code Duplication
		if ( ! empty( $site_id ) ) {
403
			$this->sql_clauses['where']['ID'] = $this->db->prepare( 'blog_id = %d', $site_id );
404
		}
405
406
		// Parse site IDs for an IN clause.
407
		if ( ! empty( $this->query_vars['site__in'] ) ) {
408
			$this->sql_clauses['where']['site__in'] = "blog_id IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__in'] ) ) . ' )';
409
		}
410
411
		// Parse site IDs for a NOT IN clause.
412
		if ( ! empty( $this->query_vars['site__not_in'] ) ) {
413
			$this->sql_clauses['where']['site__not_in'] = "blog_id NOT IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__not_in'] ) ) . ' )';
414
		}
415
416
		$network_id = absint( $this->query_vars['network_id'] );
417
418 View Code Duplication
		if ( ! empty( $network_id ) ) {
419
			$this->sql_clauses['where']['network_id'] = $this->db->prepare( 'site_id = %d', $network_id );
420
		}
421
422
		// Parse site network IDs for an IN clause.
423
		if ( ! empty( $this->query_vars['network__in'] ) ) {
424
			$this->sql_clauses['where']['network__in'] = 'site_id IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['network__in'] ) ) . ' )';
425
		}
426
427
		// Parse site network IDs for a NOT IN clause.
428
		if ( ! empty( $this->query_vars['network__not_in'] ) ) {
429
			$this->sql_clauses['where']['network__not_in'] = 'site_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['network__not_in'] ) ) . ' )';
430
		}
431
432 View Code Duplication
		if ( ! empty( $this->query_vars['domain'] ) ) {
433
			$this->sql_clauses['where']['domain'] = $this->db->prepare( 'domain = %s', $this->query_vars['domain'] );
434
		}
435
436
		// Parse site domain for an IN clause.
437
		if ( is_array( $this->query_vars['domain__in'] ) ) {
438
			$this->sql_clauses['where']['domain__in'] = "domain IN ( '" . implode( "', '", $this->db->_escape( $this->query_vars['domain__in'] ) ) . "' )";
439
		}
440
441
		// Parse site domain for a NOT IN clause.
442
		if ( is_array( $this->query_vars['domain__not_in'] ) ) {
443
			$this->sql_clauses['where']['domain__not_in'] = "domain NOT IN ( '" . implode( "', '", $this->db->_escape( $this->query_vars['domain__not_in'] ) ) . "' )";
444
		}
445
446 View Code Duplication
		if ( ! empty( $this->query_vars['path'] ) ) {
447
			$this->sql_clauses['where']['path'] = $this->db->prepare( 'path = %s', $this->query_vars['path'] );
448
		}
449
450
		// Parse site path for an IN clause.
451
		if ( is_array( $this->query_vars['path__in'] ) ) {
452
			$this->sql_clauses['where']['path__in'] = "path IN ( '" . implode( "', '", $this->db->_escape( $this->query_vars['path__in'] ) ) . "' )";
453
		}
454
455
		// Parse site path for a NOT IN clause.
456
		if ( is_array( $this->query_vars['path__not_in'] ) ) {
457
			$this->sql_clauses['where']['path__not_in'] = "path NOT IN ( '" . implode( "', '", $this->db->_escape( $this->query_vars['path__not_in'] ) ) . "' )";
458
		}
459
460 View Code Duplication
		if ( is_numeric( $this->query_vars['archived'] ) ) {
461
			$archived = absint( $this->query_vars['archived'] );
462
			$this->sql_clauses['where']['archived'] = $this->db->prepare( "archived = %d ", $archived );
463
		}
464
465 View Code Duplication
		if ( is_numeric( $this->query_vars['mature'] ) ) {
466
			$mature = absint( $this->query_vars['mature'] );
467
			$this->sql_clauses['where']['mature'] = $this->db->prepare( "mature = %d ", $mature );
468
		}
469
470 View Code Duplication
		if ( is_numeric( $this->query_vars['spam'] ) ) {
471
			$spam = absint( $this->query_vars['spam'] );
472
			$this->sql_clauses['where']['spam'] = $this->db->prepare( "spam = %d ", $spam );
473
		}
474
475 View Code Duplication
		if ( is_numeric( $this->query_vars['deleted'] ) ) {
476
			$deleted = absint( $this->query_vars['deleted'] );
477
			$this->sql_clauses['where']['deleted'] = $this->db->prepare( "deleted = %d ", $deleted );
478
		}
479
480 View Code Duplication
		if ( is_numeric( $this->query_vars['public'] ) ) {
481
			$public = absint( $this->query_vars['public'] );
482
			$this->sql_clauses['where']['public'] = $this->db->prepare( "public = %d ", $public );
483
		}
484
485
		// Falsey search strings are ignored.
486
		if ( strlen( $this->query_vars['search'] ) ) {
487
			$search_columns = array();
488
489
			if ( $this->query_vars['search_columns'] ) {
490
				$search_columns = array_intersect( $this->query_vars['search_columns'], array( 'domain', 'path' ) );
491
			}
492
493
			if ( ! $search_columns ) {
494
				$search_columns = array( 'domain', 'path' );
495
			}
496
497
			/**
498
			 * Filters the columns to search in a WP_Site_Query search.
499
			 *
500
			 * The default columns include 'domain' and 'path.
501
			 *
502
			 * @since 4.6.0
503
			 *
504
			 * @param array         $search_columns Array of column names to be searched.
505
			 * @param string        $search         Text being searched.
506
			 * @param WP_Site_Query $this           The current WP_Site_Query instance.
507
			 */
508
			$search_columns = apply_filters( 'site_search_columns', $search_columns, $this->query_vars['search'], $this );
509
510
			$this->sql_clauses['where']['search'] = $this->get_search_sql( $this->query_vars['search'], $search_columns );
511
		}
512
513
		$date_query = $this->query_vars['date_query'];
514
		if ( ! empty( $date_query ) && is_array( $date_query ) ) {
515
			$this->date_query = new WP_Date_Query( $date_query, 'registered' );
516
			$this->sql_clauses['where']['date_query'] = preg_replace( '/^\s*AND\s*/', '', $this->date_query->get_sql() );
517
		}
518
519
		$where = implode( ' AND ', $this->sql_clauses['where'] );
520
521
		$pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' );
522
523
		/**
524
		 * Filters the site query clauses.
525
		 *
526
		 * @since 4.6.0
527
		 *
528
		 * @param array $pieces A compacted array of site query clauses.
529
		 * @param WP_Site_Query &$this Current instance of WP_Site_Query, passed by reference.
530
		 */
531
		$clauses = apply_filters_ref_array( 'sites_clauses', array( compact( $pieces ), &$this ) );
532
533
		$fields = isset( $clauses['fields'] ) ? $clauses['fields'] : '';
534
		$join = isset( $clauses['join'] ) ? $clauses['join'] : '';
535
		$where = isset( $clauses['where'] ) ? $clauses['where'] : '';
536
		$orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : '';
537
		$limits = isset( $clauses['limits'] ) ? $clauses['limits'] : '';
538
		$groupby = isset( $clauses['groupby'] ) ? $clauses['groupby'] : '';
539
540
		if ( $where ) {
541
			$where = 'WHERE ' . $where;
542
		}
543
544
		if ( $groupby ) {
545
			$groupby = 'GROUP BY ' . $groupby;
546
		}
547
548
		if ( $orderby ) {
549
			$orderby = "ORDER BY $orderby";
550
		}
551
552
		$found_rows = '';
553
		if ( ! $this->query_vars['no_found_rows'] ) {
554
			$found_rows = 'SQL_CALC_FOUND_ROWS';
555
		}
556
557
		$this->sql_clauses['select']  = "SELECT $found_rows $fields";
558
		$this->sql_clauses['from']    = "FROM {$this->db->blogs} $join";
559
		$this->sql_clauses['groupby'] = $groupby;
560
		$this->sql_clauses['orderby'] = $orderby;
561
		$this->sql_clauses['limits']  = $limits;
562
563
		$this->request = "{$this->sql_clauses['select']} {$this->sql_clauses['from']} {$where} {$this->sql_clauses['groupby']} {$this->sql_clauses['orderby']} {$this->sql_clauses['limits']}";
564
565
		if ( $this->query_vars['count'] ) {
566
			return intval( $this->db->get_var( $this->request ) );
567
		}
568
569
		$site_ids = $this->db->get_col( $this->request );
570
571
		return array_map( 'intval', $site_ids );
572
	}
573
574
	/**
575
	 * Populates found_sites and max_num_pages properties for the current query
576
	 * if the limit clause was used.
577
	 *
578
	 * @since 4.6.0
579
	 * @access private
580
	 */
581 View Code Duplication
	private function set_found_sites() {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
582
		if ( $this->query_vars['number'] && ! $this->query_vars['no_found_rows'] ) {
583
			/**
584
			 * Filters the query used to retrieve found site count.
585
			 *
586
			 * @since 4.6.0
587
			 *
588
			 * @param string        $found_sites_query SQL query. Default 'SELECT FOUND_ROWS()'.
589
			 * @param WP_Site_Query $site_query        The `WP_Site_Query` instance.
590
			 */
591
			$found_sites_query = apply_filters( 'found_sites_query', 'SELECT FOUND_ROWS()', $this );
592
593
			$this->found_sites = (int) $this->db->get_var( $found_sites_query );
594
		}
595
	}
596
597
	/**
598
	 * Used internally to generate an SQL string for searching across multiple columns.
599
	 *
600
	 * @since 4.6.0
601
	 * @access protected
602
	 *
603
	 * @param string $string  Search string.
604
	 * @param array  $columns Columns to search.
605
	 * @return string Search SQL.
606
	 */
607
	protected function get_search_sql( $string, $columns ) {
608
		if ( false !== strpos( $string, '*' ) ) {
609
			$like = '%' . implode( '%', array_map( array( $this->db, 'esc_like' ), explode( '*', $string ) ) ) . '%';
610
		} else {
611
			$like = '%' . $this->db->esc_like( $string ) . '%';
612
		}
613
614
		$searches = array();
615
		foreach ( $columns as $column ) {
616
			$searches[] = $this->db->prepare( "$column LIKE %s", $like );
617
		}
618
619
		return '(' . implode( ' OR ', $searches ) . ')';
620
	}
621
622
	/**
623
	 * Parses and sanitizes 'orderby' keys passed to the site query.
624
	 *
625
	 * @since 4.6.0
626
	 * @access protected
627
	 *
628
	 * @param string $orderby Alias for the field to order by.
629
	 * @return string|false Value to used in the ORDER clause. False otherwise.
630
	 */
631
	protected function parse_orderby( $orderby ) {
632
		$parsed = false;
633
634
		switch ( $orderby ) {
635
			case 'site__in':
636
				$site__in = implode( ',', array_map( 'absint', $this->query_vars['site__in'] ) );
637
				$parsed = "FIELD( {$this->db->blogs}.blog_id, $site__in )";
638
				break;
639
			case 'network__in':
640
				$network__in = implode( ',', array_map( 'absint', $this->query_vars['network__in'] ) );
641
				$parsed = "FIELD( {$this->db->blogs}.site_id, $network__in )";
642
				break;
643
			case 'domain':
644
			case 'last_updated':
645
			case 'path':
646
			case 'registered':
647
				$parsed = $orderby;
648
				break;
649
			case 'network_id':
650
				$parsed = 'site_id';
651
				break;
652
			case 'domain_length':
653
				$parsed = 'CHAR_LENGTH(domain)';
654
				break;
655
			case 'path_length':
656
				$parsed = 'CHAR_LENGTH(path)';
657
				break;
658
			case 'id':
659
				$parsed = 'blog_id';
660
				break;
661
		}
662
663
		return $parsed;
664
	}
665
666
	/**
667
	 * Parses an 'order' query variable and cast it to 'ASC' or 'DESC' as necessary.
668
	 *
669
	 * @since 4.6.0
670
	 * @access protected
671
	 *
672
	 * @param string $order The 'order' query variable.
673
	 * @return string The sanitized 'order' query variable.
674
	 */
675 View Code Duplication
	protected function parse_order( $order ) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
676
		if ( ! is_string( $order ) || empty( $order ) ) {
677
			return 'ASC';
678
		}
679
680
		if ( 'ASC' === strtoupper( $order ) ) {
681
			return 'ASC';
682
		} else {
683
			return 'DESC';
684
		}
685
	}
686
}
687