Issues (4122)

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.

includes/search/SearchEngine.php (4 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
 * Basic search engine
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
 * http://www.gnu.org/copyleft/gpl.html
19
 *
20
 * @file
21
 * @ingroup Search
22
 */
23
24
/**
25
 * @defgroup Search Search
26
 */
27
28
use MediaWiki\MediaWikiServices;
29
30
/**
31
 * Contain a class for special pages
32
 * @ingroup Search
33
 */
34
abstract class SearchEngine {
35
	/** @var string */
36
	public $prefix = '';
37
38
	/** @var int[]|null */
39
	public $namespaces = [ NS_MAIN ];
40
41
	/** @var int */
42
	protected $limit = 10;
43
44
	/** @var int */
45
	protected $offset = 0;
46
47
	/** @var array|string */
48
	protected $searchTerms = [];
49
50
	/** @var bool */
51
	protected $showSuggestion = true;
52
	private $sort = 'relevance';
53
54
	/** @var array Feature values */
55
	protected $features = [];
56
57
	/** @const string profile type for completionSearch */
58
	const COMPLETION_PROFILE_TYPE = 'completionSearchProfile';
59
60
	/** @const string profile type for query independent ranking features */
61
	const FT_QUERY_INDEP_PROFILE_TYPE = 'fulltextQueryIndepProfile';
62
63
	/**
64
	 * Perform a full text search query and return a result set.
65
	 * If full text searches are not supported or disabled, return null.
66
	 * STUB
67
	 *
68
	 * @param string $term Raw search term
69
	 * @return SearchResultSet|Status|null
70
	 */
71
	function searchText( $term ) {
72
		return null;
73
	}
74
75
	/**
76
	 * Perform a title-only search query and return a result set.
77
	 * If title searches are not supported or disabled, return null.
78
	 * STUB
79
	 *
80
	 * @param string $term Raw search term
81
	 * @return SearchResultSet|null
82
	 */
83
	function searchTitle( $term ) {
84
		return null;
85
	}
86
87
	/**
88
	 * @since 1.18
89
	 * @param string $feature
90
	 * @return bool
91
	 */
92
	public function supports( $feature ) {
93
		switch ( $feature ) {
94
		case 'search-update':
95
			return true;
96
		case 'title-suffix-filter':
97
		default:
98
			return false;
99
		}
100
	}
101
102
	/**
103
	 * Way to pass custom data for engines
104
	 * @since 1.18
105
	 * @param string $feature
106
	 * @param mixed $data
107
	 * @return bool
108
	 */
109
	public function setFeatureData( $feature, $data ) {
110
		$this->features[$feature] = $data;
111
	}
112
113
	/**
114
	 * When overridden in derived class, performs database-specific conversions
115
	 * on text to be used for searching or updating search index.
116
	 * Default implementation does nothing (simply returns $string).
117
	 *
118
	 * @param string $string String to process
119
	 * @return string
120
	 */
121
	public function normalizeText( $string ) {
122
		global $wgContLang;
123
124
		// Some languages such as Chinese require word segmentation
125
		return $wgContLang->segmentByWord( $string );
126
	}
127
128
	/**
129
	 * Transform search term in cases when parts of the query came as different
130
	 * GET params (when supported), e.g. for prefix queries:
131
	 * search=test&prefix=Main_Page/Archive -> test prefix:Main Page/Archive
132
	 * @param string $term
133
	 * @return string
134
	 */
135
	public function transformSearchTerm( $term ) {
136
		return $term;
137
	}
138
139
	/**
140
	 * Get service class to finding near matches.
141
	 * @param Config $config Configuration to use for the matcher.
142
	 * @return SearchNearMatcher
143
	 */
144
	public function getNearMatcher( Config $config ) {
145
		global $wgContLang;
146
		return new SearchNearMatcher( $config, $wgContLang );
147
	}
148
149
	/**
150
	 * Get near matcher for default SearchEngine.
151
	 * @return SearchNearMatcher
152
	 */
153
	protected static function defaultNearMatcher() {
154
		$config = MediaWikiServices::getInstance()->getMainConfig();
155
		return MediaWikiServices::getInstance()->newSearchEngine()->getNearMatcher( $config );
156
	}
157
158
	/**
159
	 * If an exact title match can be found, or a very slightly close match,
160
	 * return the title. If no match, returns NULL.
161
	 * @deprecated since 1.27; Use SearchEngine::getNearMatcher()
162
	 * @param string $searchterm
163
	 * @return Title
164
	 */
165
	public static function getNearMatch( $searchterm ) {
166
		return static::defaultNearMatcher()->getNearMatch( $searchterm );
167
	}
168
169
	/**
170
	 * Do a near match (see SearchEngine::getNearMatch) and wrap it into a
171
	 * SearchResultSet.
172
	 * @deprecated since 1.27; Use SearchEngine::getNearMatcher()
173
	 * @param string $searchterm
174
	 * @return SearchResultSet
175
	 */
176
	public static function getNearMatchResultSet( $searchterm ) {
177
		return static::defaultNearMatcher()->getNearMatchResultSet( $searchterm );
178
	}
179
180
	/**
181
	 * Get chars legal for search.
182
	 * NOTE: usage as static is deprecated and preserved only as BC measure
183
	 * @return string
184
	 */
185
	public static function legalSearchChars() {
186
		return "A-Za-z_'.0-9\\x80-\\xFF\\-";
187
	}
188
189
	/**
190
	 * Set the maximum number of results to return
191
	 * and how many to skip before returning the first.
192
	 *
193
	 * @param int $limit
194
	 * @param int $offset
195
	 */
196
	function setLimitOffset( $limit, $offset = 0 ) {
197
		$this->limit = intval( $limit );
198
		$this->offset = intval( $offset );
199
	}
200
201
	/**
202
	 * Set which namespaces the search should include.
203
	 * Give an array of namespace index numbers.
204
	 *
205
	 * @param int[]|null $namespaces
206
	 */
207
	function setNamespaces( $namespaces ) {
208
		if ( $namespaces ) {
209
			// Filter namespaces to only keep valid ones
210
			$validNs = $this->searchableNamespaces();
211
			$namespaces = array_filter( $namespaces, function( $ns ) use( $validNs ) {
212
				return $ns < 0 || isset( $validNs[$ns] );
213
			} );
214
		} else {
215
			$namespaces = [];
216
		}
217
		$this->namespaces = $namespaces;
218
	}
219
220
	/**
221
	 * Set whether the searcher should try to build a suggestion.  Note: some searchers
222
	 * don't support building a suggestion in the first place and others don't respect
223
	 * this flag.
224
	 *
225
	 * @param bool $showSuggestion Should the searcher try to build suggestions
226
	 */
227
	function setShowSuggestion( $showSuggestion ) {
228
		$this->showSuggestion = $showSuggestion;
229
	}
230
231
	/**
232
	 * Get the valid sort directions.  All search engines support 'relevance' but others
233
	 * might support more. The default in all implementations should be 'relevance.'
234
	 *
235
	 * @since 1.25
236
	 * @return array(string) the valid sort directions for setSort
0 ignored issues
show
The doc-type array(string) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
237
	 */
238
	public function getValidSorts() {
239
		return [ 'relevance' ];
240
	}
241
242
	/**
243
	 * Set the sort direction of the search results. Must be one returned by
244
	 * SearchEngine::getValidSorts()
245
	 *
246
	 * @since 1.25
247
	 * @throws InvalidArgumentException
248
	 * @param string $sort sort direction for query result
249
	 */
250
	public function setSort( $sort ) {
251
		if ( !in_array( $sort, $this->getValidSorts() ) ) {
252
			throw new InvalidArgumentException( "Invalid sort: $sort. " .
253
				"Must be one of: " . implode( ', ', $this->getValidSorts() ) );
254
		}
255
		$this->sort = $sort;
256
	}
257
258
	/**
259
	 * Get the sort direction of the search results
260
	 *
261
	 * @since 1.25
262
	 * @return string
263
	 */
264
	public function getSort() {
265
		return $this->sort;
266
	}
267
268
	/**
269
	 * Parse some common prefixes: all (search everything)
270
	 * or namespace names and set the list of namespaces
271
	 * of this class accordingly.
272
	 *
273
	 * @param string $query
274
	 * @return string
275
	 */
276
	function replacePrefixes( $query ) {
277
		$queryAndNs = self::parseNamespacePrefixes( $query );
278
		if ( $queryAndNs === false ) {
279
			return $query;
280
		}
281
		$this->namespaces = $queryAndNs[1];
282
		return $queryAndNs[0];
283
	}
284
285
	/**
286
	 * Parse some common prefixes: all (search everything)
287
	 * or namespace names
288
	 *
289
	 * @param string $query
290
	 * @return false|array false if no namespace was extracted, an array
291
	 * with the parsed query at index 0 and an array of namespaces at index
292
	 * 1 (or null for all namespaces).
293
	 */
294
	public static function parseNamespacePrefixes( $query ) {
295
		global $wgContLang;
296
297
		$parsed = $query;
298
		if ( strpos( $query, ':' ) === false ) { // nothing to do
299
			return false;
300
		}
301
		$extractedNamespace = null;
302
303
		$allkeyword = wfMessage( 'searchall' )->inContentLanguage()->text() . ":";
304
		if ( strncmp( $query, $allkeyword, strlen( $allkeyword ) ) == 0 ) {
305
			$extractedNamespace = null;
306
			$parsed = substr( $query, strlen( $allkeyword ) );
307
		} elseif ( strpos( $query, ':' ) !== false ) {
308
			// TODO: should we unify with PrefixSearch::extractNamespace ?
309
			$prefix = str_replace( ' ', '_', substr( $query, 0, strpos( $query, ':' ) ) );
310
			$index = $wgContLang->getNsIndex( $prefix );
311
			if ( $index !== false ) {
312
				$extractedNamespace = [ $index ];
313
				$parsed = substr( $query, strlen( $prefix ) + 1 );
314
			} else {
315
				return false;
316
			}
317
		}
318
319
		if ( trim( $parsed ) == '' ) {
320
			$parsed = $query; // prefix was the whole query
321
		}
322
323
		return [ $parsed, $extractedNamespace ];
324
	}
325
326
	/**
327
	 * Find snippet highlight settings for all users
328
	 * @return array Contextlines, contextchars
329
	 */
330
	public static function userHighlightPrefs() {
331
		$contextlines = 2; // Hardcode this. Old defaults sucked. :)
332
		$contextchars = 75; // same as above.... :P
333
		return [ $contextlines, $contextchars ];
334
	}
335
336
	/**
337
	 * Create or update the search index record for the given page.
338
	 * Title and text should be pre-processed.
339
	 * STUB
340
	 *
341
	 * @param int $id
342
	 * @param string $title
343
	 * @param string $text
344
	 */
345
	function update( $id, $title, $text ) {
346
		// no-op
347
	}
348
349
	/**
350
	 * Update a search index record's title only.
351
	 * Title should be pre-processed.
352
	 * STUB
353
	 *
354
	 * @param int $id
355
	 * @param string $title
356
	 */
357
	function updateTitle( $id, $title ) {
358
		// no-op
359
	}
360
361
	/**
362
	 * Delete an indexed page
363
	 * Title should be pre-processed.
364
	 * STUB
365
	 *
366
	 * @param int $id Page id that was deleted
367
	 * @param string $title Title of page that was deleted
368
	 */
369
	function delete( $id, $title ) {
370
		// no-op
371
	}
372
373
	/**
374
	 * Get OpenSearch suggestion template
375
	 *
376
	 * @deprecated since 1.25
377
	 * @return string
378
	 */
379
	public static function getOpenSearchTemplate() {
380
		wfDeprecated( __METHOD__, '1.25' );
381
		return ApiOpenSearch::getOpenSearchTemplate( 'application/x-suggestions+json' );
382
	}
383
384
	/**
385
	 * Get the raw text for updating the index from a content object
386
	 * Nicer search backends could possibly do something cooler than
387
	 * just returning raw text
388
	 *
389
	 * @todo This isn't ideal, we'd really like to have content-specific handling here
390
	 * @param Title $t Title we're indexing
391
	 * @param Content $c Content of the page to index
392
	 * @return string
393
	 */
394
	public function getTextFromContent( Title $t, Content $c = null ) {
395
		return $c ? $c->getTextForSearchIndex() : '';
396
	}
397
398
	/**
399
	 * If an implementation of SearchEngine handles all of its own text processing
400
	 * in getTextFromContent() and doesn't require SearchUpdate::updateText()'s
401
	 * rather silly handling, it should return true here instead.
402
	 *
403
	 * @return bool
404
	 */
405
	public function textAlreadyUpdatedForIndex() {
406
		return false;
407
	}
408
409
	/**
410
	 * Makes search simple string if it was namespaced.
411
	 * Sets namespaces of the search to namespaces extracted from string.
412
	 * @param string $search
413
	 * @return string Simplified search string
414
	 */
415
	protected function normalizeNamespaces( $search ) {
416
		// Find a Title which is not an interwiki and is in NS_MAIN
417
		$title = Title::newFromText( $search );
418
		$ns = $this->namespaces;
419
		if ( $title && !$title->isExternal() ) {
420
			$ns = [ $title->getNamespace() ];
421
			$search = $title->getText();
422
			if ( $ns[0] == NS_MAIN ) {
423
				$ns = $this->namespaces; // no explicit prefix, use default namespaces
424
				Hooks::run( 'PrefixSearchExtractNamespace', [ &$ns, &$search ] );
425
			}
426
		} else {
427
			$title = Title::newFromText( $search . 'Dummy' );
428
			if ( $title && $title->getText() == 'Dummy'
429
					&& $title->getNamespace() != NS_MAIN
430
					&& !$title->isExternal() )
431
			{
432
				$ns = [ $title->getNamespace() ];
433
				$search = '';
434
			} else {
435
				Hooks::run( 'PrefixSearchExtractNamespace', [ &$ns, &$search ] );
436
			}
437
		}
438
439
		$ns = array_map( function( $space ) {
440
			return $space == NS_MEDIA ? NS_FILE : $space;
441
		}, $ns );
442
443
		$this->setNamespaces( $ns );
444
		return $search;
445
	}
446
447
	/**
448
	 * Perform a completion search.
449
	 * Does not resolve namespaces and does not check variants.
450
	 * Search engine implementations may want to override this function.
451
	 * @param string $search
452
	 * @return SearchSuggestionSet
453
	 */
454
	protected function completionSearchBackend( $search ) {
455
		$results = [];
456
457
		$search = trim( $search );
458
459
		if ( !in_array( NS_SPECIAL, $this->namespaces ) && // We do not run hook on Special: search
460
			 !Hooks::run( 'PrefixSearchBackend',
461
				[ $this->namespaces, $search, $this->limit, &$results, $this->offset ]
462
		) ) {
463
			// False means hook worked.
464
			// FIXME: Yes, the API is weird. That's why it is going to be deprecated.
465
466
			return SearchSuggestionSet::fromStrings( $results );
467
		} else {
468
			// Hook did not do the job, use default simple search
469
			$results = $this->simplePrefixSearch( $search );
470
			return SearchSuggestionSet::fromTitles( $results );
471
		}
472
	}
473
474
	/**
475
	 * Perform a completion search.
476
	 * @param string $search
477
	 * @return SearchSuggestionSet
478
	 */
479
	public function completionSearch( $search ) {
480
		if ( trim( $search ) === '' ) {
481
			return SearchSuggestionSet::emptySuggestionSet(); // Return empty result
482
		}
483
		$search = $this->normalizeNamespaces( $search );
484
		return $this->processCompletionResults( $search, $this->completionSearchBackend( $search ) );
485
	}
486
487
	/**
488
	 * Perform a completion search with variants.
489
	 * @param string $search
490
	 * @return SearchSuggestionSet
491
	 */
492
	public function completionSearchWithVariants( $search ) {
493
		if ( trim( $search ) === '' ) {
494
			return SearchSuggestionSet::emptySuggestionSet(); // Return empty result
495
		}
496
		$search = $this->normalizeNamespaces( $search );
497
498
		$results = $this->completionSearchBackend( $search );
499
		$fallbackLimit = $this->limit - $results->getSize();
500
		if ( $fallbackLimit > 0 ) {
501
			global $wgContLang;
502
503
			$fallbackSearches = $wgContLang->autoConvertToAllVariants( $search );
504
			$fallbackSearches = array_diff( array_unique( $fallbackSearches ), [ $search ] );
505
506
			foreach ( $fallbackSearches as $fbs ) {
507
				$this->setLimitOffset( $fallbackLimit );
508
				$fallbackSearchResult = $this->completionSearch( $fbs );
509
				$results->appendAll( $fallbackSearchResult );
510
				$fallbackLimit -= count( $fallbackSearchResult );
511
				if ( $fallbackLimit <= 0 ) {
512
					break;
513
				}
514
			}
515
		}
516
		return $this->processCompletionResults( $search, $results );
517
	}
518
519
	/**
520
	 * Extract titles from completion results
521
	 * @param SearchSuggestionSet $completionResults
522
	 * @return Title[]
523
	 */
524
	public function extractTitles( SearchSuggestionSet $completionResults ) {
525
		return $completionResults->map( function( SearchSuggestion $sugg ) {
526
			return $sugg->getSuggestedTitle();
527
		} );
528
	}
529
530
	/**
531
	 * Process completion search results.
532
	 * Resolves the titles and rescores.
533
	 * @param SearchSuggestionSet $suggestions
534
	 * @return SearchSuggestionSet
535
	 */
536
	protected function processCompletionResults( $search, SearchSuggestionSet $suggestions ) {
537
		$search = trim( $search );
538
		// preload the titles with LinkBatch
539
		$titles = $suggestions->map( function( SearchSuggestion $sugg ) {
540
			return $sugg->getSuggestedTitle();
541
		} );
542
		$lb = new LinkBatch( $titles );
543
		$lb->setCaller( __METHOD__ );
544
		$lb->execute();
545
546
		$results = $suggestions->map( function( SearchSuggestion $sugg ) {
547
			return $sugg->getSuggestedTitle()->getPrefixedText();
548
		} );
549
550
		if ( $this->offset === 0 ) {
551
			// Rescore results with an exact title match
552
			// NOTE: in some cases like cross-namespace redirects
553
			// (frequently used as shortcuts e.g. WP:WP on huwiki) some
554
			// backends like Cirrus will return no results. We should still
555
			// try an exact title match to workaround this limitation
556
			$rescorer = new SearchExactMatchRescorer();
557
			$rescoredResults = $rescorer->rescore( $search, $this->namespaces, $results, $this->limit );
0 ignored issues
show
It seems like $this->namespaces can also be of type null; however, SearchExactMatchRescorer::rescore() does only seem to accept array<integer,integer>, 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.

Loading history...
558
		} else {
559
			// No need to rescore if offset is not 0
560
			// The exact match must have been returned at position 0
561
			// if it existed.
562
			$rescoredResults = $results;
563
		}
564
565
		if ( count( $rescoredResults ) > 0 ) {
566
			$found = array_search( $rescoredResults[0], $results );
567
			if ( $found === false ) {
568
				// If the first result is not in the previous array it
569
				// means that we found a new exact match
570
				$exactMatch = SearchSuggestion::fromTitle( 0, Title::newFromText( $rescoredResults[0] ) );
0 ignored issues
show
It seems like \Title::newFromText($rescoredResults[0]) can be null; however, fromTitle() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
571
				$suggestions->prepend( $exactMatch );
572
				$suggestions->shrink( $this->limit );
573
			} else {
574
				// if the first result is not the same we need to rescore
575
				if ( $found > 0 ) {
576
					$suggestions->rescore( $found );
577
				}
578
			}
579
		}
580
581
		return $suggestions;
582
	}
583
584
	/**
585
	 * Simple prefix search for subpages.
586
	 * @param string $search
587
	 * @return Title[]
588
	 */
589
	public function defaultPrefixSearch( $search ) {
590
		if ( trim( $search ) === '' ) {
591
			return [];
592
		}
593
594
		$search = $this->normalizeNamespaces( $search );
595
		return $this->simplePrefixSearch( $search );
596
	}
597
598
	/**
599
	 * Call out to simple search backend.
600
	 * Defaults to TitlePrefixSearch.
601
	 * @param string $search
602
	 * @return Title[]
603
	 */
604
	protected function simplePrefixSearch( $search ) {
605
		// Use default database prefix search
606
		$backend = new TitlePrefixSearch;
0 ignored issues
show
Deprecated Code introduced by
The class TitlePrefixSearch has been deprecated with message: Since 1.27, Use SearchEngine::prefixSearchSubpages or SearchEngine::completionSearch

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
607
		return $backend->defaultSearchBackend( $this->namespaces, $search, $this->limit, $this->offset );
608
	}
609
610
	/**
611
	 * Make a list of searchable namespaces and their canonical names.
612
	 * @deprecated since 1.27; use SearchEngineConfig::searchableNamespaces()
613
	 * @return array
614
	 */
615
	public static function searchableNamespaces() {
616
		return MediaWikiServices::getInstance()->getSearchEngineConfig()->searchableNamespaces();
617
	}
618
619
	/**
620
	 * Extract default namespaces to search from the given user's
621
	 * settings, returning a list of index numbers.
622
	 * @deprecated since 1.27; use SearchEngineConfig::userNamespaces()
623
	 * @param user $user
624
	 * @return array
625
	 */
626
	public static function userNamespaces( $user ) {
627
		return MediaWikiServices::getInstance()->getSearchEngineConfig()->userNamespaces( $user );
628
	}
629
630
	/**
631
	 * An array of namespaces indexes to be searched by default
632
	 * @deprecated since 1.27; use SearchEngineConfig::defaultNamespaces()
633
	 * @return array
634
	 */
635
	public static function defaultNamespaces() {
636
		return MediaWikiServices::getInstance()->getSearchEngineConfig()->defaultNamespaces();
637
	}
638
639
	/**
640
	 * Get a list of namespace names useful for showing in tooltips
641
	 * and preferences
642
	 * @deprecated since 1.27; use SearchEngineConfig::namespacesAsText()
643
	 * @param array $namespaces
644
	 * @return array
645
	 */
646
	public static function namespacesAsText( $namespaces ) {
647
		return MediaWikiServices::getInstance()->getSearchEngineConfig()->namespacesAsText( $namespaces );
648
	}
649
650
	/**
651
	 * Load up the appropriate search engine class for the currently
652
	 * active database backend, and return a configured instance.
653
	 * @deprecated since 1.27; Use SearchEngineFactory::create
654
	 * @param string $type Type of search backend, if not the default
655
	 * @return SearchEngine
656
	 */
657
	public static function create( $type = null ) {
658
		return MediaWikiServices::getInstance()->getSearchEngineFactory()->create( $type );
659
	}
660
661
	/**
662
	 * Return the search engines we support. If only $wgSearchType
663
	 * is set, it'll be an array of just that one item.
664
	 * @deprecated since 1.27; use SearchEngineConfig::getSearchTypes()
665
	 * @return array
666
	 */
667
	public static function getSearchTypes() {
668
		return MediaWikiServices::getInstance()->getSearchEngineConfig()->getSearchTypes();
669
	}
670
671
	/**
672
	 * Get a list of supported profiles.
673
	 * Some search engine implementations may expose specific profiles to fine-tune
674
	 * its behaviors.
675
	 * The profile can be passed as a feature data with setFeatureData( $profileType, $profileName )
676
	 * The array returned by this function contains the following keys:
677
	 * - name: the profile name to use with setFeatureData
678
	 * - desc-message: the i18n description
679
	 * - default: set to true if this profile is the default
680
	 *
681
	 * @since 1.28
682
	 * @param string $profileType the type of profiles
683
	 * @param User|null $user the user requesting the list of profiles
684
	 * @return array|null the list of profiles or null if none available
685
	 */
686
	public function getProfiles( $profileType, User $user = null ) {
687
		return null;
688
	}
689
690
	/**
691
	 * Create a search field definition.
692
	 * Specific search engines should override this method to create search fields.
693
	 * @param string $name
694
	 * @param int    $type One of the types in SearchIndexField::INDEX_TYPE_*
695
	 * @return SearchIndexField
696
	 * @since 1.28
697
	 */
698
	public function makeSearchFieldMapping( $name, $type ) {
699
		return new NullIndexField();
700
	}
701
702
	/**
703
	 * Get fields for search index
704
	 * @since 1.28
705
	 * @return SearchIndexField[] Index field definitions for all content handlers
706
	 */
707
	public function getSearchIndexFields() {
708
		$models = ContentHandler::getContentModels();
709
		$fields = [];
710
		foreach ( $models as $model ) {
711
			$handler = ContentHandler::getForModelID( $model );
712
			$handlerFields = $handler->getFieldsForSearchIndex( $this );
713
			foreach ( $handlerFields as $fieldName => $fieldData ) {
714
				if ( empty( $fields[$fieldName] ) ) {
715
					$fields[$fieldName] = $fieldData;
716
				} else {
717
					// TODO: do we allow some clashes with the same type or reject all of them?
718
					$mergeDef = $fields[$fieldName]->merge( $fieldData );
719
					if ( !$mergeDef ) {
720
						throw new InvalidArgumentException( "Duplicate field $fieldName for model $model" );
721
					}
722
					$fields[$fieldName] = $mergeDef;
723
				}
724
			}
725
		}
726
		// Hook to allow extensions to produce search mapping fields
727
		Hooks::run( 'SearchIndexFields', [ &$fields, $this ] );
728
		return $fields;
729
	}
730
731
	/**
732
	 * Augment search results with extra data.
733
	 *
734
	 * @param SearchResultSet $resultSet
735
	 */
736
	public function augmentSearchResults( SearchResultSet $resultSet ) {
737
		$setAugmentors = [];
738
		$rowAugmentors = [];
739
		Hooks::run( "SearchResultsAugment", [ &$setAugmentors, &$rowAugmentors ] );
740
741
		if ( !$setAugmentors && !$rowAugmentors ) {
742
			// We're done here
743
			return;
744
		}
745
746
		// Convert row augmentors to set augmentor
747
		foreach ( $rowAugmentors as $name => $row ) {
748
			if ( isset( $setAugmentors[$name] ) ) {
749
				throw new InvalidArgumentException( "Both row and set augmentors are defined for $name" );
750
			}
751
			$setAugmentors[$name] = new PerRowAugmentor( $row );
752
		}
753
754
		foreach ( $setAugmentors as $name => $augmentor ) {
755
			$data = $augmentor->augmentAll( $resultSet );
756
			if ( $data ) {
757
				$resultSet->setAugmentedData( $name, $data );
758
			}
759
		}
760
	}
761
}
762
763
/**
764
 * Dummy class to be used when non-supported Database engine is present.
765
 * @todo FIXME: Dummy class should probably try something at least mildly useful,
766
 * such as a LIKE search through titles.
767
 * @ingroup Search
768
 */
769
class SearchEngineDummy extends SearchEngine {
770
	// no-op
771
}
772