public static function ifexistCommon($parser, $frame, $titletext = '', $then = '', $else = '') { global $wgContLang; $title = Title::newFromText($titletext); $wgContLang->findVariantLink($titletext, $title, true); if ($title) { if ($title->getNamespace() == NS_MEDIA) { /* If namespace is specified as NS_MEDIA, then we want to * check the physical file, not the "description" page. */ if (!self::incrementIfexistCount($parser, $frame)) { return $else; } $file = wfFindFile($title); if (!$file) { return $else; } $parser->mOutput->addImage($file->getName(), $file->getTimestamp(), $file->getSha1()); return $file->exists() ? $then : $else; } elseif ($title->getNamespace() == NS_SPECIAL) { /* Don't bother with the count for special pages, * since their existence can be checked without * accessing the database. */ return SpecialPage::exists($title->getDBkey()) ? $then : $else; } elseif ($title->isExternal()) { /* Can't check the existence of pages on other sites, * so just return $else. Makes a sort of sense, since * they don't exist _locally_. */ return $else; } else { $pdbk = $title->getPrefixedDBkey(); $lc = LinkCache::singleton(); if (!self::incrementIfexistCount($parser, $frame)) { return $else; } if (0 != ($id = $lc->getGoodLinkID($pdbk))) { $parser->mOutput->addLink($title, $id); return $then; } elseif ($lc->isBadLink($pdbk)) { $parser->mOutput->addLink($title, 0); return $else; } $id = $title->getArticleID(); $parser->mOutput->addLink($title, $id); if ($id) { return $then; } } } return $else; }
private function shouldFollow(&$title) { global $wgUser; if ($title) { $namespace = $title->getNamespace(); if (!Misc::allowRedirectFromLogin($title)) { return false; } //leaving in case we open it back up /*if( $namespace == NS_MAIN && $title->exists() ) { return true; }*/ if ($namespace == NS_SPECIAL && SpecialPage::exists($title->getText())) { $requiresLogin = Misc::requiresLogin($title); if ($wgUser->getID() > 0 || !$requiresLogin) { return true; } } } return false; }
/** * Appends an element for each page in the current pageSet with the * most general information (id, title), plus any title normalizations * and missing or invalid title/pageids/revids. */ private function outputGeneralPageInfo() { $pageSet = $this->getPageSet(); $result = $this->getResult(); // We don't check for a full result set here because we can't be adding // more than 380K. The maximum revision size is in the megabyte range, // and the maximum result size must be even higher than that. // Title normalizations $normValues = array(); foreach ($pageSet->getNormalizedTitles() as $rawTitleStr => $titleStr) { $normValues[] = array('from' => $rawTitleStr, 'to' => $titleStr); } if (count($normValues)) { $result->setIndexedTagName($normValues, 'n'); $result->addValue('query', 'normalized', $normValues); } // Title conversions $convValues = array(); foreach ($pageSet->getConvertedTitles() as $rawTitleStr => $titleStr) { $convValues[] = array('from' => $rawTitleStr, 'to' => $titleStr); } if (count($convValues)) { $result->setIndexedTagName($convValues, 'c'); $result->addValue('query', 'converted', $convValues); } // Interwiki titles $intrwValues = array(); foreach ($pageSet->getInterwikiTitles() as $rawTitleStr => $interwikiStr) { $intrwValues[] = array('title' => $rawTitleStr, 'iw' => $interwikiStr); } if (count($intrwValues)) { $result->setIndexedTagName($intrwValues, 'i'); $result->addValue('query', 'interwiki', $intrwValues); } // Show redirect information $redirValues = array(); foreach ($pageSet->getRedirectTitles() as $titleStrFrom => $titleStrTo) { $redirValues[] = array('from' => strval($titleStrFrom), 'to' => $titleStrTo); } if (count($redirValues)) { $result->setIndexedTagName($redirValues, 'r'); $result->addValue('query', 'redirects', $redirValues); } // Missing revision elements $missingRevIDs = $pageSet->getMissingRevisionIDs(); if (count($missingRevIDs)) { $revids = array(); foreach ($missingRevIDs as $revid) { $revids[$revid] = array('revid' => $revid); } $result->setIndexedTagName($revids, 'rev'); $result->addValue('query', 'badrevids', $revids); } // Page elements $pages = array(); // Report any missing titles foreach ($pageSet->getMissingTitles() as $fakeId => $title) { $vals = array(); ApiQueryBase::addTitleInfo($vals, $title); $vals['missing'] = ''; $pages[$fakeId] = $vals; } // Report any invalid titles foreach ($pageSet->getInvalidTitles() as $fakeId => $title) { $pages[$fakeId] = array('title' => $title, 'invalid' => ''); } // Report any missing page ids foreach ($pageSet->getMissingPageIDs() as $pageid) { $pages[$pageid] = array('pageid' => $pageid, 'missing' => ''); } // Report special pages foreach ($pageSet->getSpecialTitles() as $fakeId => $title) { $vals = array(); ApiQueryBase::addTitleInfo($vals, $title); $vals['special'] = ''; if ($title->getNamespace() == NS_SPECIAL && !SpecialPage::exists($title->getDbKey())) { $vals['missing'] = ''; } elseif ($title->getNamespace() == NS_MEDIA && !wfFindFile($title)) { $vals['missing'] = ''; } $pages[$fakeId] = $vals; } // Output general page information for found titles foreach ($pageSet->getGoodTitles() as $pageid => $title) { $vals = array(); $vals['pageid'] = $pageid; ApiQueryBase::addTitleInfo($vals, $title); $pages[$pageid] = $vals; } if (count($pages)) { if ($this->params['indexpageids']) { $pageIDs = array_keys($pages); // json treats all map keys as strings - converting to match $pageIDs = array_map('strval', $pageIDs); $result->setIndexedTagName($pageIDs, 'id'); $result->addValue('query', 'pageids', $pageIDs); } $result->setIndexedTagName($pages, 'page'); $result->addValue('query', 'pages', $pages); } if ($this->params['export']) { $this->doExport($pageSet, $result); } }
/** * Replace <!--LINK--> link placeholders with actual links, in the buffer * Placeholders created in Skin::makeLinkObj() * Returns an array of link CSS classes, indexed by PDBK. * $options is a bit field, RLH_FOR_UPDATE to select for update */ function replaceLinkHolders(&$text, $options = 0) { global $wgUser; global $wgContLang; $fname = 'Parser::replaceLinkHolders'; wfProfileIn($fname); $pdbks = array(); $colours = array(); $linkcolour_ids = array(); $sk = $this->mOptions->getSkin(); $linkCache =& LinkCache::singleton(); if (!empty($this->mLinkHolders['namespaces'])) { wfProfileIn($fname . '-check'); $dbr = wfGetDB(DB_SLAVE); $page = $dbr->tableName('page'); $threshold = $wgUser->getOption('stubthreshold'); # Sort by namespace asort($this->mLinkHolders['namespaces']); # Generate query $query = false; $current = null; foreach ($this->mLinkHolders['namespaces'] as $key => $ns) { # Make title object $title = $this->mLinkHolders['titles'][$key]; # Skip invalid entries. # Result will be ugly, but prevents crash. if (is_null($title)) { continue; } $pdbk = $pdbks[$key] = $title->getPrefixedDBkey(); # Check if it's a static known link, e.g. interwiki if ($title->isAlwaysKnown()) { $colours[$pdbk] = ''; } elseif (($id = $linkCache->getGoodLinkID($pdbk)) != 0) { $colours[$pdbk] = ''; $this->mOutput->addLink($title, $id); } elseif ($linkCache->isBadLink($pdbk)) { $colours[$pdbk] = 'new'; } elseif ($title->getNamespace() == NS_SPECIAL && !SpecialPage::exists($pdbk)) { $colours[$pdbk] = 'new'; } else { # Not in the link cache, add it to the query if (!isset($current)) { $current = $ns; $query = "SELECT page_id, page_namespace, page_title, page_is_redirect"; if ($threshold > 0) { $query .= ', page_len'; } $query .= " FROM {$page} WHERE (page_namespace={$ns} AND page_title IN("; } elseif ($current != $ns) { $current = $ns; $query .= ")) OR (page_namespace={$ns} AND page_title IN("; } else { $query .= ', '; } $query .= $dbr->addQuotes($this->mLinkHolders['dbkeys'][$key]); } } if ($query) { $query .= '))'; if ($options & RLH_FOR_UPDATE) { $query .= ' FOR UPDATE'; } $res = $dbr->query($query, $fname); # Fetch data and form into an associative array # non-existent = broken while ($s = $dbr->fetchObject($res)) { $title = Title::makeTitle($s->page_namespace, $s->page_title); $pdbk = $title->getPrefixedDBkey(); $linkCache->addGoodLinkObj($s->page_id, $title); $this->mOutput->addLink($title, $s->page_id); $colours[$pdbk] = $sk->getLinkColour($s, $threshold); //add id to the extension todolist $linkcolour_ids[$s->page_id] = $pdbk; } //pass an array of page_ids to an extension wfRunHooks('GetLinkColours', array($linkcolour_ids, &$colours)); } wfProfileOut($fname . '-check'); # Do a second query for different language variants of links and categories if ($wgContLang->hasVariants()) { $linkBatch = new LinkBatch(); $variantMap = array(); // maps $pdbkey_Variant => $keys (of link holders) $categoryMap = array(); // maps $category_variant => $category (dbkeys) $varCategories = array(); // category replacements oldDBkey => newDBkey $categories = $this->mOutput->getCategoryLinks(); // Add variants of links to link batch foreach ($this->mLinkHolders['namespaces'] as $key => $ns) { $title = $this->mLinkHolders['titles'][$key]; if (is_null($title)) { continue; } $pdbk = $title->getPrefixedDBkey(); $titleText = $title->getText(); // generate all variants of the link title text $allTextVariants = $wgContLang->convertLinkToAllVariants($titleText); // if link was not found (in first query), add all variants to query if (!isset($colours[$pdbk])) { foreach ($allTextVariants as $textVariant) { if ($textVariant != $titleText) { $variantTitle = Title::makeTitle($ns, $textVariant); if (is_null($variantTitle)) { continue; } $linkBatch->addObj($variantTitle); $variantMap[$variantTitle->getPrefixedDBkey()][] = $key; } } } } // process categories, check if a category exists in some variant foreach ($categories as $category) { $variants = $wgContLang->convertLinkToAllVariants($category); foreach ($variants as $variant) { if ($variant != $category) { $variantTitle = Title::newFromDBkey(Title::makeName(NS_CATEGORY, $variant)); if (is_null($variantTitle)) { continue; } $linkBatch->addObj($variantTitle); $categoryMap[$variant] = $category; } } } if (!$linkBatch->isEmpty()) { // construct query $titleClause = $linkBatch->constructSet('page', $dbr); $variantQuery = "SELECT page_id, page_namespace, page_title, page_is_redirect"; if ($threshold > 0) { $variantQuery .= ', page_len'; } $variantQuery .= " FROM {$page} WHERE {$titleClause}"; if ($options & RLH_FOR_UPDATE) { $variantQuery .= ' FOR UPDATE'; } $varRes = $dbr->query($variantQuery, $fname); // for each found variants, figure out link holders and replace while ($s = $dbr->fetchObject($varRes)) { $variantTitle = Title::makeTitle($s->page_namespace, $s->page_title); $varPdbk = $variantTitle->getPrefixedDBkey(); $vardbk = $variantTitle->getDBkey(); $holderKeys = array(); if (isset($variantMap[$varPdbk])) { $holderKeys = $variantMap[$varPdbk]; $linkCache->addGoodLinkObj($s->page_id, $variantTitle); $this->mOutput->addLink($variantTitle, $s->page_id); } // loop over link holders foreach ($holderKeys as $key) { $title = $this->mLinkHolders['titles'][$key]; if (is_null($title)) { continue; } $pdbk = $title->getPrefixedDBkey(); if (!isset($colours[$pdbk])) { // found link in some of the variants, replace the link holder data $this->mLinkHolders['titles'][$key] = $variantTitle; $this->mLinkHolders['dbkeys'][$key] = $variantTitle->getDBkey(); // set pdbk and colour $pdbks[$key] = $varPdbk; $colours[$varPdbk] = $sk->getLinkColour($s, $threshold); $linkcolour_ids[$s->page_id] = $pdbk; } wfRunHooks('GetLinkColours', array($linkcolour_ids, &$colours)); } // check if the object is a variant of a category if (isset($categoryMap[$vardbk])) { $oldkey = $categoryMap[$vardbk]; if ($oldkey != $vardbk) { $varCategories[$oldkey] = $vardbk; } } } // rebuild the categories in original order (if there are replacements) if (count($varCategories) > 0) { $newCats = array(); $originalCats = $this->mOutput->getCategories(); foreach ($originalCats as $cat => $sortkey) { // make the replacement if (array_key_exists($cat, $varCategories)) { $newCats[$varCategories[$cat]] = $sortkey; } else { $newCats[$cat] = $sortkey; } } $this->mOutput->setCategoryLinks($newCats); } } } # Construct search and replace arrays wfProfileIn($fname . '-construct'); $replacePairs = array(); foreach ($this->mLinkHolders['namespaces'] as $key => $ns) { $pdbk = $pdbks[$key]; $searchkey = "<!--LINK {$key}-->"; $title = $this->mLinkHolders['titles'][$key]; if (!isset($colours[$pdbk]) || $colours[$pdbk] == 'new') { $linkCache->addBadLinkObj($title); $colours[$pdbk] = 'new'; $this->mOutput->addLink($title, 0); $replacePairs[$searchkey] = $sk->makeBrokenLinkObj($title, $this->mLinkHolders['texts'][$key], $this->mLinkHolders['queries'][$key]); } else { $replacePairs[$searchkey] = $sk->makeColouredLinkObj($title, $colours[$pdbk], $this->mLinkHolders['texts'][$key], $this->mLinkHolders['queries'][$key]); } } $replacer = new HashtableReplacer($replacePairs, 1); wfProfileOut($fname . '-construct'); # Do the thing wfProfileIn($fname . '-replace'); $text = preg_replace_callback('/(<!--LINK .*?-->)/', $replacer->cb(), $text); wfProfileOut($fname . '-replace'); } # Now process interwiki link holders # This is quite a bit simpler than internal links if (!empty($this->mInterwikiLinkHolders['texts'])) { wfProfileIn($fname . '-interwiki'); # Make interwiki link HTML $replacePairs = array(); foreach ($this->mInterwikiLinkHolders['texts'] as $key => $link) { $title = $this->mInterwikiLinkHolders['titles'][$key]; $replacePairs[$key] = $sk->makeLinkObj($title, $link); } $replacer = new HashtableReplacer($replacePairs, 1); $text = preg_replace_callback('/<!--IWLINK (.*?)-->/', $replacer->cb(), $text); wfProfileOut($fname . '-interwiki'); } wfProfileOut($fname); return $colours; }
/** * Should links to this title be shown as potentially viewable (i.e. as * "bluelinks"), even if there's no record by this title in the page * table? * * This function is semi-deprecated for public use, as well as somewhat * misleadingly named. You probably just want to call isKnown(), which * calls this function internally. * * (ISSUE: Most of these checks are cheap, but the file existence check * can potentially be quite expensive. Including it here fixes a lot of * existing code, but we might want to add an optional parameter to skip * it and any other expensive checks.) * * @return \type{\bool} */ public function isAlwaysKnown() { if ($this->mInterwiki != '') { return true; // any interwiki link might be viewable, for all we know } switch ($this->mNamespace) { case NS_MEDIA: case NS_FILE: return (bool) wfFindFile($this); // file exists, possibly in a foreign repo // file exists, possibly in a foreign repo case NS_SPECIAL: return SpecialPage::exists($this->getDBkey()); // valid special page // valid special page case NS_MAIN: return $this->mDbkeyform == ''; // selflink, possibly with fragment // selflink, possibly with fragment case NS_MEDIAWIKI: // If the page is form Mediawiki:message/lang, calling wfMsgWeirdKey causes // the full l10n of that language to be loaded. That takes much memory and // isn't needed. So we strip the language part away. list($basename, ) = explode('/', $this->mDbkeyform, 2); return (bool) wfMsgWeirdKey($basename); // known system message // known system message default: return false; } }
/** * Make a link for a title which may or may not be in the database. If you need to * call this lots of times, pre-fill the link cache with a LinkBatch, otherwise each * call to this will result in a DB query. * * @param $nt Title: the title object to make the link from, e.g. from * Title::newFromText. * @param $text String: link text * @param $query String: optional query part * @param $trail String: optional trail. Alphabetic characters at the start of this string will * be included in the link text. Other characters will be appended after * the end of the link. * @param $prefix String: optional prefix. As trail, only before instead of after. */ function makeLinkObj($nt, $text = '', $query = '', $trail = '', $prefix = '') { global $wgUser; wfProfileIn(__METHOD__); if (!$nt instanceof Title) { # Fail gracefully wfProfileOut(__METHOD__); return "<!-- ERROR -->{$prefix}{$text}{$trail}"; } if ($nt->isExternal()) { $u = $nt->getFullURL(); $link = $nt->getPrefixedURL(); if ('' == $text) { $text = $nt->getPrefixedText(); } $style = $this->getInterwikiLinkAttributes($link, $text, 'extiw'); $inside = ''; if ('' != $trail) { $m = array(); if (preg_match('/^([a-z]+)(.*)$$/sD', $trail, $m)) { $inside = $m[1]; $trail = $m[2]; } } $t = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>"; wfProfileOut(__METHOD__); return $t; } elseif ($nt->isAlwaysKnown()) { # Image links, special page links and self-links with fragements are always known. $retVal = $this->makeKnownLinkObj($nt, $text, $query, $trail, $prefix); } else { wfProfileIn(__METHOD__ . '-immediate'); # Handles links to special pages which do not exist in the database: if ($nt->getNamespace() == NS_SPECIAL) { if (SpecialPage::exists($nt->getDBkey())) { $retVal = $this->makeKnownLinkObj($nt, $text, $query, $trail, $prefix); } else { $retVal = $this->makeBrokenLinkObj($nt, $text, $query, $trail, $prefix); } wfProfileOut(__METHOD__ . '-immediate'); wfProfileOut(__METHOD__); return $retVal; } # Work out link colour immediately $aid = $nt->getArticleID(); if (0 == $aid) { $retVal = $this->makeBrokenLinkObj($nt, $text, $query, $trail, $prefix); } else { $colour = ''; if ($nt->isContentPage()) { # FIXME: This is stupid, we should combine this query with # the Title::getArticleID() query above. $threshold = $wgUser->getOption('stubthreshold'); $dbr = wfGetDB(DB_SLAVE); $s = $dbr->selectRow(array('page'), array('page_len', 'page_is_redirect', 'page_namespace'), array('page_id' => $aid), __METHOD__); $colour = $this->getLinkColour($s, $threshold); } $retVal = $this->makeColouredLinkObj($nt, $colour, $text, $query, $trail, $prefix); } wfProfileOut(__METHOD__ . '-immediate'); } wfProfileOut(__METHOD__); return $retVal; }