* (bug 1184) expiry time of indefinite blocks shown as the current time
[lhc/web/wiklou.git] / includes / SearchEngine.php
1 <?php
2 /**
3 * Contain a class for special pages
4 * @package MediaWiki
5 */
6
7 /** */
8 class SearchEngine {
9 var $limit = 10;
10 var $offset = 0;
11 var $searchTerms = array();
12 var $namespaces = array( 0 );
13 var $showRedirects = false;
14
15 /**
16 * Perform a full text search query and return a result set.
17 *
18 * @param string $term - Raw search term
19 * @param array $namespaces - List of namespaces to search
20 * @return ResultWrapper
21 * @access public
22 */
23 function searchText( $term ) {
24 return $this->db->resultObject( $this->db->query( $this->getQuery( $this->filter( $term ), true ) ) );
25 }
26
27 /**
28 * Perform a title-only search query and return a result set.
29 *
30 * @param string $term - Raw search term
31 * @param array $namespaces - List of namespaces to search
32 * @return ResultWrapper
33 * @access public
34 */
35 function searchTitle( $term ) {
36 return $this->db->resultObject( $this->db->query( $this->getQuery( $this->filter( $term ), false ) ) );
37 }
38
39 /**
40 * If an exact title match can be find, or a very slightly close match,
41 * return the title. If no match, returns NULL.
42 *
43 * @param string $term
44 * @return Title
45 * @access private
46 */
47 function getNearMatch( $term ) {
48 # Exact match? No need to look further.
49 $title = Title::newFromText( $term );
50 if ( $title->getNamespace() == NS_SPECIAL || 0 != $title->getArticleID() ) {
51 return $title;
52 }
53
54 # Now try all lower case (i.e. first letter capitalized)
55 #
56 $title = Title::newFromText( strtolower( $term ) );
57 if ( 0 != $title->getArticleID() ) {
58 return $title;
59 }
60
61 # Now try capitalized string
62 #
63 $title = Title::newFromText( ucwords( strtolower( $term ) ) );
64 if ( 0 != $title->getArticleID() ) {
65 return $title;
66 }
67
68 # Now try all upper case
69 #
70 $title = Title::newFromText( strtoupper( $term ) );
71 if ( 0 != $title->getArticleID() ) {
72 return $title;
73 }
74
75 # Entering an IP address goes to the contributions page
76 if ( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $term ) ) {
77 $title = Title::makeTitle( NS_SPECIAL, "Contributions/" . $term );
78 return $title;
79 }
80
81 return NULL;
82 }
83
84 function legalSearchChars() {
85 return "A-Za-z_'0-9\\x80-\\xFF\\-";
86 }
87
88 /**
89 * Set the maximum number of results to return
90 * and how many to skip before returning the first.
91 *
92 * @param int $limit
93 * @param int $offset
94 * @access public
95 */
96 function setLimitOffset( $limit, $offset = 0 ) {
97 $this->limit = IntVal( $limit );
98 $this->offset = IntVal( $offset );
99 }
100
101 /**
102 * Set which namespaces the search should include.
103 * Give an array of namespace index numbers.
104 *
105 * @param array $namespaces
106 * @access public
107 */
108 function setNamespaces( $namespaces ) {
109 $this->namespaces = $namespaces;
110 }
111
112 /**
113 * Make a list of searchable namespaces and their canonical names.
114 * @return array
115 * @access public
116 */
117 function searchableNamespaces() {
118 global $wgContLang;
119 $arr = array();
120 foreach( $wgContLang->getNamespaces() as $ns => $name ) {
121 if( $ns >= 0 ) {
122 $arr[$ns] = $name;
123 }
124 }
125 return $arr;
126 }
127
128 /**
129 * Fetch an array of regular expression fragments for matching
130 * the search terms as parsed by this engine in a text extract.
131 *
132 * @return array
133 * @access public
134 */
135 function termMatches() {
136 return $this->searchTerms;
137 }
138
139 /**
140 * Return a 'cleaned up' search string
141 *
142 * @return string
143 * @access public
144 */
145 function filter( $text ) {
146 $lc = $this->legalSearchChars();
147 return trim( preg_replace( "/[^{$lc}]/", " ", $text ) );
148 }
149
150 /**
151 * Return a partial WHERE clause to exclude redirects, if so set
152 * @return string
153 * @access private
154 */
155 function queryRedirect() {
156 if( $this->showRedirects ) {
157 return 'AND cur_is_redirect=0';
158 } else {
159 return '';
160 }
161 }
162
163 /**
164 * Return a partial WHERE clause to limit the search to the given namespaces
165 * @return string
166 * @access private
167 */
168 function queryNamespaces() {
169 $namespaces = implode( ',', $this->namespaces );
170 if ($namespaces == '') {
171 $namespaces = '0';
172 }
173 return 'AND page_namespace IN (' . $namespaces . ')';
174 }
175
176 /**
177 * Return a LIMIT clause to limit results on the query.
178 * @return string
179 * @access private
180 */
181 function queryLimit() {
182 return $this->db->limitResult( $this->limit, $this->offset );
183 }
184
185 /**
186 * Does not do anything for generic search engine
187 * subclasses may define this though
188 * @return string
189 * @access private
190 */
191 function queryRanking($filteredTerm,$fulltext) {
192 return "";
193 }
194
195 /**
196 * Construct the full SQL query to do the search.
197 * The guts shoulds be constructed in queryMain()
198 * @param string $filteredTerm
199 * @param bool $fulltext
200 * @access private
201 */
202 function getQuery( $filteredTerm, $fulltext ) {
203 return $this->queryMain( $filteredTerm, $fulltext ) . ' ' .
204 $this->queryRedirect() . ' ' .
205 $this->queryNamespaces() . ' ' .
206 $this->queryRanking($filteredTerm, $fulltext) . ' ' .
207 $this->queryLimit();
208 }
209
210 /**
211 * Load up the appropriate search engine class for the currently
212 * active database backend, and return a configured instance.
213 *
214 * @return SearchEngine
215 * @access private
216 */
217 function create() {
218 global $wgDBtype, $wgDBmysql4, $wgSearchType;
219 if( $wgDBtype == 'mysql' ) {
220 if( $wgDBmysql4 ) {
221 $class = 'SearchMySQL4';
222 require_once( 'SearchMySQL4.php' );
223 } else {
224 $class = 'SearchMysql3';
225 require_once( 'SearchMySQL3.php' );
226 }
227 } else if ( $wgDBtype == 'PostgreSQL' ) {
228 $class = 'SearchTsearch2';
229 require_once( 'SearchTsearch2.php' );
230 } else {
231 $class = 'SearchEngineDummy';
232 }
233 $search = new $class( wfGetDB( DB_SLAVE ) );
234 $search->setLimitOffset(0,0);
235 return $search;
236 }
237
238
239 }
240
241 /** */
242 class SearchEngineDummy {
243 function search( $term ) {
244 return null;
245 }
246 }
247