MediaWiki master
SpecialLinkSearch.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Specials;
22
31use Skin;
32use stdClass;
38
47 private $mungedQuery = false;
49 private $mQuery;
51 private $mNs;
53 private $mProt;
54
55 private UrlUtils $urlUtils;
56
57 private function setParams( $params ) {
58 $this->mQuery = $params['query'];
59 $this->mNs = $params['namespace'];
60 $this->mProt = $params['protocol'];
61 }
62
68 public function __construct(
69 IConnectionProvider $dbProvider,
70 LinkBatchFactory $linkBatchFactory,
71 UrlUtils $urlUtils
72 ) {
73 parent::__construct( 'LinkSearch' );
74 $this->setDatabaseProvider( $dbProvider );
75 $this->setLinkBatchFactory( $linkBatchFactory );
76 $this->urlUtils = $urlUtils;
77 }
78
79 public function isCacheable() {
80 return false;
81 }
82
83 public function execute( $par ) {
84 $this->setHeaders();
85 $this->outputHeader();
86
87 $out = $this->getOutput();
88 $out->setPreventClickjacking( false );
89
90 $request = $this->getRequest();
91 $target = $request->getVal( 'target', $par ?? '' );
92 $namespace = $request->getIntOrNull( 'namespace' );
93
94 $protocols_list = [];
95 foreach ( $this->getConfig()->get( MainConfigNames::UrlProtocols ) as $prot ) {
96 if ( $prot !== '//' ) {
97 $protocols_list[] = $prot;
98 }
99 }
100
101 $target2 = Parser::normalizeLinkUrl( $target );
102 $protocol = null;
103 $bits = $this->urlUtils->parse( $target );
104 if ( isset( $bits['scheme'] ) && isset( $bits['delimiter'] ) ) {
105 $protocol = $bits['scheme'] . $bits['delimiter'];
106 // Make sure UrlUtils::parse() didn't make some well-intended correction in the protocol
107 if ( str_starts_with( strtolower( $target ), strtolower( $protocol ) ) ) {
108 $target2 = substr( $target, strlen( $protocol ) );
109 } else {
110 // If it did, let LinkFilter::makeLikeArray() handle this
111 $protocol = '';
112 }
113 }
114
115 $out->addWikiMsg(
116 'linksearch-text',
117 '<nowiki>' . $this->getLanguage()->commaList( $protocols_list ) . '</nowiki>',
118 count( $protocols_list )
119 );
120 $fields = [
121 'target' => [
122 'type' => 'text',
123 'name' => 'target',
124 'id' => 'target',
125 'size' => 50,
126 'label-message' => 'linksearch-pat',
127 'default' => $target,
128 'dir' => 'ltr',
129 ]
130 ];
131 if ( !$this->getConfig()->get( MainConfigNames::MiserMode ) ) {
132 $fields += [
133 'namespace' => [
134 'type' => 'namespaceselect',
135 'name' => 'namespace',
136 'label-message' => 'linksearch-ns',
137 'default' => $namespace,
138 'id' => 'namespace',
139 'all' => '',
140 'cssclass' => 'namespaceselector',
141 ],
142 ];
143 }
144 $htmlForm = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
145 $htmlForm->setSubmitTextMsg( 'linksearch-ok' );
146 $htmlForm->setWrapperLegendMsg( 'linksearch' );
147 $htmlForm->setTitle( $this->getPageTitle() );
148 $htmlForm->setMethod( 'get' );
149 $htmlForm->prepareForm()->displayForm( false );
150 $this->addHelpLink( 'Help:Linksearch' );
151
152 if ( $target != '' ) {
153 $this->setParams( [
154 'query' => $target2,
155 'namespace' => $namespace,
156 'protocol' => $protocol ] );
157 parent::execute( $par );
158 if ( $this->mungedQuery === false ) {
159 $out->addWikiMsg( 'linksearch-error' );
160 }
161 }
162 }
163
168 public function isSyndicated() {
169 return false;
170 }
171
172 protected function linkParameters() {
173 $params = [];
174 $params['target'] = $this->mProt . $this->mQuery;
175 if ( $this->mNs !== null && !$this->getConfig()->get( MainConfigNames::MiserMode ) ) {
176 $params['namespace'] = $this->mNs;
177 }
178
179 return $params;
180 }
181
182 public function getQueryInfo() {
183 $dbr = $this->getDatabaseProvider()->getReplicaDatabase();
184
185 $field = 'el_to_domain_index';
186 $extraFields = [
187 'urldomain' => 'el_to_domain_index',
188 'urlpath' => 'el_to_path'
189 ];
190 if ( $this->mQuery === '*' && $this->mProt !== '' ) {
191 if ( $this->mProt !== null ) {
192 $this->mungedQuery = [
193 $dbr->expr( $field, IExpression::LIKE, new LikeValue( $this->mProt, $dbr->anyString() ) ),
194 ];
195 } else {
196 $this->mungedQuery = [
197 $dbr->expr( $field, IExpression::LIKE, new LikeValue( 'http://', $dbr->anyString() ) )
198 ->or( $field, IExpression::LIKE, new LikeValue( 'https://', $dbr->anyString() ) ),
199 ];
200 }
201 } else {
202 $this->mungedQuery = LinkFilter::getQueryConditions( $this->mQuery, [
203 'protocol' => $this->mProt,
204 'oneWildcard' => true,
205 'db' => $dbr
206 ] );
207 if ( $this->mungedQuery === false ) {
208 // Invalid query; return no results
209 return [ 'tables' => 'page', 'fields' => 'page_id', 'conds' => '0=1' ];
210 }
211 }
212 $orderBy = [ 'el_id' ];
213
214 $retval = [
215 'tables' => [ 'page', 'externallinks' ],
216 'fields' => array_merge( [
217 'namespace' => 'page_namespace',
218 'title' => 'page_title',
219 ], $extraFields ),
220 'conds' => array_merge(
221 [
222 'page_id = el_from',
223 ],
224 $this->mungedQuery
225 ),
226 'options' => [ 'ORDER BY' => $orderBy ]
227 ];
228
229 if ( $this->mNs !== null && !$this->getConfig()->get( MainConfigNames::MiserMode ) ) {
230 $retval['conds']['page_namespace'] = $this->mNs;
231 }
232
233 return $retval;
234 }
235
242 public function preprocessResults( $db, $res ) {
243 $this->executeLBFromResultWrapper( $res );
244 }
245
251 public function formatResult( $skin, $result ) {
252 $title = new TitleValue( (int)$result->namespace, $result->title );
253 $pageLink = $this->getLinkRenderer()->makeLink( $title );
254 $url = LinkFilter::reverseIndexes( $result->urldomain ) . $result->urlpath;
255
256 $urlLink = $this->getLinkRenderer()->makeExternalLink( $url, $url, $this->getFullTitle() );
257
258 return $this->msg( 'linksearch-line' )->rawParams( $urlLink, $pageLink )->escaped();
259 }
260
266 protected function getOrderFields() {
267 return [];
268 }
269
270 protected function getGroupName() {
271 return 'pages';
272 }
273
281 protected function getMaxResults() {
282 return max( parent::getMaxResults(), 60000 );
283 }
284}
285
287class_alias( SpecialLinkSearch::class, 'SpecialLinkSearch' );
array $params
The job parameters.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:208
A class containing constants representing the names of configuration variables.
const UrlProtocols
Name constant for the UrlProtocols setting, for use with Config::get()
const MiserMode
Name constant for the MiserMode setting, for use with Config::get()
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition Parser.php:155
This is a class for doing query pages; since they're almost all the same, we factor out some of the f...
Definition QueryPage.php:89
setDatabaseProvider(IConnectionProvider $databaseProvider)
executeLBFromResultWrapper(IResultWrapper $res, $ns=null)
Creates a new LinkBatch object, adds all pages from the passed result wrapper (MUST include title and...
setLinkBatchFactory(LinkBatchFactory $linkBatchFactory)
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getPageTitle( $subpage=false)
Get a self-referential title object.
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getLanguage()
Shortcut to get user's language.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages By default the message key is the canonical name of...
getFullTitle()
Return the full title, including $par.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Special:LinkSearch to search the external-links table.
getOrderFields()
Override to squash the ORDER BY.
getQueryInfo()
Subclasses return an SQL query here, formatted as an array with the following keys: tables => Table(s...
execute( $par)
This is the actual workhorse.
__construct(IConnectionProvider $dbProvider, LinkBatchFactory $linkBatchFactory, UrlUtils $urlUtils)
getMaxResults()
enwiki complained about low limits on this special page
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
linkParameters()
If using extra form wheely-dealies, return a set of parameters here as an associative array.
preprocessResults( $db, $res)
Pre-fill the link cache.
isCacheable()
Is the output of this query cacheable? Non-cacheable expensive pages will be disabled in miser mode a...
Represents the target of a wiki link.
A service to expand, parse, and otherwise manipulate URLs.
Definition UrlUtils.php:16
The base class for all skins.
Definition Skin.php:59
Content of like value.
Definition LikeValue.php:14
Provide primary and replica IDatabase connections.
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:39
Result wrapper for grabbing data queried from an IDatabase object.