MediaWiki
REL1_22
|
00001 <?php 00032 class ApiQueryInfo extends ApiQueryBase { 00033 00034 private $fld_protection = false, $fld_talkid = false, 00035 $fld_subjectid = false, $fld_url = false, 00036 $fld_readable = false, $fld_watched = false, $fld_watchers = false, 00037 $fld_notificationtimestamp = false, 00038 $fld_preload = false, $fld_displaytitle = false; 00039 00040 private $params, $titles, $missing, $everything, $pageCounter; 00041 00042 private $pageRestrictions, $pageIsRedir, $pageIsNew, $pageTouched, 00043 $pageLatest, $pageLength; 00044 00045 private $protections, $watched, $watchers, $notificationtimestamps, $talkids, $subjectids, $displaytitles; 00046 private $showZeroWatchers = false; 00047 00048 private $tokenFunctions; 00049 00050 public function __construct( $query, $moduleName ) { 00051 parent::__construct( $query, $moduleName, 'in' ); 00052 } 00053 00058 public function requestExtraData( $pageSet ) { 00059 global $wgDisableCounters, $wgContentHandlerUseDB; 00060 00061 $pageSet->requestField( 'page_restrictions' ); 00062 // when resolving redirects, no page will have this field 00063 if ( !$pageSet->isResolvingRedirects() ) { 00064 $pageSet->requestField( 'page_is_redirect' ); 00065 } 00066 $pageSet->requestField( 'page_is_new' ); 00067 if ( !$wgDisableCounters ) { 00068 $pageSet->requestField( 'page_counter' ); 00069 } 00070 $pageSet->requestField( 'page_touched' ); 00071 $pageSet->requestField( 'page_latest' ); 00072 $pageSet->requestField( 'page_len' ); 00073 if ( $wgContentHandlerUseDB ) { 00074 $pageSet->requestField( 'page_content_model' ); 00075 } 00076 } 00077 00084 protected function getTokenFunctions() { 00085 // Don't call the hooks twice 00086 if ( isset( $this->tokenFunctions ) ) { 00087 return $this->tokenFunctions; 00088 } 00089 00090 // If we're in JSON callback mode, no tokens can be obtained 00091 if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { 00092 return array(); 00093 } 00094 00095 $this->tokenFunctions = array( 00096 'edit' => array( 'ApiQueryInfo', 'getEditToken' ), 00097 'delete' => array( 'ApiQueryInfo', 'getDeleteToken' ), 00098 'protect' => array( 'ApiQueryInfo', 'getProtectToken' ), 00099 'move' => array( 'ApiQueryInfo', 'getMoveToken' ), 00100 'block' => array( 'ApiQueryInfo', 'getBlockToken' ), 00101 'unblock' => array( 'ApiQueryInfo', 'getUnblockToken' ), 00102 'email' => array( 'ApiQueryInfo', 'getEmailToken' ), 00103 'import' => array( 'ApiQueryInfo', 'getImportToken' ), 00104 'watch' => array( 'ApiQueryInfo', 'getWatchToken' ), 00105 ); 00106 wfRunHooks( 'APIQueryInfoTokens', array( &$this->tokenFunctions ) ); 00107 return $this->tokenFunctions; 00108 } 00109 00110 static $cachedTokens = array(); 00111 00112 public static function resetTokenCache() { 00113 ApiQueryInfo::$cachedTokens = array(); 00114 } 00115 00116 public static function getEditToken( $pageid, $title ) { 00117 // We could check for $title->userCan('edit') here, 00118 // but that's too expensive for this purpose 00119 // and would break caching 00120 global $wgUser; 00121 if ( !$wgUser->isAllowed( 'edit' ) ) { 00122 return false; 00123 } 00124 00125 // The token is always the same, let's exploit that 00126 if ( !isset( ApiQueryInfo::$cachedTokens['edit'] ) ) { 00127 ApiQueryInfo::$cachedTokens['edit'] = $wgUser->getEditToken(); 00128 } 00129 00130 return ApiQueryInfo::$cachedTokens['edit']; 00131 } 00132 00133 public static function getDeleteToken( $pageid, $title ) { 00134 global $wgUser; 00135 if ( !$wgUser->isAllowed( 'delete' ) ) { 00136 return false; 00137 } 00138 00139 // The token is always the same, let's exploit that 00140 if ( !isset( ApiQueryInfo::$cachedTokens['delete'] ) ) { 00141 ApiQueryInfo::$cachedTokens['delete'] = $wgUser->getEditToken(); 00142 } 00143 00144 return ApiQueryInfo::$cachedTokens['delete']; 00145 } 00146 00147 public static function getProtectToken( $pageid, $title ) { 00148 global $wgUser; 00149 if ( !$wgUser->isAllowed( 'protect' ) ) { 00150 return false; 00151 } 00152 00153 // The token is always the same, let's exploit that 00154 if ( !isset( ApiQueryInfo::$cachedTokens['protect'] ) ) { 00155 ApiQueryInfo::$cachedTokens['protect'] = $wgUser->getEditToken(); 00156 } 00157 00158 return ApiQueryInfo::$cachedTokens['protect']; 00159 } 00160 00161 public static function getMoveToken( $pageid, $title ) { 00162 global $wgUser; 00163 if ( !$wgUser->isAllowed( 'move' ) ) { 00164 return false; 00165 } 00166 00167 // The token is always the same, let's exploit that 00168 if ( !isset( ApiQueryInfo::$cachedTokens['move'] ) ) { 00169 ApiQueryInfo::$cachedTokens['move'] = $wgUser->getEditToken(); 00170 } 00171 00172 return ApiQueryInfo::$cachedTokens['move']; 00173 } 00174 00175 public static function getBlockToken( $pageid, $title ) { 00176 global $wgUser; 00177 if ( !$wgUser->isAllowed( 'block' ) ) { 00178 return false; 00179 } 00180 00181 // The token is always the same, let's exploit that 00182 if ( !isset( ApiQueryInfo::$cachedTokens['block'] ) ) { 00183 ApiQueryInfo::$cachedTokens['block'] = $wgUser->getEditToken(); 00184 } 00185 00186 return ApiQueryInfo::$cachedTokens['block']; 00187 } 00188 00189 public static function getUnblockToken( $pageid, $title ) { 00190 // Currently, this is exactly the same as the block token 00191 return self::getBlockToken( $pageid, $title ); 00192 } 00193 00194 public static function getEmailToken( $pageid, $title ) { 00195 global $wgUser; 00196 if ( !$wgUser->canSendEmail() || $wgUser->isBlockedFromEmailUser() ) { 00197 return false; 00198 } 00199 00200 // The token is always the same, let's exploit that 00201 if ( !isset( ApiQueryInfo::$cachedTokens['email'] ) ) { 00202 ApiQueryInfo::$cachedTokens['email'] = $wgUser->getEditToken(); 00203 } 00204 00205 return ApiQueryInfo::$cachedTokens['email']; 00206 } 00207 00208 public static function getImportToken( $pageid, $title ) { 00209 global $wgUser; 00210 if ( !$wgUser->isAllowedAny( 'import', 'importupload' ) ) { 00211 return false; 00212 } 00213 00214 // The token is always the same, let's exploit that 00215 if ( !isset( ApiQueryInfo::$cachedTokens['import'] ) ) { 00216 ApiQueryInfo::$cachedTokens['import'] = $wgUser->getEditToken(); 00217 } 00218 00219 return ApiQueryInfo::$cachedTokens['import']; 00220 } 00221 00222 public static function getWatchToken( $pageid, $title ) { 00223 global $wgUser; 00224 if ( !$wgUser->isLoggedIn() ) { 00225 return false; 00226 } 00227 00228 // The token is always the same, let's exploit that 00229 if ( !isset( ApiQueryInfo::$cachedTokens['watch'] ) ) { 00230 ApiQueryInfo::$cachedTokens['watch'] = $wgUser->getEditToken( 'watch' ); 00231 } 00232 00233 return ApiQueryInfo::$cachedTokens['watch']; 00234 } 00235 00236 public static function getOptionsToken( $pageid, $title ) { 00237 global $wgUser; 00238 if ( !$wgUser->isLoggedIn() ) { 00239 return false; 00240 } 00241 00242 // The token is always the same, let's exploit that 00243 if ( !isset( ApiQueryInfo::$cachedTokens['options'] ) ) { 00244 ApiQueryInfo::$cachedTokens['options'] = $wgUser->getEditToken(); 00245 } 00246 00247 return ApiQueryInfo::$cachedTokens['options']; 00248 } 00249 00250 public function execute() { 00251 $this->params = $this->extractRequestParams(); 00252 if ( !is_null( $this->params['prop'] ) ) { 00253 $prop = array_flip( $this->params['prop'] ); 00254 $this->fld_protection = isset( $prop['protection'] ); 00255 $this->fld_watched = isset( $prop['watched'] ); 00256 $this->fld_watchers = isset( $prop['watchers'] ); 00257 $this->fld_notificationtimestamp = isset( $prop['notificationtimestamp'] ); 00258 $this->fld_talkid = isset( $prop['talkid'] ); 00259 $this->fld_subjectid = isset( $prop['subjectid'] ); 00260 $this->fld_url = isset( $prop['url'] ); 00261 $this->fld_readable = isset( $prop['readable'] ); 00262 $this->fld_preload = isset( $prop['preload'] ); 00263 $this->fld_displaytitle = isset( $prop['displaytitle'] ); 00264 } 00265 00266 $pageSet = $this->getPageSet(); 00267 $this->titles = $pageSet->getGoodTitles(); 00268 $this->missing = $pageSet->getMissingTitles(); 00269 $this->everything = $this->titles + $this->missing; 00270 $result = $this->getResult(); 00271 00272 uasort( $this->everything, array( 'Title', 'compare' ) ); 00273 if ( !is_null( $this->params['continue'] ) ) { 00274 // Throw away any titles we're gonna skip so they don't 00275 // clutter queries 00276 $cont = explode( '|', $this->params['continue'] ); 00277 $this->dieContinueUsageIf( count( $cont ) != 2 ); 00278 $conttitle = Title::makeTitleSafe( $cont[0], $cont[1] ); 00279 foreach ( $this->everything as $pageid => $title ) { 00280 if ( Title::compare( $title, $conttitle ) >= 0 ) { 00281 break; 00282 } 00283 unset( $this->titles[$pageid] ); 00284 unset( $this->missing[$pageid] ); 00285 unset( $this->everything[$pageid] ); 00286 } 00287 } 00288 00289 $this->pageRestrictions = $pageSet->getCustomField( 'page_restrictions' ); 00290 // when resolving redirects, no page will have this field 00291 $this->pageIsRedir = !$pageSet->isResolvingRedirects() 00292 ? $pageSet->getCustomField( 'page_is_redirect' ) 00293 : array(); 00294 $this->pageIsNew = $pageSet->getCustomField( 'page_is_new' ); 00295 00296 global $wgDisableCounters; 00297 00298 if ( !$wgDisableCounters ) { 00299 $this->pageCounter = $pageSet->getCustomField( 'page_counter' ); 00300 } 00301 $this->pageTouched = $pageSet->getCustomField( 'page_touched' ); 00302 $this->pageLatest = $pageSet->getCustomField( 'page_latest' ); 00303 $this->pageLength = $pageSet->getCustomField( 'page_len' ); 00304 00305 // Get protection info if requested 00306 if ( $this->fld_protection ) { 00307 $this->getProtectionInfo(); 00308 } 00309 00310 if ( $this->fld_watched || $this->fld_notificationtimestamp ) { 00311 $this->getWatchedInfo(); 00312 } 00313 00314 if ( $this->fld_watchers ) { 00315 $this->getWatcherInfo(); 00316 } 00317 00318 // Run the talkid/subjectid query if requested 00319 if ( $this->fld_talkid || $this->fld_subjectid ) { 00320 $this->getTSIDs(); 00321 } 00322 00323 if ( $this->fld_displaytitle ) { 00324 $this->getDisplayTitle(); 00325 } 00326 00328 foreach ( $this->everything as $pageid => $title ) { 00329 $pageInfo = $this->extractPageInfo( $pageid, $title ); 00330 $fit = $result->addValue( array( 00331 'query', 00332 'pages' 00333 ), $pageid, $pageInfo ); 00334 if ( !$fit ) { 00335 $this->setContinueEnumParameter( 'continue', 00336 $title->getNamespace() . '|' . 00337 $title->getText() ); 00338 break; 00339 } 00340 } 00341 } 00342 00349 private function extractPageInfo( $pageid, $title ) { 00350 $pageInfo = array(); 00351 $titleExists = $pageid > 0; //$title->exists() needs pageid, which is not set for all title objects 00352 $ns = $title->getNamespace(); 00353 $dbkey = $title->getDBkey(); 00354 00355 $pageInfo['contentmodel'] = $title->getContentModel(); 00356 $pageInfo['pagelanguage'] = $title->getPageLanguage()->getCode(); 00357 00358 if ( $titleExists ) { 00359 global $wgDisableCounters; 00360 00361 $pageInfo['touched'] = wfTimestamp( TS_ISO_8601, $this->pageTouched[$pageid] ); 00362 $pageInfo['lastrevid'] = intval( $this->pageLatest[$pageid] ); 00363 $pageInfo['counter'] = $wgDisableCounters 00364 ? '' 00365 : intval( $this->pageCounter[$pageid] ); 00366 $pageInfo['length'] = intval( $this->pageLength[$pageid] ); 00367 00368 if ( isset( $this->pageIsRedir[$pageid] ) && $this->pageIsRedir[$pageid] ) { 00369 $pageInfo['redirect'] = ''; 00370 } 00371 if ( $this->pageIsNew[$pageid] ) { 00372 $pageInfo['new'] = ''; 00373 } 00374 } 00375 00376 if ( !is_null( $this->params['token'] ) ) { 00377 $tokenFunctions = $this->getTokenFunctions(); 00378 $pageInfo['starttimestamp'] = wfTimestamp( TS_ISO_8601, time() ); 00379 foreach ( $this->params['token'] as $t ) { 00380 $val = call_user_func( $tokenFunctions[$t], $pageid, $title ); 00381 if ( $val === false ) { 00382 $this->setWarning( "Action '$t' is not allowed for the current user" ); 00383 } else { 00384 $pageInfo[$t . 'token'] = $val; 00385 } 00386 } 00387 } 00388 00389 if ( $this->fld_protection ) { 00390 $pageInfo['protection'] = array(); 00391 if ( isset( $this->protections[$ns][$dbkey] ) ) { 00392 $pageInfo['protection'] = 00393 $this->protections[$ns][$dbkey]; 00394 } 00395 $this->getResult()->setIndexedTagName( $pageInfo['protection'], 'pr' ); 00396 } 00397 00398 if ( $this->fld_watched && isset( $this->watched[$ns][$dbkey] ) ) { 00399 $pageInfo['watched'] = ''; 00400 } 00401 00402 if ( $this->fld_watchers ) { 00403 if ( isset( $this->watchers[$ns][$dbkey] ) ) { 00404 $pageInfo['watchers'] = $this->watchers[$ns][$dbkey]; 00405 } elseif ( $this->showZeroWatchers ) { 00406 $pageInfo['watchers'] = 0; 00407 } 00408 } 00409 00410 if ( $this->fld_notificationtimestamp ) { 00411 $pageInfo['notificationtimestamp'] = ''; 00412 if ( isset( $this->notificationtimestamps[$ns][$dbkey] ) ) { 00413 $pageInfo['notificationtimestamp'] = wfTimestamp( TS_ISO_8601, $this->notificationtimestamps[$ns][$dbkey] ); 00414 } 00415 } 00416 00417 if ( $this->fld_talkid && isset( $this->talkids[$ns][$dbkey] ) ) { 00418 $pageInfo['talkid'] = $this->talkids[$ns][$dbkey]; 00419 } 00420 00421 if ( $this->fld_subjectid && isset( $this->subjectids[$ns][$dbkey] ) ) { 00422 $pageInfo['subjectid'] = $this->subjectids[$ns][$dbkey]; 00423 } 00424 00425 if ( $this->fld_url ) { 00426 $pageInfo['fullurl'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ); 00427 $pageInfo['editurl'] = wfExpandUrl( $title->getFullURL( 'action=edit' ), PROTO_CURRENT ); 00428 } 00429 if ( $this->fld_readable && $title->userCan( 'read', $this->getUser() ) ) { 00430 $pageInfo['readable'] = ''; 00431 } 00432 00433 if ( $this->fld_preload ) { 00434 if ( $titleExists ) { 00435 $pageInfo['preload'] = ''; 00436 } else { 00437 $text = null; 00438 wfRunHooks( 'EditFormPreloadText', array( &$text, &$title ) ); 00439 00440 $pageInfo['preload'] = $text; 00441 } 00442 } 00443 00444 if ( $this->fld_displaytitle ) { 00445 if ( isset( $this->displaytitles[$pageid] ) ) { 00446 $pageInfo['displaytitle'] = $this->displaytitles[$pageid]; 00447 } else { 00448 $pageInfo['displaytitle'] = $title->getPrefixedText(); 00449 } 00450 } 00451 00452 return $pageInfo; 00453 } 00454 00458 private function getProtectionInfo() { 00459 global $wgContLang; 00460 $this->protections = array(); 00461 $db = $this->getDB(); 00462 00463 // Get normal protections for existing titles 00464 if ( count( $this->titles ) ) { 00465 $this->resetQueryParams(); 00466 $this->addTables( 'page_restrictions' ); 00467 $this->addFields( array( 'pr_page', 'pr_type', 'pr_level', 00468 'pr_expiry', 'pr_cascade' ) ); 00469 $this->addWhereFld( 'pr_page', array_keys( $this->titles ) ); 00470 00471 $res = $this->select( __METHOD__ ); 00472 foreach ( $res as $row ) { 00474 $title = $this->titles[$row->pr_page]; 00475 $a = array( 00476 'type' => $row->pr_type, 00477 'level' => $row->pr_level, 00478 'expiry' => $wgContLang->formatExpiry( $row->pr_expiry, TS_ISO_8601 ) 00479 ); 00480 if ( $row->pr_cascade ) { 00481 $a['cascade'] = ''; 00482 } 00483 $this->protections[$title->getNamespace()][$title->getDBkey()][] = $a; 00484 } 00485 // Also check old restrictions 00486 foreach ( $this->titles as $pageId => $title ) { 00487 if ( $this->pageRestrictions[$pageId] ) { 00488 $namespace = $title->getNamespace(); 00489 $dbKey = $title->getDBkey(); 00490 $restrictions = explode( ':', trim( $this->pageRestrictions[$pageId] ) ); 00491 foreach ( $restrictions as $restrict ) { 00492 $temp = explode( '=', trim( $restrict ) ); 00493 if ( count( $temp ) == 1 ) { 00494 // old old format should be treated as edit/move restriction 00495 $restriction = trim( $temp[0] ); 00496 00497 if ( $restriction == '' ) { 00498 continue; 00499 } 00500 $this->protections[$namespace][$dbKey][] = array( 00501 'type' => 'edit', 00502 'level' => $restriction, 00503 'expiry' => 'infinity', 00504 ); 00505 $this->protections[$namespace][$dbKey][] = array( 00506 'type' => 'move', 00507 'level' => $restriction, 00508 'expiry' => 'infinity', 00509 ); 00510 } else { 00511 $restriction = trim( $temp[1] ); 00512 if ( $restriction == '' ) { 00513 continue; 00514 } 00515 $this->protections[$namespace][$dbKey][] = array( 00516 'type' => $temp[0], 00517 'level' => $restriction, 00518 'expiry' => 'infinity', 00519 ); 00520 } 00521 } 00522 } 00523 } 00524 } 00525 00526 // Get protections for missing titles 00527 if ( count( $this->missing ) ) { 00528 $this->resetQueryParams(); 00529 $lb = new LinkBatch( $this->missing ); 00530 $this->addTables( 'protected_titles' ); 00531 $this->addFields( array( 'pt_title', 'pt_namespace', 'pt_create_perm', 'pt_expiry' ) ); 00532 $this->addWhere( $lb->constructSet( 'pt', $db ) ); 00533 $res = $this->select( __METHOD__ ); 00534 foreach ( $res as $row ) { 00535 $this->protections[$row->pt_namespace][$row->pt_title][] = array( 00536 'type' => 'create', 00537 'level' => $row->pt_create_perm, 00538 'expiry' => $wgContLang->formatExpiry( $row->pt_expiry, TS_ISO_8601 ) 00539 ); 00540 } 00541 } 00542 00543 // Cascading protections 00544 $images = $others = array(); 00545 foreach ( $this->everything as $title ) { 00546 if ( $title->getNamespace() == NS_FILE ) { 00547 $images[] = $title->getDBkey(); 00548 } else { 00549 $others[] = $title; 00550 } 00551 } 00552 00553 if ( count( $others ) ) { 00554 // Non-images: check templatelinks 00555 $lb = new LinkBatch( $others ); 00556 $this->resetQueryParams(); 00557 $this->addTables( array( 'page_restrictions', 'page', 'templatelinks' ) ); 00558 $this->addFields( array( 'pr_type', 'pr_level', 'pr_expiry', 00559 'page_title', 'page_namespace', 00560 'tl_title', 'tl_namespace' ) ); 00561 $this->addWhere( $lb->constructSet( 'tl', $db ) ); 00562 $this->addWhere( 'pr_page = page_id' ); 00563 $this->addWhere( 'pr_page = tl_from' ); 00564 $this->addWhereFld( 'pr_cascade', 1 ); 00565 00566 $res = $this->select( __METHOD__ ); 00567 foreach ( $res as $row ) { 00568 $source = Title::makeTitle( $row->page_namespace, $row->page_title ); 00569 $this->protections[$row->tl_namespace][$row->tl_title][] = array( 00570 'type' => $row->pr_type, 00571 'level' => $row->pr_level, 00572 'expiry' => $wgContLang->formatExpiry( $row->pr_expiry, TS_ISO_8601 ), 00573 'source' => $source->getPrefixedText() 00574 ); 00575 } 00576 } 00577 00578 if ( count( $images ) ) { 00579 // Images: check imagelinks 00580 $this->resetQueryParams(); 00581 $this->addTables( array( 'page_restrictions', 'page', 'imagelinks' ) ); 00582 $this->addFields( array( 'pr_type', 'pr_level', 'pr_expiry', 00583 'page_title', 'page_namespace', 'il_to' ) ); 00584 $this->addWhere( 'pr_page = page_id' ); 00585 $this->addWhere( 'pr_page = il_from' ); 00586 $this->addWhereFld( 'pr_cascade', 1 ); 00587 $this->addWhereFld( 'il_to', $images ); 00588 00589 $res = $this->select( __METHOD__ ); 00590 foreach ( $res as $row ) { 00591 $source = Title::makeTitle( $row->page_namespace, $row->page_title ); 00592 $this->protections[NS_FILE][$row->il_to][] = array( 00593 'type' => $row->pr_type, 00594 'level' => $row->pr_level, 00595 'expiry' => $wgContLang->formatExpiry( $row->pr_expiry, TS_ISO_8601 ), 00596 'source' => $source->getPrefixedText() 00597 ); 00598 } 00599 } 00600 } 00601 00606 private function getTSIDs() { 00607 $getTitles = $this->talkids = $this->subjectids = array(); 00608 00610 foreach ( $this->everything as $t ) { 00611 if ( MWNamespace::isTalk( $t->getNamespace() ) ) { 00612 if ( $this->fld_subjectid ) { 00613 $getTitles[] = $t->getSubjectPage(); 00614 } 00615 } elseif ( $this->fld_talkid ) { 00616 $getTitles[] = $t->getTalkPage(); 00617 } 00618 } 00619 if ( !count( $getTitles ) ) { 00620 return; 00621 } 00622 00623 $db = $this->getDB(); 00624 00625 // Construct a custom WHERE clause that matches 00626 // all titles in $getTitles 00627 $lb = new LinkBatch( $getTitles ); 00628 $this->resetQueryParams(); 00629 $this->addTables( 'page' ); 00630 $this->addFields( array( 'page_title', 'page_namespace', 'page_id' ) ); 00631 $this->addWhere( $lb->constructSet( 'page', $db ) ); 00632 $res = $this->select( __METHOD__ ); 00633 foreach ( $res as $row ) { 00634 if ( MWNamespace::isTalk( $row->page_namespace ) ) { 00635 $this->talkids[MWNamespace::getSubject( $row->page_namespace )][$row->page_title] = 00636 intval( $row->page_id ); 00637 } else { 00638 $this->subjectids[MWNamespace::getTalk( $row->page_namespace )][$row->page_title] = 00639 intval( $row->page_id ); 00640 } 00641 } 00642 } 00643 00644 private function getDisplayTitle() { 00645 $this->displaytitles = array(); 00646 00647 $pageIds = array_keys( $this->titles ); 00648 00649 if ( !count( $pageIds ) ) { 00650 return; 00651 } 00652 00653 $this->resetQueryParams(); 00654 $this->addTables( 'page_props' ); 00655 $this->addFields( array( 'pp_page', 'pp_value' ) ); 00656 $this->addWhereFld( 'pp_page', $pageIds ); 00657 $this->addWhereFld( 'pp_propname', 'displaytitle' ); 00658 $res = $this->select( __METHOD__ ); 00659 00660 foreach ( $res as $row ) { 00661 $this->displaytitles[$row->pp_page] = $row->pp_value; 00662 } 00663 } 00664 00669 private function getWatchedInfo() { 00670 $user = $this->getUser(); 00671 00672 if ( $user->isAnon() || count( $this->everything ) == 0 00673 || !$user->isAllowed( 'viewmywatchlist' ) 00674 ) { 00675 return; 00676 } 00677 00678 $this->watched = array(); 00679 $this->notificationtimestamps = array(); 00680 $db = $this->getDB(); 00681 00682 $lb = new LinkBatch( $this->everything ); 00683 00684 $this->resetQueryParams(); 00685 $this->addTables( array( 'watchlist' ) ); 00686 $this->addFields( array( 'wl_title', 'wl_namespace' ) ); 00687 $this->addFieldsIf( 'wl_notificationtimestamp', $this->fld_notificationtimestamp ); 00688 $this->addWhere( array( 00689 $lb->constructSet( 'wl', $db ), 00690 'wl_user' => $user->getID() 00691 ) ); 00692 00693 $res = $this->select( __METHOD__ ); 00694 00695 foreach ( $res as $row ) { 00696 if ( $this->fld_watched ) { 00697 $this->watched[$row->wl_namespace][$row->wl_title] = true; 00698 } 00699 if ( $this->fld_notificationtimestamp ) { 00700 $this->notificationtimestamps[$row->wl_namespace][$row->wl_title] = $row->wl_notificationtimestamp; 00701 } 00702 } 00703 } 00704 00708 private function getWatcherInfo() { 00709 global $wgUnwatchedPageThreshold; 00710 00711 if ( count( $this->everything ) == 0 ) { 00712 return; 00713 } 00714 00715 $user = $this->getUser(); 00716 $canUnwatchedpages = $user->isAllowed( 'unwatchedpages' ); 00717 if ( !$canUnwatchedpages && !is_int( $wgUnwatchedPageThreshold ) ) { 00718 return; 00719 } 00720 00721 $this->watchers = array(); 00722 $this->showZeroWatchers = $canUnwatchedpages; 00723 $db = $this->getDB(); 00724 00725 $lb = new LinkBatch( $this->everything ); 00726 00727 $this->resetQueryParams(); 00728 $this->addTables( array( 'watchlist' ) ); 00729 $this->addFields( array( 'wl_title', 'wl_namespace', 'count' => 'COUNT(*)' ) ); 00730 $this->addWhere( array( 00731 $lb->constructSet( 'wl', $db ) 00732 ) ); 00733 $this->addOption( 'GROUP BY', array( 'wl_namespace', 'wl_title' ) ); 00734 if ( !$canUnwatchedpages ) { 00735 $this->addOption( 'HAVING', "COUNT(*) >= $wgUnwatchedPageThreshold" ); 00736 } 00737 00738 $res = $this->select( __METHOD__ ); 00739 00740 foreach ( $res as $row ) { 00741 $this->watchers[$row->wl_namespace][$row->wl_title] = (int)$row->count; 00742 } 00743 } 00744 00745 public function getCacheMode( $params ) { 00746 $publicProps = array( 00747 'protection', 00748 'talkid', 00749 'subjectid', 00750 'url', 00751 'preload', 00752 'displaytitle', 00753 ); 00754 if ( !is_null( $params['prop'] ) ) { 00755 foreach ( $params['prop'] as $prop ) { 00756 if ( !in_array( $prop, $publicProps ) ) { 00757 return 'private'; 00758 } 00759 } 00760 } 00761 if ( !is_null( $params['token'] ) ) { 00762 return 'private'; 00763 } 00764 return 'public'; 00765 } 00766 00767 public function getAllowedParams() { 00768 return array( 00769 'prop' => array( 00770 ApiBase::PARAM_DFLT => null, 00771 ApiBase::PARAM_ISMULTI => true, 00772 ApiBase::PARAM_TYPE => array( 00773 'protection', 00774 'talkid', 00775 'watched', # private 00776 'watchers', # private 00777 'notificationtimestamp', # private 00778 'subjectid', 00779 'url', 00780 'readable', # private 00781 'preload', 00782 'displaytitle', 00783 // If you add more properties here, please consider whether they 00784 // need to be added to getCacheMode() 00785 ) ), 00786 'token' => array( 00787 ApiBase::PARAM_DFLT => null, 00788 ApiBase::PARAM_ISMULTI => true, 00789 ApiBase::PARAM_TYPE => array_keys( $this->getTokenFunctions() ) 00790 ), 00791 'continue' => null, 00792 ); 00793 } 00794 00795 public function getParamDescription() { 00796 return array( 00797 'prop' => array( 00798 'Which additional properties to get:', 00799 ' protection - List the protection level of each page', 00800 ' talkid - The page ID of the talk page for each non-talk page', 00801 ' watched - List the watched status of each page', 00802 ' watchers - The number of watchers, if allowed', 00803 ' notificationtimestamp - The watchlist notification timestamp of each page', 00804 ' subjectid - The page ID of the parent page for each talk page', 00805 ' url - Gives a full URL to the page, and also an edit URL', 00806 ' readable - Whether the user can read this page', 00807 ' preload - Gives the text returned by EditFormPreloadText', 00808 ' displaytitle - Gives the way the page title is actually displayed', 00809 ), 00810 'token' => 'Request a token to perform a data-modifying action on a page', 00811 'continue' => 'When more results are available, use this to continue', 00812 ); 00813 } 00814 00815 public function getResultProperties() { 00816 $props = array( 00817 ApiBase::PROP_LIST => false, 00818 '' => array( 00819 'touched' => 'timestamp', 00820 'lastrevid' => 'integer', 00821 'counter' => array( 00822 ApiBase::PROP_TYPE => 'integer', 00823 ApiBase::PROP_NULLABLE => true 00824 ), 00825 'length' => 'integer', 00826 'redirect' => 'boolean', 00827 'new' => 'boolean', 00828 'starttimestamp' => array( 00829 ApiBase::PROP_TYPE => 'timestamp', 00830 ApiBase::PROP_NULLABLE => true 00831 ), 00832 'contentmodel' => 'string', 00833 ), 00834 'watched' => array( 00835 'watched' => 'boolean' 00836 ), 00837 'watchers' => array( 00838 'watchers' => array( 00839 ApiBase::PROP_TYPE => 'integer', 00840 ApiBase::PROP_NULLABLE => true 00841 ) 00842 ), 00843 'notificationtimestamp' => array( 00844 'notificationtimestamp' => array( 00845 ApiBase::PROP_TYPE => 'timestamp', 00846 ApiBase::PROP_NULLABLE => true 00847 ) 00848 ), 00849 'talkid' => array( 00850 'talkid' => array( 00851 ApiBase::PROP_TYPE => 'integer', 00852 ApiBase::PROP_NULLABLE => true 00853 ) 00854 ), 00855 'subjectid' => array( 00856 'subjectid' => array( 00857 ApiBase::PROP_TYPE => 'integer', 00858 ApiBase::PROP_NULLABLE => true 00859 ) 00860 ), 00861 'url' => array( 00862 'fullurl' => 'string', 00863 'editurl' => 'string' 00864 ), 00865 'readable' => array( 00866 'readable' => 'boolean' 00867 ), 00868 'preload' => array( 00869 'preload' => 'string' 00870 ), 00871 'displaytitle' => array( 00872 'displaytitle' => 'string' 00873 ) 00874 ); 00875 00876 self::addTokenProperties( $props, $this->getTokenFunctions() ); 00877 00878 return $props; 00879 } 00880 00881 public function getDescription() { 00882 return 'Get basic page information such as namespace, title, last touched date, ...'; 00883 } 00884 00885 public function getExamples() { 00886 return array( 00887 'api.php?action=query&prop=info&titles=Main%20Page', 00888 'api.php?action=query&prop=info&inprop=protection&titles=Main%20Page' 00889 ); 00890 } 00891 00892 public function getHelpUrls() { 00893 return 'https://www.mediawiki.org/wiki/API:Properties#info_.2F_in'; 00894 } 00895 }