MediaWiki  master
ApiQueryExtLinksUsage.php
Go to the documentation of this file.
1 <?php
2 
25 
30 
35  public function __construct( ApiQuery $query, $moduleName ) {
36  parent::__construct( $query, $moduleName, 'eu' );
37  }
38 
39  public function execute() {
40  $this->run();
41  }
42 
43  public function getCacheMode( $params ) {
44  return 'public';
45  }
46 
47  public function executeGenerator( $resultPageSet ) {
48  $this->run( $resultPageSet );
49  }
50 
55  private function run( $resultPageSet = null ) {
56  $params = $this->extractRequestParams();
57  $db = $this->getDB();
58 
59  $query = $params['query'];
60  $protocol = self::getProtocolPrefix( $params['protocol'] );
61 
62  $this->addTables( [ 'externallinks', 'page' ] );
63  $this->addJoinConds( [ 'page' => [ 'JOIN', 'page_id=el_from' ] ] );
64 
65  $miser_ns = [];
66  if ( $this->getConfig()->get( 'MiserMode' ) ) {
67  $miser_ns = $params['namespace'] ?: [];
68  } else {
69  $this->addWhereFld( 'page_namespace', $params['namespace'] );
70  }
71 
72  $orderBy = [];
73 
74  if ( $query !== null && $query !== '' ) {
75  if ( $protocol === null ) {
76  $protocol = 'http://';
77  }
78 
79  // Normalize query to match the normalization applied for the externallinks table
80  $query = Parser::normalizeLinkUrl( $protocol . $query );
81 
82  $conds = LinkFilter::getQueryConditions( $query, [
83  'protocol' => '',
84  'oneWildcard' => true,
85  'db' => $db
86  ] );
87  if ( !$conds ) {
88  $this->dieWithError( 'apierror-badquery' );
89  }
90  $this->addWhere( $conds );
91  if ( !isset( $conds['el_index_60'] ) ) {
92  $orderBy[] = 'el_index_60';
93  }
94  } else {
95  $orderBy[] = 'el_index_60';
96 
97  if ( $protocol !== null ) {
98  $this->addWhere( 'el_index_60' . $db->buildLike( "$protocol", $db->anyString() ) );
99  } else {
100  // We're querying all protocols, filter out duplicate protocol-relative links
101  $this->addWhere( $db->makeList( [
102  'el_to NOT' . $db->buildLike( '//', $db->anyString() ),
103  'el_index_60 ' . $db->buildLike( 'http://', $db->anyString() ),
104  ], LIST_OR ) );
105  }
106  }
107 
108  $orderBy[] = 'el_id';
109  $this->addOption( 'ORDER BY', $orderBy );
110  $this->addFields( $orderBy ); // Make sure
111 
112  $prop = array_fill_keys( $params['prop'], true );
113  $fld_ids = isset( $prop['ids'] );
114  $fld_title = isset( $prop['title'] );
115  $fld_url = isset( $prop['url'] );
116 
117  if ( $resultPageSet === null ) {
118  $this->addFields( [
119  'page_id',
120  'page_namespace',
121  'page_title'
122  ] );
123  $this->addFieldsIf( 'el_to', $fld_url );
124  } else {
125  $this->addFields( $resultPageSet->getPageTableFields() );
126  }
127 
128  $limit = $params['limit'];
129  $this->addOption( 'LIMIT', $limit + 1 );
130 
131  // T244254: Avoid MariaDB deciding to scan all of `page`.
132  $this->addOption( 'STRAIGHT_JOIN' );
133 
134  if ( $params['continue'] !== null ) {
135  $cont = explode( '|', $params['continue'] );
136  $this->dieContinueUsageIf( count( $cont ) !== count( $orderBy ) );
137  $i = count( $cont ) - 1;
138  $cond = $orderBy[$i] . ' >= ' . $db->addQuotes( rawurldecode( $cont[$i] ) );
139  while ( $i-- > 0 ) {
140  $field = $orderBy[$i];
141  $v = $db->addQuotes( rawurldecode( $cont[$i] ) );
142  $cond = "($field > $v OR ($field = $v AND $cond))";
143  }
144  $this->addWhere( $cond );
145  }
146 
147  $res = $this->select( __METHOD__ );
148 
149  $result = $this->getResult();
150 
151  if ( $resultPageSet === null ) {
152  $this->executeGenderCacheFromResultWrapper( $res, __METHOD__ );
153  }
154 
155  $count = 0;
156  foreach ( $res as $row ) {
157  if ( ++$count > $limit ) {
158  // We've reached the one extra which shows that there are
159  // additional pages to be had. Stop here...
160  $this->setContinue( $orderBy, $row );
161  break;
162  }
163 
164  if ( count( $miser_ns ) && !in_array( $row->page_namespace, $miser_ns ) ) {
165  continue;
166  }
167 
168  if ( $resultPageSet === null ) {
169  $vals = [
170  ApiResult::META_TYPE => 'assoc',
171  ];
172  if ( $fld_ids ) {
173  $vals['pageid'] = (int)$row->page_id;
174  }
175  if ( $fld_title ) {
176  $title = Title::makeTitle( $row->page_namespace, $row->page_title );
178  }
179  if ( $fld_url ) {
180  $to = $row->el_to;
181  // expand protocol-relative urls
182  if ( $params['expandurl'] ) {
183  $to = wfExpandUrl( $to, PROTO_CANONICAL );
184  }
185  $vals['url'] = $to;
186  }
187  $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $vals );
188  if ( !$fit ) {
189  $this->setContinue( $orderBy, $row );
190  break;
191  }
192  } else {
193  $resultPageSet->processDbRow( $row );
194  }
195  }
196 
197  if ( $resultPageSet === null ) {
198  $result->addIndexedTagName( [ 'query', $this->getModuleName() ],
199  $this->getModulePrefix() );
200  }
201  }
202 
203  private function setContinue( $orderBy, $row ) {
204  $fields = [];
205  foreach ( $orderBy as $field ) {
206  $fields[] = strtr( $row->$field, [ '%' => '%25', '|' => '%7C' ] );
207  }
208  $this->setContinueEnumParameter( 'continue', implode( '|', $fields ) );
209  }
210 
211  public function getAllowedParams() {
212  $ret = [
213  'prop' => [
214  ApiBase::PARAM_ISMULTI => true,
215  ApiBase::PARAM_DFLT => 'ids|title|url',
217  'ids',
218  'title',
219  'url'
220  ],
222  ],
223  'continue' => [
224  ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
225  ],
226  'protocol' => [
228  ApiBase::PARAM_DFLT => '',
229  ],
230  'query' => null,
231  'namespace' => [
232  ApiBase::PARAM_ISMULTI => true,
233  ApiBase::PARAM_TYPE => 'namespace'
234  ],
235  'limit' => [
236  ApiBase::PARAM_DFLT => 10,
237  ApiBase::PARAM_TYPE => 'limit',
238  ApiBase::PARAM_MIN => 1,
241  ],
242  'expandurl' => false,
243  ];
244 
245  if ( $this->getConfig()->get( 'MiserMode' ) ) {
246  $ret['namespace'][ApiBase::PARAM_HELP_MSG_APPEND] = [
247  'api-help-param-limited-in-miser-mode',
248  ];
249  }
250 
251  return $ret;
252  }
253 
254  public static function prepareProtocols() {
255  $urlProtocols = MediaWikiServices::getInstance()->getMainConfig()->get( 'UrlProtocols' );
256  $protocols = [ '' ];
257  foreach ( $urlProtocols as $p ) {
258  if ( $p !== '//' ) {
259  $protocols[] = substr( $p, 0, strpos( $p, ':' ) );
260  }
261  }
262 
263  return $protocols;
264  }
265 
266  public static function getProtocolPrefix( $protocol ) {
267  // Find the right prefix
268  $urlProtocols = MediaWikiServices::getInstance()->getMainConfig()->get( 'UrlProtocols' );
269  if ( $protocol && !in_array( $protocol, $urlProtocols ) ) {
270  foreach ( $urlProtocols as $p ) {
271  if ( substr( $p, 0, strlen( $protocol ) ) === $protocol ) {
272  $protocol = $p;
273  break;
274  }
275  }
276 
277  return $protocol;
278  } else {
279  return null;
280  }
281  }
282 
283  protected function getExamplesMessages() {
284  return [
285  'action=query&list=exturlusage&euquery=www.mediawiki.org'
286  => 'apihelp-query+exturlusage-example-simple',
287  ];
288  }
289 
290  public function getHelpUrls() {
291  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Exturlusage';
292  }
293 }
LIST_OR
const LIST_OR
Definition: Defines.php:46
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:72
ApiQueryExtLinksUsage\getCacheMode
getCacheMode( $params)
Get the cache mode for the data generated by this module.
Definition: ApiQueryExtLinksUsage.php:43
ApiQueryBase\addFields
addFields( $value)
Add a set of fields to select to the internal array.
Definition: ApiQueryBase.php:212
ApiQuery
This is the main query class.
Definition: ApiQuery.php:39
LinkFilter\getQueryConditions
static getQueryConditions( $filterEntry, array $options=[])
Return query conditions which will match the specified string.
Definition: LinkFilter.php:256
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:203
ApiResult\META_TYPE
const META_TYPE
Key for the 'type' metadata item.
Definition: ApiResult.php:110
ApiBase\dieWithError
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:1436
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:162
ApiQueryExtLinksUsage\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiQueryExtLinksUsage.php:290
ApiBase\PARAM_TYPE
const PARAM_TYPE
Definition: ApiBase.php:81
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:628
ApiQueryExtLinksUsage
Definition: ApiQueryExtLinksUsage.php:29
ApiQueryBase\addOption
addOption( $name, $value=null)
Add an option such as LIMIT or USE INDEX.
Definition: ApiQueryBase.php:378
ApiQueryExtLinksUsage\execute
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition: ApiQueryExtLinksUsage.php:39
$res
$res
Definition: testCompression.php:57
ApiBase\PARAM_HELP_MSG_APPEND
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
Definition: ApiBase.php:169
ApiQueryBase\addFieldsIf
addFieldsIf( $value, $condition)
Same as addFields(), but add the fields only if a condition is met.
Definition: ApiQueryBase.php:222
ApiQueryGeneratorBase\setContinueEnumParameter
setContinueEnumParameter( $paramName, $paramValue)
Overridden to set the generator param if in generator mode.
Definition: ApiQueryGeneratorBase.php:83
ApiQueryExtLinksUsage\prepareProtocols
static prepareProtocols()
Definition: ApiQueryExtLinksUsage.php:254
ApiBase\PARAM_MIN
const PARAM_MIN
Definition: ApiBase.php:93
ApiQueryBase\executeGenderCacheFromResultWrapper
executeGenderCacheFromResultWrapper(IResultWrapper $res, $fname=__METHOD__, $fieldPrefix='page')
Preprocess the result set to fill the GenderCache with the necessary information before using self::a...
Definition: ApiQueryBase.php:626
ApiBase\LIMIT_BIG1
const LIMIT_BIG1
Fast query, standard limit.
Definition: ApiBase.php:220
ApiQueryBase\getDB
getDB()
Get the Query database connection (read-only)
Definition: ApiQueryBase.php:117
ApiBase\PARAM_MAX
const PARAM_MAX
Definition: ApiBase.php:85
ApiQueryExtLinksUsage\setContinue
setContinue( $orderBy, $row)
Definition: ApiQueryExtLinksUsage.php:203
ApiQueryBase\addTables
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
Definition: ApiQueryBase.php:182
ApiQueryBase\select
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
Definition: ApiQueryBase.php:399
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:764
ApiQueryExtLinksUsage\run
run( $resultPageSet=null)
Definition: ApiQueryExtLinksUsage.php:55
$title
$title
Definition: testCompression.php:38
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:648
PROTO_CANONICAL
const PROTO_CANONICAL
Definition: Defines.php:196
ApiQueryExtLinksUsage\__construct
__construct(ApiQuery $query, $moduleName)
Definition: ApiQueryExtLinksUsage.php:35
ApiBase\getModulePrefix
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition: ApiBase.php:505
ApiBase\dieContinueUsageIf
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition: ApiBase.php:1626
ApiQueryBase\addJoinConds
addJoinConds( $join_conds)
Add a set of JOIN conditions to the internal array.
Definition: ApiQueryBase.php:201
ApiQueryBase\addWhereFld
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
Definition: ApiQueryBase.php:282
ApiQueryExtLinksUsage\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiQueryExtLinksUsage.php:211
ApiQueryGeneratorBase
Definition: ApiQueryGeneratorBase.php:28
Parser\normalizeLinkUrl
static normalizeLinkUrl( $url)
Replace unusual escape codes in a URL with their equivalent characters.
Definition: Parser.php:2265
ApiQueryExtLinksUsage\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiQueryExtLinksUsage.php:283
ApiBase\LIMIT_BIG2
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition: ApiBase.php:222
ApiBase\PARAM_DFLT
const PARAM_DFLT
Definition: ApiBase.php:73
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:497
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
Definition: ApiBase.php:77
ApiBase\PARAM_MAX2
const PARAM_MAX2
Definition: ApiBase.php:89
ApiQueryBase\addWhere
addWhere( $value)
Add a set of WHERE clauses to the internal array.
Definition: ApiQueryBase.php:245
ApiBase\PARAM_HELP_MSG_PER_VALUE
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
Definition: ApiBase.php:195
ApiQueryExtLinksUsage\executeGenerator
executeGenerator( $resultPageSet)
Execute this module as a generator.
Definition: ApiQueryExtLinksUsage.php:47
ApiQueryBase\addTitleInfo
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
Definition: ApiQueryBase.php:466
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:474
ApiQueryExtLinksUsage\getProtocolPrefix
static getProtocolPrefix( $protocol)
Definition: ApiQueryExtLinksUsage.php:266