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 | * Implements Special:Whatlinkshere |
||
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 | * @todo Use some variant of Pager or something; the pagination here is lousy. |
||
22 | */ |
||
23 | |||
24 | /** |
||
25 | * Implements Special:Whatlinkshere |
||
26 | * |
||
27 | * @ingroup SpecialPage |
||
28 | */ |
||
29 | class SpecialWhatLinksHere extends IncludableSpecialPage { |
||
30 | /** @var FormOptions */ |
||
31 | protected $opts; |
||
32 | |||
33 | protected $selfTitle; |
||
34 | |||
35 | /** @var Title */ |
||
36 | protected $target; |
||
37 | |||
38 | protected $limits = [ 20, 50, 100, 250, 500 ]; |
||
39 | |||
40 | public function __construct() { |
||
41 | parent::__construct( 'Whatlinkshere' ); |
||
42 | } |
||
43 | |||
44 | function execute( $par ) { |
||
45 | $out = $this->getOutput(); |
||
46 | |||
47 | $this->setHeaders(); |
||
48 | $this->outputHeader(); |
||
49 | $this->addHelpLink( 'Help:What links here' ); |
||
50 | |||
51 | $opts = new FormOptions(); |
||
52 | |||
53 | $opts->add( 'target', '' ); |
||
54 | $opts->add( 'namespace', '', FormOptions::INTNULL ); |
||
55 | $opts->add( 'limit', $this->getConfig()->get( 'QueryPageDefaultLimit' ) ); |
||
56 | $opts->add( 'from', 0 ); |
||
57 | $opts->add( 'back', 0 ); |
||
58 | $opts->add( 'hideredirs', false ); |
||
59 | $opts->add( 'hidetrans', false ); |
||
60 | $opts->add( 'hidelinks', false ); |
||
61 | $opts->add( 'hideimages', false ); |
||
62 | $opts->add( 'invert', false ); |
||
63 | |||
64 | $opts->fetchValuesFromRequest( $this->getRequest() ); |
||
65 | $opts->validateIntBounds( 'limit', 0, 5000 ); |
||
66 | |||
67 | // Give precedence to subpage syntax |
||
68 | if ( $par !== null ) { |
||
69 | $opts->setValue( 'target', $par ); |
||
70 | } |
||
71 | |||
72 | // Bind to member variable |
||
73 | $this->opts = $opts; |
||
74 | |||
75 | $this->target = Title::newFromText( $opts->getValue( 'target' ) ); |
||
76 | if ( !$this->target ) { |
||
77 | if ( !$this->including() ) { |
||
78 | $out->addHTML( $this->whatlinkshereForm() ); |
||
79 | } |
||
80 | |||
81 | return; |
||
82 | } |
||
83 | |||
84 | $this->getSkin()->setRelevantTitle( $this->target ); |
||
85 | |||
86 | $this->selfTitle = $this->getPageTitle( $this->target->getPrefixedDBkey() ); |
||
87 | |||
88 | $out->setPageTitle( $this->msg( 'whatlinkshere-title', $this->target->getPrefixedText() ) ); |
||
89 | $out->addBacklinkSubtitle( $this->target ); |
||
90 | $this->showIndirectLinks( |
||
91 | 0, |
||
92 | $this->target, |
||
93 | $opts->getValue( 'limit' ), |
||
94 | $opts->getValue( 'from' ), |
||
95 | $opts->getValue( 'back' ) |
||
96 | ); |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * @param int $level Recursion level |
||
101 | * @param Title $target Target title |
||
102 | * @param int $limit Number of entries to display |
||
103 | * @param int $from Display from this article ID (default: 0) |
||
104 | * @param int $back Display from this article ID at backwards scrolling (default: 0) |
||
105 | */ |
||
106 | function showIndirectLinks( $level, $target, $limit, $from = 0, $back = 0 ) { |
||
107 | $out = $this->getOutput(); |
||
108 | $dbr = wfGetDB( DB_REPLICA ); |
||
109 | |||
110 | $hidelinks = $this->opts->getValue( 'hidelinks' ); |
||
111 | $hideredirs = $this->opts->getValue( 'hideredirs' ); |
||
112 | $hidetrans = $this->opts->getValue( 'hidetrans' ); |
||
113 | $hideimages = $target->getNamespace() != NS_FILE || $this->opts->getValue( 'hideimages' ); |
||
114 | |||
115 | $fetchlinks = ( !$hidelinks || !$hideredirs ); |
||
116 | |||
117 | // Build query conds in concert for all three tables... |
||
118 | $conds['pagelinks'] = [ |
||
0 ignored issues
–
show
|
|||
119 | 'pl_namespace' => $target->getNamespace(), |
||
120 | 'pl_title' => $target->getDBkey(), |
||
121 | ]; |
||
122 | $conds['templatelinks'] = [ |
||
123 | 'tl_namespace' => $target->getNamespace(), |
||
124 | 'tl_title' => $target->getDBkey(), |
||
125 | ]; |
||
126 | $conds['imagelinks'] = [ |
||
127 | 'il_to' => $target->getDBkey(), |
||
128 | ]; |
||
129 | |||
130 | $namespace = $this->opts->getValue( 'namespace' ); |
||
131 | $invert = $this->opts->getValue( 'invert' ); |
||
132 | $nsComparison = ( $invert ? '!= ' : '= ' ) . $dbr->addQuotes( $namespace ); |
||
133 | View Code Duplication | if ( is_int( $namespace ) ) { |
|
134 | $conds['pagelinks'][] = "pl_from_namespace $nsComparison"; |
||
135 | $conds['templatelinks'][] = "tl_from_namespace $nsComparison"; |
||
136 | $conds['imagelinks'][] = "il_from_namespace $nsComparison"; |
||
137 | } |
||
138 | |||
139 | View Code Duplication | if ( $from ) { |
|
140 | $conds['templatelinks'][] = "tl_from >= $from"; |
||
141 | $conds['pagelinks'][] = "pl_from >= $from"; |
||
142 | $conds['imagelinks'][] = "il_from >= $from"; |
||
143 | } |
||
144 | |||
145 | if ( $hideredirs ) { |
||
146 | $conds['pagelinks']['rd_from'] = null; |
||
147 | } elseif ( $hidelinks ) { |
||
148 | $conds['pagelinks'][] = 'rd_from is NOT NULL'; |
||
149 | } |
||
150 | |||
151 | $queryFunc = function ( IDatabase $dbr, $table, $fromCol ) use ( |
||
152 | $conds, $target, $limit |
||
153 | ) { |
||
154 | // Read an extra row as an at-end check |
||
155 | $queryLimit = $limit + 1; |
||
156 | $on = [ |
||
157 | "rd_from = $fromCol", |
||
158 | 'rd_title' => $target->getDBkey(), |
||
159 | 'rd_interwiki = ' . $dbr->addQuotes( '' ) . ' OR rd_interwiki IS NULL' |
||
160 | ]; |
||
161 | $on['rd_namespace'] = $target->getNamespace(); |
||
162 | // Inner LIMIT is 2X in case of stale backlinks with wrong namespaces |
||
163 | $subQuery = $dbr->selectSQLText( |
||
164 | [ $table, 'redirect', 'page' ], |
||
165 | [ $fromCol, 'rd_from' ], |
||
166 | $conds[$table], |
||
167 | __CLASS__ . '::showIndirectLinks', |
||
168 | // Force JOIN order per T106682 to avoid large filesorts |
||
169 | [ 'ORDER BY' => $fromCol, 'LIMIT' => 2 * $queryLimit, 'STRAIGHT_JOIN' ], |
||
170 | [ |
||
171 | 'page' => [ 'INNER JOIN', "$fromCol = page_id" ], |
||
172 | 'redirect' => [ 'LEFT JOIN', $on ] |
||
173 | ] |
||
174 | ); |
||
175 | return $dbr->select( |
||
176 | [ 'page', 'temp_backlink_range' => "($subQuery)" ], |
||
177 | [ 'page_id', 'page_namespace', 'page_title', 'rd_from', 'page_is_redirect' ], |
||
178 | [], |
||
179 | __CLASS__ . '::showIndirectLinks', |
||
180 | [ 'ORDER BY' => 'page_id', 'LIMIT' => $queryLimit ], |
||
181 | [ 'page' => [ 'INNER JOIN', "$fromCol = page_id" ] ] |
||
182 | ); |
||
183 | }; |
||
184 | |||
185 | if ( $fetchlinks ) { |
||
186 | $plRes = $queryFunc( $dbr, 'pagelinks', 'pl_from' ); |
||
187 | } |
||
188 | |||
189 | if ( !$hidetrans ) { |
||
190 | $tlRes = $queryFunc( $dbr, 'templatelinks', 'tl_from' ); |
||
191 | } |
||
192 | |||
193 | if ( !$hideimages ) { |
||
194 | $ilRes = $queryFunc( $dbr, 'imagelinks', 'il_from' ); |
||
195 | } |
||
196 | |||
197 | if ( ( !$fetchlinks || !$plRes->numRows() ) |
||
0 ignored issues
–
show
The variable
$plRes does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
198 | && ( $hidetrans || !$tlRes->numRows() ) |
||
0 ignored issues
–
show
The variable
$tlRes does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
199 | && ( $hideimages || !$ilRes->numRows() ) |
||
0 ignored issues
–
show
The variable
$ilRes does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
200 | ) { |
||
201 | if ( 0 == $level ) { |
||
202 | if ( !$this->including() ) { |
||
203 | $out->addHTML( $this->whatlinkshereForm() ); |
||
204 | |||
205 | // Show filters only if there are links |
||
206 | if ( $hidelinks || $hidetrans || $hideredirs || $hideimages ) { |
||
207 | $out->addHTML( $this->getFilterPanel() ); |
||
208 | } |
||
209 | $errMsg = is_int( $namespace ) ? 'nolinkshere-ns' : 'nolinkshere'; |
||
210 | $out->addWikiMsg( $errMsg, $this->target->getPrefixedText() ); |
||
211 | $out->setStatusCode( 404 ); |
||
212 | } |
||
213 | } |
||
214 | |||
215 | return; |
||
216 | } |
||
217 | |||
218 | // Read the rows into an array and remove duplicates |
||
219 | // templatelinks comes second so that the templatelinks row overwrites the |
||
220 | // pagelinks row, so we get (inclusion) rather than nothing |
||
221 | if ( $fetchlinks ) { |
||
222 | foreach ( $plRes as $row ) { |
||
223 | $row->is_template = 0; |
||
224 | $row->is_image = 0; |
||
225 | $rows[$row->page_id] = $row; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$rows was never initialized. Although not strictly required by PHP, it is generally a good practice to add $rows = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
226 | } |
||
227 | } |
||
228 | if ( !$hidetrans ) { |
||
229 | foreach ( $tlRes as $row ) { |
||
230 | $row->is_template = 1; |
||
231 | $row->is_image = 0; |
||
232 | $rows[$row->page_id] = $row; |
||
0 ignored issues
–
show
The variable
$rows does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
233 | } |
||
234 | } |
||
235 | if ( !$hideimages ) { |
||
236 | foreach ( $ilRes as $row ) { |
||
237 | $row->is_template = 0; |
||
238 | $row->is_image = 1; |
||
239 | $rows[$row->page_id] = $row; |
||
240 | } |
||
241 | } |
||
242 | |||
243 | // Sort by key and then change the keys to 0-based indices |
||
244 | ksort( $rows ); |
||
245 | $rows = array_values( $rows ); |
||
246 | |||
247 | $numRows = count( $rows ); |
||
248 | |||
249 | // Work out the start and end IDs, for prev/next links |
||
250 | if ( $numRows > $limit ) { |
||
251 | // More rows available after these ones |
||
252 | // Get the ID from the last row in the result set |
||
253 | $nextId = $rows[$limit]->page_id; |
||
254 | // Remove undisplayed rows |
||
255 | $rows = array_slice( $rows, 0, $limit ); |
||
256 | } else { |
||
257 | // No more rows after |
||
258 | $nextId = false; |
||
259 | } |
||
260 | $prevId = $from; |
||
261 | |||
262 | // use LinkBatch to make sure, that all required data (associated with Titles) |
||
263 | // is loaded in one query |
||
264 | $lb = new LinkBatch(); |
||
265 | foreach ( $rows as $row ) { |
||
266 | $lb->add( $row->page_namespace, $row->page_title ); |
||
267 | } |
||
268 | $lb->execute(); |
||
269 | |||
270 | if ( $level == 0 ) { |
||
271 | if ( !$this->including() ) { |
||
272 | $out->addHTML( $this->whatlinkshereForm() ); |
||
273 | $out->addHTML( $this->getFilterPanel() ); |
||
274 | $out->addWikiMsg( 'linkshere', $this->target->getPrefixedText() ); |
||
275 | |||
276 | $prevnext = $this->getPrevNext( $prevId, $nextId ); |
||
277 | $out->addHTML( $prevnext ); |
||
278 | } |
||
279 | } |
||
280 | $out->addHTML( $this->listStart( $level ) ); |
||
281 | foreach ( $rows as $row ) { |
||
282 | $nt = Title::makeTitle( $row->page_namespace, $row->page_title ); |
||
283 | |||
284 | if ( $row->rd_from && $level < 2 ) { |
||
285 | $out->addHTML( $this->listItem( $row, $nt, $target, true ) ); |
||
286 | $this->showIndirectLinks( |
||
287 | $level + 1, |
||
288 | $nt, |
||
289 | $this->getConfig()->get( 'MaxRedirectLinksRetrieved' ) |
||
290 | ); |
||
291 | $out->addHTML( Xml::closeElement( 'li' ) ); |
||
292 | } else { |
||
293 | $out->addHTML( $this->listItem( $row, $nt, $target ) ); |
||
294 | } |
||
295 | } |
||
296 | |||
297 | $out->addHTML( $this->listEnd() ); |
||
298 | |||
299 | if ( $level == 0 ) { |
||
300 | if ( !$this->including() ) { |
||
301 | $out->addHTML( $prevnext ); |
||
0 ignored issues
–
show
The variable
$prevnext does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
302 | } |
||
303 | } |
||
304 | } |
||
305 | |||
306 | protected function listStart( $level ) { |
||
307 | return Xml::openElement( 'ul', ( $level ? [] : [ 'id' => 'mw-whatlinkshere-list' ] ) ); |
||
308 | } |
||
309 | |||
310 | protected function listItem( $row, $nt, $target, $notClose = false ) { |
||
311 | $dirmark = $this->getLanguage()->getDirMark(); |
||
312 | |||
313 | # local message cache |
||
314 | static $msgcache = null; |
||
315 | if ( $msgcache === null ) { |
||
316 | static $msgs = [ 'isredirect', 'istemplate', 'semicolon-separator', |
||
317 | 'whatlinkshere-links', 'isimage', 'editlink' ]; |
||
318 | $msgcache = []; |
||
319 | foreach ( $msgs as $msg ) { |
||
320 | $msgcache[$msg] = $this->msg( $msg )->escaped(); |
||
321 | } |
||
322 | } |
||
323 | |||
324 | if ( $row->rd_from ) { |
||
325 | $query = [ 'redirect' => 'no' ]; |
||
326 | } else { |
||
327 | $query = []; |
||
328 | } |
||
329 | |||
330 | $link = Linker::linkKnown( |
||
331 | $nt, |
||
332 | null, |
||
333 | $row->page_is_redirect ? [ 'class' => 'mw-redirect' ] : [], |
||
334 | $query |
||
335 | ); |
||
336 | |||
337 | // Display properties (redirect or template) |
||
338 | $propsText = ''; |
||
339 | $props = []; |
||
340 | if ( $row->rd_from ) { |
||
341 | $props[] = $msgcache['isredirect']; |
||
342 | } |
||
343 | if ( $row->is_template ) { |
||
344 | $props[] = $msgcache['istemplate']; |
||
345 | } |
||
346 | if ( $row->is_image ) { |
||
347 | $props[] = $msgcache['isimage']; |
||
348 | } |
||
349 | |||
350 | Hooks::run( 'WhatLinksHereProps', [ $row, $nt, $target, &$props ] ); |
||
351 | |||
352 | if ( count( $props ) ) { |
||
353 | $propsText = $this->msg( 'parentheses' ) |
||
354 | ->rawParams( implode( $msgcache['semicolon-separator'], $props ) )->escaped(); |
||
355 | } |
||
356 | |||
357 | # Space for utilities links, with a what-links-here link provided |
||
358 | $wlhLink = $this->wlhLink( $nt, $msgcache['whatlinkshere-links'], $msgcache['editlink'] ); |
||
359 | $wlh = Xml::wrapClass( |
||
360 | $this->msg( 'parentheses' )->rawParams( $wlhLink )->escaped(), |
||
361 | 'mw-whatlinkshere-tools' |
||
362 | ); |
||
363 | |||
364 | return $notClose ? |
||
365 | Xml::openElement( 'li' ) . "$link $propsText $dirmark $wlh\n" : |
||
366 | Xml::tags( 'li', null, "$link $propsText $dirmark $wlh" ) . "\n"; |
||
367 | } |
||
368 | |||
369 | protected function listEnd() { |
||
370 | return Xml::closeElement( 'ul' ); |
||
371 | } |
||
372 | |||
373 | protected function wlhLink( Title $target, $text, $editText ) { |
||
374 | static $title = null; |
||
375 | if ( $title === null ) { |
||
376 | $title = $this->getPageTitle(); |
||
377 | } |
||
378 | |||
379 | // always show a "<- Links" link |
||
380 | $links = [ |
||
381 | 'links' => Linker::linkKnown( |
||
382 | $title, |
||
383 | $text, |
||
384 | [], |
||
385 | [ 'target' => $target->getPrefixedText() ] |
||
386 | ), |
||
387 | ]; |
||
388 | |||
389 | // if the page is editable, add an edit link |
||
390 | View Code Duplication | if ( |
|
391 | // check user permissions |
||
392 | $this->getUser()->isAllowed( 'edit' ) && |
||
393 | // check, if the content model is editable through action=edit |
||
394 | ContentHandler::getForTitle( $target )->supportsDirectEditing() |
||
395 | ) { |
||
396 | $links['edit'] = Linker::linkKnown( |
||
397 | $target, |
||
398 | $editText, |
||
399 | [], |
||
400 | [ 'action' => 'edit' ] |
||
401 | ); |
||
402 | } |
||
403 | |||
404 | // build the links html |
||
405 | return $this->getLanguage()->pipeList( $links ); |
||
406 | } |
||
407 | |||
408 | function makeSelfLink( $text, $query ) { |
||
409 | return Linker::linkKnown( |
||
410 | $this->selfTitle, |
||
411 | $text, |
||
412 | [], |
||
413 | $query |
||
414 | ); |
||
415 | } |
||
416 | |||
417 | function getPrevNext( $prevId, $nextId ) { |
||
418 | $currentLimit = $this->opts->getValue( 'limit' ); |
||
419 | $prev = $this->msg( 'whatlinkshere-prev' )->numParams( $currentLimit )->escaped(); |
||
420 | $next = $this->msg( 'whatlinkshere-next' )->numParams( $currentLimit )->escaped(); |
||
421 | |||
422 | $changed = $this->opts->getChangedValues(); |
||
423 | unset( $changed['target'] ); // Already in the request title |
||
424 | |||
425 | View Code Duplication | if ( 0 != $prevId ) { |
|
426 | $overrides = [ 'from' => $this->opts->getValue( 'back' ) ]; |
||
427 | $prev = $this->makeSelfLink( $prev, array_merge( $changed, $overrides ) ); |
||
428 | } |
||
429 | View Code Duplication | if ( 0 != $nextId ) { |
|
430 | $overrides = [ 'from' => $nextId, 'back' => $prevId ]; |
||
431 | $next = $this->makeSelfLink( $next, array_merge( $changed, $overrides ) ); |
||
432 | } |
||
433 | |||
434 | $limitLinks = []; |
||
435 | $lang = $this->getLanguage(); |
||
436 | foreach ( $this->limits as $limit ) { |
||
437 | $prettyLimit = htmlspecialchars( $lang->formatNum( $limit ) ); |
||
438 | $overrides = [ 'limit' => $limit ]; |
||
439 | $limitLinks[] = $this->makeSelfLink( $prettyLimit, array_merge( $changed, $overrides ) ); |
||
440 | } |
||
441 | |||
442 | $nums = $lang->pipeList( $limitLinks ); |
||
443 | |||
444 | return $this->msg( 'viewprevnext' )->rawParams( $prev, $next, $nums )->escaped(); |
||
445 | } |
||
446 | |||
447 | function whatlinkshereForm() { |
||
448 | // We get nicer value from the title object |
||
449 | $this->opts->consumeValue( 'target' ); |
||
450 | // Reset these for new requests |
||
451 | $this->opts->consumeValues( [ 'back', 'from' ] ); |
||
452 | |||
453 | $target = $this->target ? $this->target->getPrefixedText() : ''; |
||
454 | $namespace = $this->opts->consumeValue( 'namespace' ); |
||
455 | $nsinvert = $this->opts->consumeValue( 'invert' ); |
||
456 | |||
457 | # Build up the form |
||
458 | $f = Xml::openElement( 'form', [ 'action' => wfScript() ] ); |
||
459 | |||
460 | # Values that should not be forgotten |
||
461 | $f .= Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() ); |
||
462 | foreach ( $this->opts->getUnconsumedValues() as $name => $value ) { |
||
463 | $f .= Html::hidden( $name, $value ); |
||
464 | } |
||
465 | |||
466 | $f .= Xml::fieldset( $this->msg( 'whatlinkshere' )->text() ); |
||
467 | |||
468 | # Target input (.mw-searchInput enables suggestions) |
||
469 | $f .= Xml::inputLabel( $this->msg( 'whatlinkshere-page' )->text(), 'target', |
||
470 | 'mw-whatlinkshere-target', 40, $target, [ 'class' => 'mw-searchInput' ] ); |
||
471 | |||
472 | $f .= ' '; |
||
473 | |||
474 | # Namespace selector |
||
475 | $f .= Html::namespaceSelector( |
||
476 | [ |
||
477 | 'selected' => $namespace, |
||
478 | 'all' => '', |
||
479 | 'label' => $this->msg( 'namespace' )->text() |
||
480 | ], [ |
||
481 | 'name' => 'namespace', |
||
482 | 'id' => 'namespace', |
||
483 | 'class' => 'namespaceselector', |
||
484 | ] |
||
485 | ); |
||
486 | |||
487 | $f .= ' ' . |
||
488 | Xml::checkLabel( |
||
489 | $this->msg( 'invert' )->text(), |
||
490 | 'invert', |
||
491 | 'nsinvert', |
||
492 | $nsinvert, |
||
493 | [ 'title' => $this->msg( 'tooltip-whatlinkshere-invert' )->text() ] |
||
494 | ); |
||
495 | |||
496 | $f .= ' '; |
||
497 | |||
498 | # Submit |
||
499 | $f .= Xml::submitButton( $this->msg( 'whatlinkshere-submit' )->text() ); |
||
500 | |||
501 | # Close |
||
502 | $f .= Xml::closeElement( 'fieldset' ) . Xml::closeElement( 'form' ) . "\n"; |
||
503 | |||
504 | return $f; |
||
505 | } |
||
506 | |||
507 | /** |
||
508 | * Create filter panel |
||
509 | * |
||
510 | * @return string HTML fieldset and filter panel with the show/hide links |
||
511 | */ |
||
512 | function getFilterPanel() { |
||
513 | $show = $this->msg( 'show' )->escaped(); |
||
514 | $hide = $this->msg( 'hide' )->escaped(); |
||
515 | |||
516 | $changed = $this->opts->getChangedValues(); |
||
517 | unset( $changed['target'] ); // Already in the request title |
||
518 | |||
519 | $links = []; |
||
520 | $types = [ 'hidetrans', 'hidelinks', 'hideredirs' ]; |
||
521 | if ( $this->target->getNamespace() == NS_FILE ) { |
||
522 | $types[] = 'hideimages'; |
||
523 | } |
||
524 | |||
525 | // Combined message keys: 'whatlinkshere-hideredirs', 'whatlinkshere-hidetrans', |
||
526 | // 'whatlinkshere-hidelinks', 'whatlinkshere-hideimages' |
||
527 | // To be sure they will be found by grep |
||
528 | foreach ( $types as $type ) { |
||
529 | $chosen = $this->opts->getValue( $type ); |
||
530 | $msg = $chosen ? $show : $hide; |
||
531 | $overrides = [ $type => !$chosen ]; |
||
532 | $links[] = $this->msg( "whatlinkshere-{$type}" )->rawParams( |
||
533 | $this->makeSelfLink( $msg, array_merge( $changed, $overrides ) ) )->escaped(); |
||
534 | } |
||
535 | |||
536 | return Xml::fieldset( |
||
537 | $this->msg( 'whatlinkshere-filters' )->text(), |
||
538 | $this->getLanguage()->pipeList( $links ) |
||
539 | ); |
||
540 | } |
||
541 | |||
542 | /** |
||
543 | * Return an array of subpages beginning with $search that this special page will accept. |
||
544 | * |
||
545 | * @param string $search Prefix to search for |
||
546 | * @param int $limit Maximum number of results to return (usually 10) |
||
547 | * @param int $offset Number of results to skip (usually 0) |
||
548 | * @return string[] Matching subpages |
||
549 | */ |
||
550 | public function prefixSearchSubpages( $search, $limit, $offset ) { |
||
551 | return $this->prefixSearchString( $search, $limit, $offset ); |
||
552 | } |
||
553 | |||
554 | protected function getGroupName() { |
||
555 | return 'pagetools'; |
||
556 | } |
||
557 | } |
||
558 |
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.
Let’s take a look at an example:
As you can see in this example, the array
$myArray
is initialized the first time when the foreach loop is entered. You can also see that the value of thebar
key is only written conditionally; thus, its value might result from a previous iteration.This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.