00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 if ( !defined( 'MEDIAWIKI' ) ) {
00027
00028 require_once ( 'ApiQueryBase.php' );
00029 }
00030
00036 class ApiQueryInfo extends ApiQueryBase {
00037
00038 private $fld_protection = false, $fld_talkid = false,
00039 $fld_subjectid = false, $fld_url = false,
00040 $fld_readable = false, $fld_watched = false,
00041 $fld_preload = false;
00042
00043 public function __construct( $query, $moduleName ) {
00044 parent :: __construct( $query, $moduleName, 'in' );
00045 }
00046
00047 public function requestExtraData( $pageSet ) {
00048 $pageSet->requestField( 'page_restrictions' );
00049 $pageSet->requestField( 'page_is_redirect' );
00050 $pageSet->requestField( 'page_is_new' );
00051 $pageSet->requestField( 'page_counter' );
00052 $pageSet->requestField( 'page_touched' );
00053 $pageSet->requestField( 'page_latest' );
00054 $pageSet->requestField( 'page_len' );
00055 }
00056
00063 protected function getTokenFunctions() {
00064
00065 if ( isset( $this->tokenFunctions ) )
00066 return $this->tokenFunctions;
00067
00068
00069 if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) )
00070 return array();
00071
00072 $this->tokenFunctions = array(
00073 'edit' => array( 'ApiQueryInfo', 'getEditToken' ),
00074 'delete' => array( 'ApiQueryInfo', 'getDeleteToken' ),
00075 'protect' => array( 'ApiQueryInfo', 'getProtectToken' ),
00076 'move' => array( 'ApiQueryInfo', 'getMoveToken' ),
00077 'block' => array( 'ApiQueryInfo', 'getBlockToken' ),
00078 'unblock' => array( 'ApiQueryInfo', 'getUnblockToken' ),
00079 'email' => array( 'ApiQueryInfo', 'getEmailToken' ),
00080 'import' => array( 'ApiQueryInfo', 'getImportToken' ),
00081 );
00082 wfRunHooks( 'APIQueryInfoTokens', array( &$this->tokenFunctions ) );
00083 return $this->tokenFunctions;
00084 }
00085
00086 public static function getEditToken( $pageid, $title )
00087 {
00088
00089
00090
00091 global $wgUser;
00092 if ( !$wgUser->isAllowed( 'edit' ) )
00093 return false;
00094
00095
00096 static $cachedEditToken = null;
00097 if ( !is_null( $cachedEditToken ) )
00098 return $cachedEditToken;
00099
00100 $cachedEditToken = $wgUser->editToken();
00101 return $cachedEditToken;
00102 }
00103
00104 public static function getDeleteToken( $pageid, $title )
00105 {
00106 global $wgUser;
00107 if ( !$wgUser->isAllowed( 'delete' ) )
00108 return false;
00109
00110 static $cachedDeleteToken = null;
00111 if ( !is_null( $cachedDeleteToken ) )
00112 return $cachedDeleteToken;
00113
00114 $cachedDeleteToken = $wgUser->editToken();
00115 return $cachedDeleteToken;
00116 }
00117
00118 public static function getProtectToken( $pageid, $title )
00119 {
00120 global $wgUser;
00121 if ( !$wgUser->isAllowed( 'protect' ) )
00122 return false;
00123
00124 static $cachedProtectToken = null;
00125 if ( !is_null( $cachedProtectToken ) )
00126 return $cachedProtectToken;
00127
00128 $cachedProtectToken = $wgUser->editToken();
00129 return $cachedProtectToken;
00130 }
00131
00132 public static function getMoveToken( $pageid, $title )
00133 {
00134 global $wgUser;
00135 if ( !$wgUser->isAllowed( 'move' ) )
00136 return false;
00137
00138 static $cachedMoveToken = null;
00139 if ( !is_null( $cachedMoveToken ) )
00140 return $cachedMoveToken;
00141
00142 $cachedMoveToken = $wgUser->editToken();
00143 return $cachedMoveToken;
00144 }
00145
00146 public static function getBlockToken( $pageid, $title )
00147 {
00148 global $wgUser;
00149 if ( !$wgUser->isAllowed( 'block' ) )
00150 return false;
00151
00152 static $cachedBlockToken = null;
00153 if ( !is_null( $cachedBlockToken ) )
00154 return $cachedBlockToken;
00155
00156 $cachedBlockToken = $wgUser->editToken();
00157 return $cachedBlockToken;
00158 }
00159
00160 public static function getUnblockToken( $pageid, $title )
00161 {
00162
00163 return self::getBlockToken( $pageid, $title );
00164 }
00165
00166 public static function getEmailToken( $pageid, $title )
00167 {
00168 global $wgUser;
00169 if ( !$wgUser->canSendEmail() || $wgUser->isBlockedFromEmailUser() )
00170 return false;
00171
00172 static $cachedEmailToken = null;
00173 if ( !is_null( $cachedEmailToken ) )
00174 return $cachedEmailToken;
00175
00176 $cachedEmailToken = $wgUser->editToken();
00177 return $cachedEmailToken;
00178 }
00179
00180 public static function getImportToken( $pageid, $title )
00181 {
00182 global $wgUser;
00183 if ( !$wgUser->isAllowed( 'import' ) )
00184 return false;
00185
00186 static $cachedImportToken = null;
00187 if ( !is_null( $cachedImportToken ) )
00188 return $cachedImportToken;
00189
00190 $cachedImportToken = $wgUser->editToken();
00191 return $cachedImportToken;
00192 }
00193
00194 public function execute() {
00195 $this->params = $this->extractRequestParams();
00196 if ( !is_null( $this->params['prop'] ) ) {
00197 $prop = array_flip( $this->params['prop'] );
00198 $this->fld_protection = isset( $prop['protection'] );
00199 $this->fld_watched = isset( $prop['watched'] );
00200 $this->fld_talkid = isset( $prop['talkid'] );
00201 $this->fld_subjectid = isset( $prop['subjectid'] );
00202 $this->fld_url = isset( $prop['url'] );
00203 $this->fld_readable = isset( $prop['readable'] );
00204 $this->fld_preload = isset ( $prop['preload'] );
00205 }
00206
00207 $pageSet = $this->getPageSet();
00208 $this->titles = $pageSet->getGoodTitles();
00209 $this->missing = $pageSet->getMissingTitles();
00210 $this->everything = $this->titles + $this->missing;
00211 $result = $this->getResult();
00212
00213 uasort( $this->everything, array( 'Title', 'compare' ) );
00214 if ( !is_null( $this->params['continue'] ) )
00215 {
00216
00217
00218 $cont = explode( '|', $this->params['continue'] );
00219 if ( count( $cont ) != 2 )
00220 $this->dieUsage( "Invalid continue param. You should pass the original " .
00221 "value returned by the previous query", "_badcontinue" );
00222 $conttitle = Title::makeTitleSafe( $cont[0], $cont[1] );
00223 foreach ( $this->everything as $pageid => $title )
00224 {
00225 if ( Title::compare( $title, $conttitle ) >= 0 )
00226 break;
00227 unset( $this->titles[$pageid] );
00228 unset( $this->missing[$pageid] );
00229 unset( $this->everything[$pageid] );
00230 }
00231 }
00232
00233 $this->pageRestrictions = $pageSet->getCustomField( 'page_restrictions' );
00234 $this->pageIsRedir = $pageSet->getCustomField( 'page_is_redirect' );
00235 $this->pageIsNew = $pageSet->getCustomField( 'page_is_new' );
00236 $this->pageCounter = $pageSet->getCustomField( 'page_counter' );
00237 $this->pageTouched = $pageSet->getCustomField( 'page_touched' );
00238 $this->pageLatest = $pageSet->getCustomField( 'page_latest' );
00239 $this->pageLength = $pageSet->getCustomField( 'page_len' );
00240
00241 $db = $this->getDB();
00242
00243 if ( $this->fld_protection )
00244 $this->getProtectionInfo();
00245
00246 if ( $this->fld_watched )
00247 $this->getWatchedInfo();
00248
00249
00250 if ( $this->fld_talkid || $this->fld_subjectid )
00251 $this->getTSIDs();
00252
00253 foreach ( $this->everything as $pageid => $title ) {
00254 $pageInfo = $this->extractPageInfo( $pageid, $title );
00255 $fit = $result->addValue( array (
00256 'query',
00257 'pages'
00258 ), $pageid, $pageInfo );
00259 if ( !$fit )
00260 {
00261 $this->setContinueEnumParameter( 'continue',
00262 $title->getNamespace() . '|' .
00263 $title->getText() );
00264 break;
00265 }
00266 }
00267 }
00268
00275 private function extractPageInfo( $pageid, $title )
00276 {
00277 $pageInfo = array();
00278 if ( $title->exists() )
00279 {
00280 $pageInfo['touched'] = wfTimestamp( TS_ISO_8601, $this->pageTouched[$pageid] );
00281 $pageInfo['lastrevid'] = intval( $this->pageLatest[$pageid] );
00282 $pageInfo['counter'] = intval( $this->pageCounter[$pageid] );
00283 $pageInfo['length'] = intval( $this->pageLength[$pageid] );
00284 if ( $this->pageIsRedir[$pageid] )
00285 $pageInfo['redirect'] = '';
00286 if ( $this->pageIsNew[$pageid] )
00287 $pageInfo['new'] = '';
00288 }
00289
00290 if ( !is_null( $this->params['token'] ) ) {
00291 $tokenFunctions = $this->getTokenFunctions();
00292 $pageInfo['starttimestamp'] = wfTimestamp( TS_ISO_8601, time() );
00293 foreach ( $this->params['token'] as $t )
00294 {
00295 $val = call_user_func( $tokenFunctions[$t], $pageid, $title );
00296 if ( $val === false )
00297 $this->setWarning( "Action '$t' is not allowed for the current user" );
00298 else
00299 $pageInfo[$t . 'token'] = $val;
00300 }
00301 }
00302
00303 if ( $this->fld_protection ) {
00304 $pageInfo['protection'] = array();
00305 if ( isset( $this->protections[$title->getNamespace()][$title->getDBkey()] ) )
00306 $pageInfo['protection'] =
00307 $this->protections[$title->getNamespace()][$title->getDBkey()];
00308 $this->getResult()->setIndexedTagName( $pageInfo['protection'], 'pr' );
00309 }
00310
00311 if ( $this->fld_watched && isset( $this->watched[$title->getNamespace()][$title->getDBkey()] ) )
00312 $pageInfo['watched'] = '';
00313
00314 if ( $this->fld_talkid && isset( $this->talkids[$title->getNamespace()][$title->getDBkey()] ) )
00315 $pageInfo['talkid'] = $this->talkids[$title->getNamespace()][$title->getDBkey()];
00316
00317 if ( $this->fld_subjectid && isset( $this->subjectids[$title->getNamespace()][$title->getDBkey()] ) )
00318 $pageInfo['subjectid'] = $this->subjectids[$title->getNamespace()][$title->getDBkey()];
00319
00320 if ( $this->fld_url ) {
00321 $pageInfo['fullurl'] = $title->getFullURL();
00322 $pageInfo['editurl'] = $title->getFullURL( 'action=edit' );
00323 }
00324 if ( $this->fld_readable && $title->userCanRead() )
00325 $pageInfo['readable'] = '';
00326
00327 if ( $this->fld_preload ) {
00328 if ( $title->exists() )
00329 $pageInfo['preload'] = '';
00330 else {
00331 wfRunHooks( 'EditFormPreloadText', array( &$text, &$title ) );
00332
00333 $pageInfo['preload'] = $text;
00334 }
00335 }
00336 return $pageInfo;
00337 }
00338
00342 private function getProtectionInfo()
00343 {
00344 $this->protections = array();
00345 $db = $this->getDB();
00346
00347
00348 if ( count( $this->titles ) )
00349 {
00350 $this->resetQueryParams();
00351 $this->addTables( array( 'page_restrictions', 'page' ) );
00352 $this->addWhere( 'page_id=pr_page' );
00353 $this->addFields( array( 'pr_page', 'pr_type', 'pr_level',
00354 'pr_expiry', 'pr_cascade', 'page_namespace',
00355 'page_title' ) );
00356 $this->addWhereFld( 'pr_page', array_keys( $this->titles ) );
00357
00358 $res = $this->select( __METHOD__ );
00359 while ( $row = $db->fetchObject( $res ) ) {
00360 $a = array(
00361 'type' => $row->pr_type,
00362 'level' => $row->pr_level,
00363 'expiry' => Block::decodeExpiry( $row->pr_expiry, TS_ISO_8601 )
00364 );
00365 if ( $row->pr_cascade )
00366 $a['cascade'] = '';
00367 $this->protections[$row->page_namespace][$row->page_title][] = $a;
00368
00369
00370 if ( $this->pageRestrictions[$row->pr_page] ) {
00371 $restrictions = explode( ':', trim( $this->pageRestrictions[$row->pr_page] ) );
00372 foreach ( $restrictions as $restrict ) {
00373 $temp = explode( '=', trim( $restrict ) );
00374 if ( count( $temp ) == 1 ) {
00375
00376 $restriction = trim( $temp[0] );
00377
00378 if ( $restriction == '' )
00379 continue;
00380 $this->protections[$row->page_namespace][$row->page_title][] = array(
00381 'type' => 'edit',
00382 'level' => $restriction,
00383 'expiry' => 'infinity',
00384 );
00385 $this->protections[$row->page_namespace][$row->page_title][] = array(
00386 'type' => 'move',
00387 'level' => $restriction,
00388 'expiry' => 'infinity',
00389 );
00390 } else {
00391 $restriction = trim( $temp[1] );
00392 if ( $restriction == '' )
00393 continue;
00394 $this->protections[$row->page_namespace][$row->page_title][] = array(
00395 'type' => $temp[0],
00396 'level' => $restriction,
00397 'expiry' => 'infinity',
00398 );
00399 }
00400 }
00401 }
00402 }
00403 $db->freeResult( $res );
00404 }
00405
00406
00407 if ( count( $this->missing ) )
00408 {
00409 $this->resetQueryParams();
00410 $lb = new LinkBatch( $this->missing );
00411 $this->addTables( 'protected_titles' );
00412 $this->addFields( array( 'pt_title', 'pt_namespace', 'pt_create_perm', 'pt_expiry' ) );
00413 $this->addWhere( $lb->constructSet( 'pt', $db ) );
00414 $res = $this->select( __METHOD__ );
00415 while ( $row = $db->fetchObject( $res ) ) {
00416 $this->protections[$row->pt_namespace][$row->pt_title][] = array(
00417 'type' => 'create',
00418 'level' => $row->pt_create_perm,
00419 'expiry' => Block::decodeExpiry( $row->pt_expiry, TS_ISO_8601 )
00420 );
00421 }
00422 $db->freeResult( $res );
00423 }
00424
00425
00426 $images = $others = array();
00427 foreach ( $this->everything as $title )
00428 if ( $title->getNamespace() == NS_FILE )
00429 $images[] = $title->getDBkey();
00430 else
00431 $others[] = $title;
00432
00433 if ( count( $others ) ) {
00434
00435 $lb = new LinkBatch( $others );
00436 $this->resetQueryParams();
00437 $this->addTables( array( 'page_restrictions', 'page', 'templatelinks' ) );
00438 $this->addFields( array( 'pr_type', 'pr_level', 'pr_expiry',
00439 'page_title', 'page_namespace',
00440 'tl_title', 'tl_namespace' ) );
00441 $this->addWhere( $lb->constructSet( 'tl', $db ) );
00442 $this->addWhere( 'pr_page = page_id' );
00443 $this->addWhere( 'pr_page = tl_from' );
00444 $this->addWhereFld( 'pr_cascade', 1 );
00445
00446 $res = $this->select( __METHOD__ );
00447 while ( $row = $db->fetchObject( $res ) ) {
00448 $source = Title::makeTitle( $row->page_namespace, $row->page_title );
00449 $this->protections[$row->tl_namespace][$row->tl_title][] = array(
00450 'type' => $row->pr_type,
00451 'level' => $row->pr_level,
00452 'expiry' => Block::decodeExpiry( $row->pr_expiry, TS_ISO_8601 ),
00453 'source' => $source->getPrefixedText()
00454 );
00455 }
00456 $db->freeResult( $res );
00457 }
00458
00459 if ( count( $images ) ) {
00460
00461 $this->resetQueryParams();
00462 $this->addTables( array( 'page_restrictions', 'page', 'imagelinks' ) );
00463 $this->addFields( array( 'pr_type', 'pr_level', 'pr_expiry',
00464 'page_title', 'page_namespace', 'il_to' ) );
00465 $this->addWhere( 'pr_page = page_id' );
00466 $this->addWhere( 'pr_page = il_from' );
00467 $this->addWhereFld( 'pr_cascade', 1 );
00468 $this->addWhereFld( 'il_to', $images );
00469
00470 $res = $this->select( __METHOD__ );
00471 while ( $row = $db->fetchObject( $res ) ) {
00472 $source = Title::makeTitle( $row->page_namespace, $row->page_title );
00473 $this->protections[NS_FILE][$row->il_to][] = array(
00474 'type' => $row->pr_type,
00475 'level' => $row->pr_level,
00476 'expiry' => Block::decodeExpiry( $row->pr_expiry, TS_ISO_8601 ),
00477 'source' => $source->getPrefixedText()
00478 );
00479 }
00480 $db->freeResult( $res );
00481 }
00482 }
00483
00488 private function getTSIDs()
00489 {
00490 $getTitles = $this->talkids = $this->subjectids = array();
00491 $db = $this->getDB();
00492 foreach ( $this->everything as $t )
00493 {
00494 if ( MWNamespace::isTalk( $t->getNamespace() ) )
00495 {
00496 if ( $this->fld_subjectid )
00497 $getTitles[] = $t->getSubjectPage();
00498 }
00499 else if ( $this->fld_talkid )
00500 $getTitles[] = $t->getTalkPage();
00501 }
00502 if ( !count( $getTitles ) )
00503 return;
00504
00505
00506
00507 $lb = new LinkBatch( $getTitles );
00508 $this->resetQueryParams();
00509 $this->addTables( 'page' );
00510 $this->addFields( array( 'page_title', 'page_namespace', 'page_id' ) );
00511 $this->addWhere( $lb->constructSet( 'page', $db ) );
00512 $res = $this->select( __METHOD__ );
00513 while ( $row = $db->fetchObject( $res ) )
00514 {
00515 if ( MWNamespace::isTalk( $row->page_namespace ) )
00516 $this->talkids[MWNamespace::getSubject( $row->page_namespace )][$row->page_title] =
00517 intval( $row->page_id );
00518 else
00519 $this->subjectids[MWNamespace::getTalk( $row->page_namespace )][$row->page_title] =
00520 intval( $row->page_id );
00521 }
00522 }
00523
00527 private function getWatchedInfo()
00528 {
00529 global $wgUser;
00530
00531 if ( $wgUser->isAnon() || count( $this->titles ) == 0 )
00532 return;
00533
00534 $this->watched = array();
00535 $db = $this->getDB();
00536
00537 $lb = new LinkBatch( $this->titles );
00538
00539 $this->resetQueryParams();
00540 $this->addTables( array( 'page', 'watchlist' ) );
00541 $this->addFields( array( 'page_title', 'page_namespace' ) );
00542 $this->addWhere( array(
00543 $lb->constructSet( 'page', $db ),
00544 'wl_namespace=page_namespace',
00545 'wl_title=page_title',
00546 'wl_user' => $wgUser->getID()
00547 ) );
00548
00549 $res = $this->select( __METHOD__ );
00550
00551 while ( $row = $db->fetchObject( $res ) ) {
00552 $this->watched[$row->page_namespace][$row->page_title] = true;
00553 }
00554 }
00555
00556 public function getCacheMode( $params ) {
00557 $publicProps = array(
00558 'protection',
00559 'talkid',
00560 'subjectid',
00561 'url',
00562 'preload',
00563 );
00564 if ( !is_null( $params['prop'] ) ) {
00565 foreach ( $params['prop'] as $prop ) {
00566 if ( !in_array( $prop, $publicProps ) ) {
00567 return 'private';
00568 }
00569 }
00570 }
00571 if ( !is_null( $params['token'] ) ) {
00572 return 'private';
00573 }
00574 return 'public';
00575 }
00576
00577 public function getAllowedParams() {
00578 return array (
00579 'prop' => array (
00580 ApiBase :: PARAM_DFLT => null,
00581 ApiBase :: PARAM_ISMULTI => true,
00582 ApiBase :: PARAM_TYPE => array (
00583 'protection',
00584 'talkid',
00585 'watched', # private
00586 'subjectid',
00587 'url',
00588 'readable', # private
00589 'preload'
00590
00591
00592 ) ),
00593 'token' => array (
00594 ApiBase :: PARAM_DFLT => null,
00595 ApiBase :: PARAM_ISMULTI => true,
00596 ApiBase :: PARAM_TYPE => array_keys( $this->getTokenFunctions() )
00597 ),
00598 'continue' => null,
00599 );
00600 }
00601
00602 public function getParamDescription() {
00603 return array (
00604 'prop' => array (
00605 'Which additional properties to get:',
00606 ' protection - List the protection level of each page',
00607 ' talkid - The page ID of the talk page for each non-talk page',
00608 ' watched - List the watched status of each page',
00609 ' subjectid - The page ID of the parent page for each talk page',
00610 ' url - Gives a full URL to the page, and also an edit URL',
00611 ' readable - Whether the user can read this page',
00612 ' preload - Gives the text returned by EditFormPreloadText'
00613 ),
00614 'token' => 'Request a token to perform a data-modifying action on a page',
00615 'continue' => 'When more results are available, use this to continue',
00616 );
00617 }
00618
00619 public function getDescription() {
00620 return 'Get basic page information such as namespace, title, last touched date, ...';
00621 }
00622
00623 public function getPossibleErrors() {
00624 return array_merge( parent::getPossibleErrors(), array(
00625 array( 'code' => '_badcontinue', 'info' => 'Invalid continue param. You should pass the original value returned by the previous query' ),
00626 ) );
00627 }
00628
00629 protected function getExamples() {
00630 return array (
00631 'api.php?action=query&prop=info&titles=Main%20Page',
00632 'api.php?action=query&prop=info&inprop=protection&titles=Main%20Page'
00633 );
00634 }
00635
00636 public function getVersion() {
00637 return __CLASS__ . ': $Id: ApiQueryInfo.php 69932 2010-07-26 08:03:21Z tstarling $';
00638 }
00639 }