MediaWiki  master
SpecialLinkSearch.php
Go to the documentation of this file.
1 <?php
25 namespace MediaWiki\Specials;
26 
27 use HTMLForm;
35 use Parser;
36 use Skin;
37 use stdClass;
41 
48  private $mungedQuery = false;
50  private $mQuery;
52  private $mNs;
54  private $mProt;
55 
56  private UrlUtils $urlUtils;
57 
58  private function setParams( $params ) {
59  $this->mQuery = $params['query'];
60  $this->mNs = $params['namespace'];
61  $this->mProt = $params['protocol'];
62  }
63 
69  public function __construct(
70  IConnectionProvider $dbProvider,
71  LinkBatchFactory $linkBatchFactory,
72  UrlUtils $urlUtils
73  ) {
74  parent::__construct( 'LinkSearch' );
75  $this->setDatabaseProvider( $dbProvider );
76  $this->setLinkBatchFactory( $linkBatchFactory );
77  $this->urlUtils = $urlUtils;
78  }
79 
80  public function isCacheable() {
81  return false;
82  }
83 
84  public function execute( $par ) {
85  $this->setHeaders();
86  $this->outputHeader();
87 
88  $out = $this->getOutput();
89  $out->setPreventClickjacking( false );
90 
91  $request = $this->getRequest();
92  $target = $request->getVal( 'target', $par ?? '' );
93  $namespace = $request->getIntOrNull( 'namespace' );
94 
95  $protocols_list = [];
96  foreach ( $this->getConfig()->get( MainConfigNames::UrlProtocols ) as $prot ) {
97  if ( $prot !== '//' ) {
98  $protocols_list[] = $prot;
99  }
100  }
101 
102  $target2 = Parser::normalizeLinkUrl( $target );
103  $protocol = null;
104  $bits = $this->urlUtils->parse( $target );
105  if ( isset( $bits['scheme'] ) && isset( $bits['delimiter'] ) ) {
106  $protocol = $bits['scheme'] . $bits['delimiter'];
107  // Make sure UrlUtils::parse() didn't make some well-intended correction in the protocol
108  if ( str_starts_with( strtolower( $target ), strtolower( $protocol ) ) ) {
109  $target2 = substr( $target, strlen( $protocol ) );
110  } else {
111  // If it did, let LinkFilter::makeLikeArray() handle this
112  $protocol = '';
113  }
114  }
115 
116  $out->addWikiMsg(
117  'linksearch-text',
118  '<nowiki>' . $this->getLanguage()->commaList( $protocols_list ) . '</nowiki>',
119  count( $protocols_list )
120  );
121  $fields = [
122  'target' => [
123  'type' => 'text',
124  'name' => 'target',
125  'id' => 'target',
126  'size' => 50,
127  'label-message' => 'linksearch-pat',
128  'default' => $target,
129  'dir' => 'ltr',
130  ]
131  ];
132  if ( !$this->getConfig()->get( MainConfigNames::MiserMode ) ) {
133  $fields += [
134  'namespace' => [
135  'type' => 'namespaceselect',
136  'name' => 'namespace',
137  'label-message' => 'linksearch-ns',
138  'default' => $namespace,
139  'id' => 'namespace',
140  'all' => '',
141  'cssclass' => 'namespaceselector',
142  ],
143  ];
144  }
145  $htmlForm = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
146  $htmlForm->setSubmitTextMsg( 'linksearch-ok' );
147  $htmlForm->setWrapperLegendMsg( 'linksearch' );
148  $htmlForm->setTitle( $this->getPageTitle() );
149  $htmlForm->setMethod( 'get' );
150  $htmlForm->prepareForm()->displayForm( false );
151  $this->addHelpLink( 'Help:Linksearch' );
152 
153  if ( $target != '' ) {
154  $this->setParams( [
155  'query' => $target2,
156  'namespace' => $namespace,
157  'protocol' => $protocol ] );
158  parent::execute( $par );
159  if ( $this->mungedQuery === false ) {
160  $out->addWikiMsg( 'linksearch-error' );
161  }
162  }
163  }
164 
169  public function isSyndicated() {
170  return false;
171  }
172 
173  protected function linkParameters() {
174  $params = [];
175  $params['target'] = $this->mProt . $this->mQuery;
176  if ( $this->mNs !== null && !$this->getConfig()->get( MainConfigNames::MiserMode ) ) {
177  $params['namespace'] = $this->mNs;
178  }
179 
180  return $params;
181  }
182 
183  public function getQueryInfo() {
184  $dbr = $this->getDatabaseProvider()->getReplicaDatabase();
185 
186  $field = 'el_to_domain_index';
187  $extraFields = [
188  'urldomain' => 'el_to_domain_index',
189  'urlpath' => 'el_to_path'
190  ];
191  if ( $this->mQuery === '*' && $this->mProt !== '' ) {
192  $this->mungedQuery = [
193  $field . $dbr->buildLike( $this->mProt, $dbr->anyString() ),
194  ];
195  } else {
196  $this->mungedQuery = LinkFilter::getQueryConditions( $this->mQuery, [
197  'protocol' => $this->mProt,
198  'oneWildcard' => true,
199  'db' => $dbr
200  ] );
201  if ( $this->mungedQuery === false ) {
202  // Invalid query; return no results
203  return [ 'tables' => 'page', 'fields' => 'page_id', 'conds' => '0=1' ];
204  }
205  }
206  $orderBy = [ 'el_id' ];
207 
208  $retval = [
209  'tables' => [ 'page', 'externallinks' ],
210  'fields' => array_merge( [
211  'namespace' => 'page_namespace',
212  'title' => 'page_title',
213  ], $extraFields ),
214  'conds' => array_merge(
215  [
216  'page_id = el_from',
217  ],
218  $this->mungedQuery
219  ),
220  'options' => [ 'ORDER BY' => $orderBy ]
221  ];
222 
223  if ( $this->mNs !== null && !$this->getConfig()->get( MainConfigNames::MiserMode ) ) {
224  $retval['conds']['page_namespace'] = $this->mNs;
225  }
226 
227  return $retval;
228  }
229 
236  public function preprocessResults( $db, $res ) {
237  $this->executeLBFromResultWrapper( $res );
238  }
239 
245  public function formatResult( $skin, $result ) {
246  $title = new TitleValue( (int)$result->namespace, $result->title );
247  $pageLink = $this->getLinkRenderer()->makeLink( $title );
248  $url = LinkFilter::reverseIndexes( $result->urldomain ) . $result->urlpath;
249 
250  $urlLink = Linker::makeExternalLink( $url, $url );
251 
252  return $this->msg( 'linksearch-line' )->rawParams( $urlLink, $pageLink )->escaped();
253  }
254 
260  protected function getOrderFields() {
261  return [];
262  }
263 
264  protected function getGroupName() {
265  return 'pages';
266  }
267 
275  protected function getMaxResults() {
276  return max( parent::getMaxResults(), 60000 );
277  }
278 }
279 
283 class_alias( SpecialLinkSearch::class, 'SpecialLinkSearch' );
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition: HTMLForm.php:158
static factory( $displayFormat, $descriptor, IContextSource $context, $messagePrefix='')
Construct a HTMLForm object for given display type.
Definition: HTMLForm.php:360
Some internal bits split of from Skin.php.
Definition: Linker.php:65
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Definition: Linker.php:1130
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()
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:88
setDatabaseProvider(IConnectionProvider $databaseProvider)
Definition: QueryPage.php:985
executeLBFromResultWrapper(IResultWrapper $res, $ns=null)
Creates a new LinkBatch object, adds all pages from the passed result wrapper (MUST include title and...
Definition: QueryPage.php:946
setLinkBatchFactory(LinkBatchFactory $linkBatchFactory)
Definition: QueryPage.php:185
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 Per default the message key is the canonical name o...
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.
Definition: TitleValue.php:44
A service to expand, parse, and otherwise manipulate URLs.
Definition: UrlUtils.php:17
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition: Parser.php:115
static normalizeLinkUrl( $url)
Replace unusual escape codes in a URL with their equivalent characters.
Definition: Parser.php:2248
The base class for all skins.
Definition: Skin.php:60
Provide primary and replica IDatabase connections.
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:36
Result wrapper for grabbing data queried from an IDatabase object.