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:LinkSearch |
||
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 SpecialPage |
||
22 | * @author Brion Vibber |
||
23 | */ |
||
24 | |||
25 | /** |
||
26 | * Special:LinkSearch to search the external-links table. |
||
27 | * @ingroup SpecialPage |
||
28 | */ |
||
29 | class LinkSearchPage extends QueryPage { |
||
30 | /** @var array|bool */ |
||
31 | private $mungedQuery = false; |
||
32 | |||
33 | function setParams( $params ) { |
||
34 | $this->mQuery = $params['query']; |
||
0 ignored issues
–
show
|
|||
35 | $this->mNs = $params['namespace']; |
||
0 ignored issues
–
show
The property
mNs does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
36 | $this->mProt = $params['protocol']; |
||
0 ignored issues
–
show
The property
mProt does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
37 | } |
||
38 | |||
39 | function __construct( $name = 'LinkSearch' ) { |
||
40 | parent::__construct( $name ); |
||
41 | |||
42 | // Since we don't control the constructor parameters, we can't inject services that way. |
||
43 | // Instead, we initialize services in the execute() method, and allow them to be overridden |
||
44 | // using the setServices() method. |
||
45 | } |
||
46 | |||
47 | function isCacheable() { |
||
48 | return false; |
||
49 | } |
||
50 | |||
51 | public function execute( $par ) { |
||
52 | $this->setHeaders(); |
||
53 | $this->outputHeader(); |
||
54 | |||
55 | $out = $this->getOutput(); |
||
56 | $out->allowClickjacking(); |
||
57 | |||
58 | $request = $this->getRequest(); |
||
59 | $target = $request->getVal( 'target', $par ); |
||
60 | $namespace = $request->getIntOrNull( 'namespace' ); |
||
61 | |||
62 | $protocols_list = []; |
||
63 | foreach ( $this->getConfig()->get( 'UrlProtocols' ) as $prot ) { |
||
64 | if ( $prot !== '//' ) { |
||
65 | $protocols_list[] = $prot; |
||
66 | } |
||
67 | } |
||
68 | |||
69 | $target2 = $target; |
||
70 | // Get protocol, default is http:// |
||
71 | $protocol = 'http://'; |
||
72 | $bits = wfParseUrl( $target ); |
||
73 | if ( isset( $bits['scheme'] ) && isset( $bits['delimiter'] ) ) { |
||
74 | $protocol = $bits['scheme'] . $bits['delimiter']; |
||
75 | // Make sure wfParseUrl() didn't make some well-intended correction in the |
||
76 | // protocol |
||
77 | if ( strcasecmp( $protocol, substr( $target, 0, strlen( $protocol ) ) ) === 0 ) { |
||
78 | $target2 = substr( $target, strlen( $protocol ) ); |
||
79 | } else { |
||
80 | // If it did, let LinkFilter::makeLikeArray() handle this |
||
81 | $protocol = ''; |
||
82 | } |
||
83 | } |
||
84 | |||
85 | $out->addWikiMsg( |
||
86 | 'linksearch-text', |
||
87 | '<nowiki>' . $this->getLanguage()->commaList( $protocols_list ) . '</nowiki>', |
||
88 | count( $protocols_list ) |
||
89 | ); |
||
90 | $fields = [ |
||
91 | 'target' => [ |
||
92 | 'type' => 'text', |
||
93 | 'name' => 'target', |
||
94 | 'id' => 'target', |
||
95 | 'size' => 50, |
||
96 | 'label-message' => 'linksearch-pat', |
||
97 | 'default' => $target, |
||
98 | 'dir' => 'ltr', |
||
99 | ] |
||
100 | ]; |
||
101 | View Code Duplication | if ( !$this->getConfig()->get( 'MiserMode' ) ) { |
|
102 | $fields += [ |
||
103 | 'namespace' => [ |
||
104 | 'type' => 'namespaceselect', |
||
105 | 'name' => 'namespace', |
||
106 | 'label-message' => 'linksearch-ns', |
||
107 | 'default' => $namespace, |
||
108 | 'id' => 'namespace', |
||
109 | 'all' => '', |
||
110 | 'cssclass' => 'namespaceselector', |
||
111 | ], |
||
112 | ]; |
||
113 | } |
||
114 | $hiddenFields = [ |
||
115 | 'title' => $this->getPageTitle()->getPrefixedDBkey(), |
||
116 | ]; |
||
117 | $htmlForm = HTMLForm::factory( 'ooui', $fields, $this->getContext() ); |
||
118 | $htmlForm->addHiddenFields( $hiddenFields ); |
||
119 | $htmlForm->setSubmitTextMsg( 'linksearch-ok' ); |
||
120 | $htmlForm->setWrapperLegendMsg( 'linksearch' ); |
||
121 | $htmlForm->setAction( wfScript() ); |
||
122 | $htmlForm->setMethod( 'get' ); |
||
123 | $htmlForm->prepareForm()->displayForm( false ); |
||
124 | $this->addHelpLink( 'Help:Linksearch' ); |
||
125 | |||
126 | if ( $target != '' ) { |
||
127 | $this->setParams( [ |
||
128 | 'query' => Parser::normalizeLinkUrl( $target2 ), |
||
129 | 'namespace' => $namespace, |
||
130 | 'protocol' => $protocol ] ); |
||
131 | parent::execute( $par ); |
||
132 | if ( $this->mungedQuery === false ) { |
||
133 | $out->addWikiMsg( 'linksearch-error' ); |
||
134 | } |
||
135 | } |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | * Disable RSS/Atom feeds |
||
140 | * @return bool |
||
141 | */ |
||
142 | function isSyndicated() { |
||
143 | return false; |
||
144 | } |
||
145 | |||
146 | /** |
||
147 | * Return an appropriately formatted LIKE query and the clause |
||
148 | * |
||
149 | * @param string $query Search pattern to search for |
||
150 | * @param string $prot Protocol, e.g. 'http://' |
||
151 | * |
||
152 | * @return array |
||
153 | */ |
||
154 | static function mungeQuery( $query, $prot ) { |
||
155 | $field = 'el_index'; |
||
156 | $dbr = wfGetDB( DB_REPLICA ); |
||
157 | |||
158 | if ( $query === '*' && $prot !== '' ) { |
||
159 | // Allow queries like 'ftp://*' to find all ftp links |
||
160 | $rv = [ $prot, $dbr->anyString() ]; |
||
161 | } else { |
||
162 | $rv = LinkFilter::makeLikeArray( $query, $prot ); |
||
163 | } |
||
164 | |||
165 | if ( $rv === false ) { |
||
166 | // LinkFilter doesn't handle wildcard in IP, so we'll have to munge here. |
||
167 | $pattern = '/^(:?[0-9]{1,3}\.)+\*\s*$|^(:?[0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]*\*\s*$/'; |
||
168 | if ( preg_match( $pattern, $query ) ) { |
||
169 | $rv = [ $prot . rtrim( $query, " \t*" ), $dbr->anyString() ]; |
||
170 | $field = 'el_to'; |
||
171 | } |
||
172 | } |
||
173 | |||
174 | return [ $rv, $field ]; |
||
175 | } |
||
176 | |||
177 | function linkParameters() { |
||
178 | $params = []; |
||
179 | $params['target'] = $this->mProt . $this->mQuery; |
||
180 | if ( $this->mNs !== null && !$this->getConfig()->get( 'MiserMode' ) ) { |
||
181 | $params['namespace'] = $this->mNs; |
||
182 | } |
||
183 | |||
184 | return $params; |
||
185 | } |
||
186 | |||
187 | public function getQueryInfo() { |
||
188 | $dbr = wfGetDB( DB_REPLICA ); |
||
189 | // strip everything past first wildcard, so that |
||
190 | // index-based-only lookup would be done |
||
191 | list( $this->mungedQuery, $clause ) = self::mungeQuery( $this->mQuery, $this->mProt ); |
||
192 | if ( $this->mungedQuery === false ) { |
||
193 | // Invalid query; return no results |
||
194 | return [ 'tables' => 'page', 'fields' => 'page_id', 'conds' => '0=1' ]; |
||
195 | } |
||
196 | |||
197 | $stripped = LinkFilter::keepOneWildcard( $this->mungedQuery ); |
||
198 | $like = $dbr->buildLike( $stripped ); |
||
199 | $retval = [ |
||
200 | 'tables' => [ 'page', 'externallinks' ], |
||
201 | 'fields' => [ |
||
202 | 'namespace' => 'page_namespace', |
||
203 | 'title' => 'page_title', |
||
204 | 'value' => 'el_index', |
||
205 | 'url' => 'el_to' |
||
206 | ], |
||
207 | 'conds' => [ |
||
208 | 'page_id = el_from', |
||
209 | "$clause $like" |
||
210 | ], |
||
211 | 'options' => [ 'USE INDEX' => $clause ] |
||
212 | ]; |
||
213 | |||
214 | if ( $this->mNs !== null && !$this->getConfig()->get( 'MiserMode' ) ) { |
||
215 | $retval['conds']['page_namespace'] = $this->mNs; |
||
216 | } |
||
217 | |||
218 | return $retval; |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * Pre-fill the link cache |
||
223 | * |
||
224 | * @param IDatabase $db |
||
225 | * @param ResultWrapper $res |
||
226 | */ |
||
227 | function preprocessResults( $db, $res ) { |
||
228 | $this->executeLBFromResultWrapper( $res ); |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * @param Skin $skin |
||
233 | * @param object $result Result row |
||
234 | * @return string |
||
235 | */ |
||
236 | function formatResult( $skin, $result ) { |
||
237 | $title = new TitleValue( (int)$result->namespace, $result->title ); |
||
238 | $pageLink = $this->getLinkRenderer()->makeLink( $title ); |
||
239 | |||
240 | $url = $result->url; |
||
241 | $urlLink = Linker::makeExternalLink( $url, $url ); |
||
242 | |||
243 | return $this->msg( 'linksearch-line' )->rawParams( $urlLink, $pageLink )->escaped(); |
||
244 | } |
||
245 | |||
246 | /** |
||
247 | * Override to squash the ORDER BY. |
||
248 | * We do a truncated index search, so the optimizer won't trust |
||
249 | * it as good enough for optimizing sort. The implicit ordering |
||
250 | * from the scan will usually do well enough for our needs. |
||
251 | * @return array |
||
252 | */ |
||
253 | function getOrderFields() { |
||
254 | return []; |
||
255 | } |
||
256 | |||
257 | protected function getGroupName() { |
||
258 | return 'redirects'; |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * enwiki complained about low limits on this special page |
||
263 | * |
||
264 | * @see T130058 |
||
265 | * @todo FIXME This special page should not use LIMIT for paging |
||
266 | */ |
||
267 | protected function getMaxResults() { |
||
268 | return max( parent::getMaxResults(), 60000 ); |
||
269 | } |
||
270 | } |
||
271 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: