public function execute() { $this->output("Looking for pages with page_latest set to 0...\n"); $dbw = wfGetDB(DB_MASTER); $result = $dbw->select('page', array('page_id', 'page_namespace', 'page_title'), array('page_latest' => 0), __METHOD__); $n = 0; foreach ($result as $row) { $pageId = intval($row->page_id); $title = Title::makeTitle($row->page_namespace, $row->page_title); $name = $title->getPrefixedText(); $latestTime = $dbw->selectField('revision', 'MAX(rev_timestamp)', array('rev_page' => $pageId), __METHOD__); if (!$latestTime) { $this->output(wfWikiID() . " {$pageId} [[{$name}]] can't find latest rev time?!\n"); continue; } $revision = Revision::loadFromTimestamp($dbw, $title, $latestTime); if (is_null($revision)) { $this->output(wfWikiID() . " {$pageId} [[{$name}]] latest time {$latestTime}, can't find revision id\n"); continue; } $id = $revision->getId(); $this->output(wfWikiID() . " {$pageId} [[{$name}]] latest time {$latestTime}, rev id {$id}\n"); if ($this->hasOption('fix')) { $article = new Article($title); $article->updateRevisionOn($dbw, $revision); } $n++; } $dbw->freeResult($result); $this->output("Done! Processed {$n} pages.\n"); if (!$this->hasOption('fix')) { $this->output("This was a dry run; rerun with --fix to update page_latest.\n"); } }
/** * @param $section empty/null/false or a section number (0, 1, 2, T1, T2...) * @param $text String: new text of the section * @param $summary String: new section's subject, only if $section is 'new' * @param $edittime String: revision timestamp or null to use the current revision * @return string Complete article text, or null if error */ public function replaceSection($section, $text, $summary = '', $edittime = null) { wfProfileIn(__METHOD__); if (strval($section) == '') { // Whole-page edit; let the whole text through } else { if (is_null($edittime)) { $rev = Revision::newFromTitle($this->mTitle); } else { $dbw = wfGetDB(DB_MASTER); $rev = Revision::loadFromTimestamp($dbw, $this->mTitle, $edittime); } if (!$rev) { wfDebug("Article::replaceSection asked for bogus section (page: " . $this->getId() . "; section: {$section}; edittime: {$edittime})\n"); wfProfileOut(__METHOD__); return null; } $oldtext = $rev->getText(); if ($section == 'new') { # Inserting a new section $subject = $summary ? wfMsgForContent('newsectionheaderdefaultlevel', $summary) . "\n\n" : ''; $text = strlen(trim($oldtext)) > 0 ? "{$oldtext}\n\n{$subject}{$text}" : "{$subject}{$text}"; } else { # Replacing an existing section; roll out the big guns global $wgParser; $text = $wgParser->replaceSection($oldtext, $section, $text); } } wfProfileOut(__METHOD__); return $text; }
/** * @param $vars AbuseFilterVariableHolder * @return AFPData|array|int|mixed|null|string * @throws MWException * @throws AFPException */ function compute($vars) { $parameters = $this->mParameters; $result = null; if (!wfRunHooks('AbuseFilter-interceptVariable', array($this->mMethod, $vars, $parameters, &$result))) { return $result instanceof AFPData ? $result : AFPData::newFromPHPVar($result); } switch ($this->mMethod) { case 'diff': $text1Var = $parameters['oldtext-var']; $text2Var = $parameters['newtext-var']; $text1 = $vars->getVar($text1Var)->toString() . "\n"; $text2 = $vars->getVar($text2Var)->toString() . "\n"; $result = wfDiff($text1, $text2); break; case 'diff-split': $diff = $vars->getVar($parameters['diff-var'])->toString(); $line_prefix = $parameters['line-prefix']; $diff_lines = explode("\n", $diff); $interest_lines = array(); foreach ($diff_lines as $line) { if (substr($line, 0, 1) === $line_prefix) { $interest_lines[] = substr($line, strlen($line_prefix)); } } $result = $interest_lines; break; case 'links-from-wikitext': // This should ONLY be used when sharing a parse operation with the edit. /* @var WikiPage $article */ $article = $parameters['article']; if ($article !== null && (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT)) { $textVar = $parameters['text-var']; // XXX: Use prepareContentForEdit. But we need a Content object for that. $new_text = $vars->getVar($textVar)->toString(); $content = ContentHandler::makeContent($new_text, $article->getTitle()); $editInfo = $article->prepareContentForEdit($content); $links = array_keys($editInfo->output->getExternalLinks()); $result = $links; break; } // Otherwise fall back to database // Otherwise fall back to database case 'links-from-wikitext-nonedit': case 'links-from-wikitext-or-database': // TODO: use Content object instead, if available! In any case, use WikiPage, not Article. $article = self::articleFromTitle($parameters['namespace'], $parameters['title']); if ($vars->getVar('context')->toString() == 'filter') { $links = $this->getLinksFromDB($article); wfDebug("AbuseFilter: loading old links from DB\n"); } elseif (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT) { wfDebug("AbuseFilter: loading old links from Parser\n"); $textVar = $parameters['text-var']; $wikitext = $vars->getVar($textVar)->toString(); $editInfo = $this->parseNonEditWikitext($wikitext, $article); $links = array_keys($editInfo->output->getExternalLinks()); } else { // TODO: Get links from Content object. But we don't have the content object. // And for non-text content, $wikitext is usually not going to be a valid // serialization, but rather some dummy text for filtering. $links = array(); } $result = $links; break; case 'link-diff-added': case 'link-diff-removed': $oldLinkVar = $parameters['oldlink-var']; $newLinkVar = $parameters['newlink-var']; $oldLinks = $vars->getVar($oldLinkVar)->toString(); $newLinks = $vars->getVar($newLinkVar)->toString(); $oldLinks = explode("\n", $oldLinks); $newLinks = explode("\n", $newLinks); if ($this->mMethod == 'link-diff-added') { $result = array_diff($newLinks, $oldLinks); } if ($this->mMethod == 'link-diff-removed') { $result = array_diff($oldLinks, $newLinks); } break; case 'parse-wikitext': // Should ONLY be used when sharing a parse operation with the edit. $article = $parameters['article']; if ($article !== null && (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT)) { $textVar = $parameters['wikitext-var']; // XXX: Use prepareContentForEdit. But we need a Content object for that. $new_text = $vars->getVar($textVar)->toString(); $editInfo = $article->prepareTextForEdit($new_text); if (isset($parameters['pst']) && $parameters['pst']) { $result = $editInfo->pstContent->serialize($editInfo->format); } else { $newHTML = $editInfo->output->getText(); // Kill the PP limit comments. Ideally we'd just remove these by not setting the // parser option, but then we can't share a parse operation with the edit, which is bad. $result = preg_replace('/<!--\\s*NewPP limit report[^>]*-->\\s*$/si', '', $newHTML); } break; } // Otherwise fall back to database // Otherwise fall back to database case 'parse-wikitext-nonedit': // TODO: use Content object instead, if available! In any case, use WikiPage, not Article. $article = self::articleFromTitle($parameters['namespace'], $parameters['title']); $textVar = $parameters['wikitext-var']; if (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT) { if (isset($parameters['pst']) && $parameters['pst']) { // $textVar is already PSTed when it's not loaded from an ongoing edit. $result = $vars->getVar($textVar)->toString(); } else { $text = $vars->getVar($textVar)->toString(); $editInfo = $this->parseNonEditWikitext($text, $article); $result = $editInfo->output->getText(); } } else { // TODO: Parser Output from Content object. But we don't have the content object. // And for non-text content, $wikitext is usually not going to be a valid // serialization, but rather some dummy text for filtering. $result = ''; } break; case 'strip-html': $htmlVar = $parameters['html-var']; $html = $vars->getVar($htmlVar)->toString(); $result = StringUtils::delimiterReplace('<', '>', '', $html); break; case 'load-recent-authors': $cutOff = $parameters['cutoff']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); if (!$title->exists()) { $result = ''; break; } $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select('revision', 'DISTINCT rev_user_text', array('rev_page' => $title->getArticleID(), 'rev_timestamp<' . $dbr->addQuotes($dbr->timestamp($cutOff))), __METHOD__, array('ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 10)); $users = array(); foreach ($res as $row) { $users[] = $row->rev_user_text; } $result = $users; break; case 'get-page-restrictions': $action = $parameters['action']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); $rights = $title->getRestrictions($action); $rights = count($rights) ? $rights : array(); $result = $rights; break; case 'simple-user-accessor': $user = $parameters['user']; $method = $parameters['method']; if (!$user) { throw new MWException('No user parameter given.'); } $obj = self::getUserObject($user); if (!$obj) { throw new MWException("Invalid username {$user}"); } $result = call_user_func(array($obj, $method)); break; case 'user-age': $user = $parameters['user']; $asOf = $parameters['asof']; $obj = self::getUserObject($user); if ($obj->getId() == 0) { $result = 0; break; } $registration = $obj->getRegistration(); $result = wfTimestamp(TS_UNIX, $asOf) - wfTimestampOrNull(TS_UNIX, $registration); break; case 'user-groups': // Deprecated but needed by old log entries $user = $parameters['user']; $obj = self::getUserObject($user); $result = $obj->getEffectiveGroups(); break; case 'length': $s = $vars->getVar($parameters['length-var'])->toString(); $result = strlen($s); break; case 'subtract': $v1 = $vars->getVar($parameters['val1-var'])->toFloat(); $v2 = $vars->getVar($parameters['val2-var'])->toFloat(); $result = $v1 - $v2; break; case 'revision-text-by-id': $rev = Revision::newFromId($parameters['revid']); $result = AbuseFilter::revisionToString($rev); break; case 'revision-text-by-timestamp': $timestamp = $parameters['timestamp']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); $dbr = wfGetDB(DB_SLAVE); $rev = Revision::loadFromTimestamp($dbr, $title, $timestamp); $result = AbuseFilter::revisionToString($rev); break; default: if (wfRunHooks('AbuseFilter-computeVariable', array($this->mMethod, $vars, $parameters, &$result))) { throw new AFPException('Unknown variable compute type ' . $this->mMethod); } } return $result instanceof AFPData ? $result : AFPData::newFromPHPVar($result); }
/** * @return Revision */ function getBaseRevision() { if (!$this->mBaseRevision) { $db = wfGetDB(DB_MASTER); $baseRevision = Revision::loadFromTimestamp($db, $this->mTitle, $this->edittime); return $this->mBaseRevision = $baseRevision; } else { return $this->mBaseRevision; } }
function importOldRevision() { $dbw = wfGetDB(DB_MASTER); # Sneak a single revision into place $user = User::newFromName($this->getUser()); if ($user) { $userId = intval($user->getId()); $userText = $user->getName(); } else { $userId = 0; $userText = $this->getUser(); } // avoid memory leak...? $linkCache =& LinkCache::singleton(); $linkCache->clear(); $article = new Article($this->title); $pageId = $article->getId(); if ($pageId == 0) { # must create the page... $pageId = $article->insertOn($dbw); $created = true; } else { $created = false; $prior = Revision::loadFromTimestamp($dbw, $this->title, $this->timestamp); if (!is_null($prior)) { // FIXME: this could fail slightly for multiple matches :P wfDebug(__METHOD__ . ": skipping existing revision for [[" . $this->title->getPrefixedText() . "]], timestamp " . $this->timestamp . "\n"); return false; } } # FIXME: Use original rev_id optionally # FIXME: blah blah blah #if( $numrows > 0 ) { # return wfMsg( "importhistoryconflict" ); #} # Insert the row $revision = new Revision(array('page' => $pageId, 'text' => $this->getText(), 'comment' => $this->getComment(), 'user' => $userId, 'user_text' => $userText, 'timestamp' => $this->timestamp, 'minor_edit' => $this->minor)); $revId = $revision->insertOn($dbw); $changed = $article->updateIfNewerOn($dbw, $revision); if ($created) { wfDebug(__METHOD__ . ": running onArticleCreate\n"); Article::onArticleCreate($this->title); wfDebug(__METHOD__ . ": running create updates\n"); $article->createUpdates($revision); } elseif ($changed) { wfDebug(__METHOD__ . ": running onArticleEdit\n"); Article::onArticleEdit($this->title); wfDebug(__METHOD__ . ": running edit updates\n"); $article->editUpdates($this->getText(), $this->getComment(), $this->minor, $this->timestamp, $revId); } return true; }
/** * @return string Complete article text, or null if error */ function replaceSection($section, $text, $summary = '', $edittime = NULL) { wfProfileIn(__METHOD__); if ($section == '') { // Whole-page edit; let the text through unmolested. } else { if (is_null($edittime)) { $rev = Revision::newFromTitle($this->mTitle); } else { $dbw =& wfGetDB(DB_MASTER); $rev = Revision::loadFromTimestamp($dbw, $this->mTitle, $edittime); } if (is_null($rev)) { wfDebug("Article::replaceSection asked for bogus section (page: " . $this->getId() . "; section: {$section}; edittime: {$edittime})\n"); return null; } $oldtext = $rev->getText(); if ($section == 'new') { if ($summary) { $subject = "== {$summary} ==\n\n"; } $text = $oldtext . "\n\n" . $subject . $text; } else { global $wgParser; $text = $wgParser->replaceSection($oldtext, $section, $text); } } wfProfileOut(__METHOD__); return $text; }
/** * @param string|number|null|bool $sectionId Section identifier as a number or string * (e.g. 0, 1 or 'T-1'), null/false or an empty string for the whole page * or 'new' for a new section. * @param Content $sectionContent New content of the section. * @param string $sectionTitle New section's subject, only if $section is "new". * @param string $edittime Revision timestamp or null to use the current revision. * * @throws MWException * @return Content New complete article content, or null if error. * * @since 1.21 * @deprecated since 1.24, use replaceSectionAtRev instead */ public function replaceSectionContent($sectionId, Content $sectionContent, $sectionTitle = '', $edittime = null) { wfProfileIn(__METHOD__); $baseRevId = null; if ($edittime && $sectionId !== 'new') { $dbw = wfGetDB(DB_MASTER); $rev = Revision::loadFromTimestamp($dbw, $this->mTitle, $edittime); if ($rev) { $baseRevId = $rev->getId(); } } wfProfileOut(__METHOD__); return $this->replaceSectionAtRev($sectionId, $sectionContent, $sectionTitle, $baseRevId); }
/** * @access private * @todo document */ function mergeChangesInto(&$editText) { $fname = 'EditPage::mergeChangesInto'; wfProfileIn($fname); $db =& wfGetDB(DB_MASTER); // This is the revision the editor started from $baseRevision = Revision::loadFromTimestamp($db, $this->mArticle->mTitle, $this->edittime); if (is_null($baseRevision)) { wfProfileOut($fname); return false; } $baseText = $baseRevision->getText(); // The current state, we want to merge updates into it $currentRevision = Revision::loadFromTitle($db, $this->mArticle->mTitle); if (is_null($currentRevision)) { wfProfileOut($fname); return false; } $currentText = $currentRevision->getText(); if (wfMerge($baseText, $editText, $currentText, $result)) { $editText = $result; wfProfileOut($fname); return true; } else { wfProfileOut($fname); return false; } }
$fixit = isset($options['fix']); $fname = 'attachLatest'; echo "Looking for pages with page_latest set to 0...\n"; $dbw =& wfGetDB(DB_MASTER); $result = $dbw->select('page', array('page_id', 'page_namespace', 'page_title'), array('page_latest' => 0), $fname); $n = 0; while ($row = $dbw->fetchObject($result)) { $pageId = intval($row->page_id); $title = Title::makeTitle($row->page_namespace, $row->page_title); $name = $title->getPrefixedText(); $latestTime = $dbw->selectField('revision', 'MAX(rev_timestamp)', array('rev_page' => $pageId), $fname); if (!$latestTime) { echo "{$wgDBname} {$pageId} [[{$name}]] can't find latest rev time?!\n"; continue; } $revision = Revision::loadFromTimestamp($dbw, $title, $latestTime); if (is_null($revision)) { echo "{$wgDBname} {$pageId} [[{$name}]] latest time {$latestTime}, can't find revision id\n"; continue; } $id = $revision->getId(); echo "{$wgDBname} {$pageId} [[{$name}]] latest time {$latestTime}, rev id {$id}\n"; if ($fixit) { $article = new Article($title); $article->updateRevisionOn($dbw, $revision); } $n++; } $dbw->freeResult($result); echo "Done! Processed {$n} pages.\n"; if (!$fixit) {
function getTextOfLastEditWithSectionReplacedOrAdded($section, $text, $summary = '', $edittime = NULL) { $fname = 'Article::getTextOfLastEditWithSectionReplacedOrAdded'; if ($section != '') { if (is_null($edittime)) { $rev = Revision::newFromTitle($this->mTitle); } else { $dbw =& wfGetDB(DB_MASTER); $rev = Revision::loadFromTimestamp($dbw, $this->mTitle, $edittime); } $oldtext = $rev->getText(); if ($section == 'new') { if ($summary) { $subject = "== {$summary} ==\n\n"; } $text = $oldtext . "\n\n" . $subject . $text; } else { # strip NOWIKI etc. to avoid confusion (true-parameter causes HTML # comments to be stripped as well) $striparray = array(); $parser = new Parser(); $parser->mOutputType = OT_WIKI; $parser->mOptions = new ParserOptions(); $oldtext = $parser->strip($oldtext, $striparray, true); # now that we can be sure that no pseudo-sections are in the source, # split it up # Unfortunately we can't simply do a preg_replace because that might # replace the wrong section, so we have to use the section counter instead $secs = preg_split('/(^=+.+?=+|^<h[1-6].*?' . '>.*?<\\/h[1-6].*?' . '>)(?!\\S)/mi', $oldtext, -1, PREG_SPLIT_DELIM_CAPTURE); $secs[$section * 2] = $text . "\n\n"; // replace with edited # section 0 is top (intro) section if ($section != 0) { # headline of old section - we need to go through this section # to determine if there are any subsections that now need to # be erased, as the mother section has been replaced with # the text of all subsections. $headline = $secs[$section * 2 - 1]; preg_match('/^(=+).+?=+|^<h([1-6]).*?' . '>.*?<\\/h[1-6].*?' . '>(?!\\S)/mi', $headline, $matches); $hlevel = $matches[1]; # determine headline level for wikimarkup headings if (strpos($hlevel, '=') !== false) { $hlevel = strlen($hlevel); } $secs[$section * 2 - 1] = ''; // erase old headline $count = $section + 1; $break = false; while (!empty($secs[$count * 2 - 1]) && !$break) { $subheadline = $secs[$count * 2 - 1]; preg_match('/^(=+).+?=+|^<h([1-6]).*?' . '>.*?<\\/h[1-6].*?' . '>(?!\\S)/mi', $subheadline, $matches); $subhlevel = $matches[1]; if (strpos($subhlevel, '=') !== false) { $subhlevel = strlen($subhlevel); } if ($subhlevel > $hlevel) { // erase old subsections $secs[$count * 2 - 1] = ''; $secs[$count * 2] = ''; } if ($subhlevel <= $hlevel) { $break = true; } $count++; } } $text = join('', $secs); # reinsert the stuff that we stripped out earlier $text = $parser->unstrip($text, $striparray); $text = $parser->unstripNoWiki($text, $striparray); } } return $text; }
/** * @desc Saving CSS content * If there is more recent edit it will try to merge text and save. * Returns false when conflict is found and cannot be resolved * * @param string $content * @param string $summary * @param bool $isMinor * @param int $editTime timestamp * @param User $user * @return Status|bool */ public function saveCssFileContent($content, $summary, $isMinor, $editTime, $user) { $cssTitle = $this->getCssFileTitle(); $flags = 0; if ($cssTitle instanceof Title) { $aid = $cssTitle->getArticleID(Title::GAID_FOR_UPDATE); $flags |= $aid == 0 ? EDIT_NEW : EDIT_UPDATE; if ($isMinor) { $flags |= EDIT_MINOR; } $db = wfGetDB(DB_MASTER); $currentRevision = Revision::loadFromTitle($db, $cssTitle); // we handle both - edit and creation conflicts below if (!empty($currentRevision) && $editTime != $currentRevision->getTimestamp()) { $result = ''; $currentText = $currentRevision->getText(); if (!$editTime) { // the css did not exist when the editor was started, so the base revision for // parallel edits is an empty file $baseText = ''; } else { $baseText = Revision::loadFromTimestamp($db, $this->getCssFileTitle(), $editTime)->getText(); } // remove windows endlines from input before merging texts $content = str_replace("\r", "", $content); if (wfMerge($baseText, $content, $currentText, $result)) { // This conflict can be resolved $content = $result; } else { // We have real conflict here return false; } } $page = new WikiPage($cssTitle); $status = $page->doEdit($content, $summary, $flags, false, $user); return $status; } return Status::newFatal('special-css-saving-internal-error'); }
function compute($vars) { $parameters = $this->mParameters; $result = null; switch ($this->mMethod) { case 'diff': $text1Var = $parameters['oldtext-var']; $text2Var = $parameters['newtext-var']; $text1 = $vars->getVar($text1Var)->toString(); $text2 = $vars->getVar($text2Var)->toString(); $result = wfDiff($text1, $text2); $result = trim(preg_replace("/^\\\\ No newline at end of file\n/m", '', $result)); break; case 'diff-split': $diff = $vars->getVar($parameters['diff-var'])->toString(); $line_prefix = $parameters['line-prefix']; $diff_lines = explode("\n", $diff); $interest_lines = array(); foreach ($diff_lines as $line) { if (substr($line, 0, 1) === $line_prefix) { $interest_lines[] = substr($line, strlen($line_prefix)); } } $result = $interest_lines; break; case 'links-from-wikitext': // This should ONLY be used when sharing a parse operation with the edit. $article = $parameters['article']; if ($article) { $textVar = $parameters['text-var']; $new_text = $vars->getVar($textVar)->toString(); $editInfo = $article->prepareTextForEdit($new_text); $links = array_keys($editInfo->output->getExternalLinks()); $result = $links; break; } // Otherwise fall back to database // Otherwise fall back to database case 'links-from-wikitext-nonedit': case 'links-from-wikitext-or-database': $article = self::articleFromTitle($parameters['namespace'], $parameters['title']); if ($vars->getVar('context')->toString() == 'filter') { $links = $this->getLinksFromDB($article); wfDebug("AbuseFilter: loading old links from DB\n"); } else { wfDebug("AbuseFilter: loading old links from Parser\n"); $textVar = $parameters['text-var']; $wikitext = $vars->getVar($textVar)->toString(); $editInfo = $this->parseNonEditWikitext($wikitext, $article); $links = array_keys($editInfo->output->getExternalLinks()); } $result = $links; break; case 'link-diff-added': case 'link-diff-removed': $oldLinkVar = $parameters['oldlink-var']; $newLinkVar = $parameters['newlink-var']; $oldLinks = $vars->getVar($oldLinkVar)->toString(); $newLinks = $vars->getVar($newLinkVar)->toString(); $oldLinks = explode("\n", $oldLinks); $newLinks = explode("\n", $newLinks); if ($this->mMethod == 'link-diff-added') { $result = array_diff($newLinks, $oldLinks); } if ($this->mMethod == 'link-diff-removed') { $result = array_diff($oldLinks, $newLinks); } break; case 'parse-wikitext': // Should ONLY be used when sharing a parse operation with the edit. $article = $parameters['article']; if ($article) { $textVar = $parameters['wikitext-var']; $new_text = $vars->getVar($textVar)->toString(); $editInfo = $article->prepareTextForEdit($new_text); $newHTML = $editInfo->output->getText(); // Kill the PP limit comments. Ideally we'd just remove these by not setting the // parser option, but then we can't share a parse operation with the edit, which is bad. $result = preg_replace('/<!--\\s*NewPP limit report[^>]*-->\\s*$/si', '', $newHTML); break; } // Otherwise fall back to database // Otherwise fall back to database case 'parse-wikitext-nonedit': $article = self::articleFromTitle($parameters['namespace'], $parameters['title']); $textVar = $parameters['wikitext-var']; $text = $vars->getVar($textVar)->toString(); $editInfo = $this->parseNonEditWikitext($text, $article); $result = $editInfo->output->getText(); break; case 'strip-html': $htmlVar = $parameters['html-var']; $html = $vars->getVar($htmlVar)->toString(); $result = StringUtils::delimiterReplace('<', '>', '', $html); break; case 'load-recent-authors': $cutOff = $parameters['cutoff']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); if (!$title->exists()) { $result = ''; break; } $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select('revision', 'DISTINCT rev_user_text', array('rev_page' => $title->getArticleId(), 'rev_timestamp<' . $dbr->addQuotes($dbr->timestamp($cutOff))), __METHOD__, array('ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 10)); $users = array(); foreach ($res as $row) { $users[] = $row->rev_user_text; } $result = $users; break; case 'get-page-restrictions': $action = $parameters['action']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); $rights = $title->getRestrictions($action); $rights = count($rights) ? $rights : array(); $result = $rights; break; case 'simple-user-accessor': $user = $parameters['user']; $method = $parameters['method']; if (!$user) { throw new MWException('No user parameter given.'); } $obj = self::userObjectFromName($user); if (!$obj) { throw new MWException("Invalid username {$user}"); } $result = call_user_func(array($obj, $method)); break; case 'user-age': $user = $parameters['user']; $asOf = $parameters['asof']; $obj = self::userObjectFromName($user); if ($obj->getId() == 0) { $result = 0; break; } $registration = $obj->getRegistration(); $result = wfTimestamp(TS_UNIX, $asOf) - wfTimestampOrNull(TS_UNIX, $registration); break; case 'user-groups': $user = $parameters['user']; $obj = self::userObjectFromName($user); $result = $obj->getEffectiveGroups(); break; case 'length': $s = $vars->getVar($parameters['length-var'])->toString(); $result = strlen($s); break; case 'subtract': $v1 = $vars->getVar($parameters['val1-var'])->toFloat(); $v2 = $vars->getVar($parameters['val2-var'])->toFloat(); $result = $v1 - $v2; break; case 'revision-text-by-id': $rev = Revision::newFromId($parameters['revid']); $result = $rev->getText(); break; case 'revision-text-by-timestamp': $timestamp = $parameters['timestamp']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); $dbr = wfGetDB(DB_SLAVE); $rev = Revision::loadFromTimestamp($dbr, $title, $timestamp); if ($rev) { $result = $rev->getText(); } else { $result = ''; } break; default: if (wfRunHooks('AbuseFilter-computeVariable', array($this->mMethod, $vars))) { throw new AFPException('Unknown variable compute type ' . $this->mMethod); } } return $result instanceof AFPData ? $result : AFPData::newFromPHPVar($result); }
/** * When an user makes a null-edit we sometimes want to review it... * (a) Null undo or rollback * (b) Null edit with review box checked * Note: called after edit ops are finished */ public static function maybeNullEditReview(Page $article, $user, $text, $s, $m, $a, $b, $flags, $rev, &$status, $baseId) { global $wgRequest; # Revision must *be* null (null edit). We also need the user who made the edit. if (!$user || $rev !== null) { return true; } # Rollback/undo or box checked $reviewEdit = $wgRequest->getCheck('wpReviewEdit'); if (!$baseId && !$reviewEdit) { return true; // short-circuit } $fa = FlaggableWikiPage::getTitleInstance($article->getTitle()); $fa->loadPageData('fromdbmaster'); if (!$fa->isReviewable()) { return true; // page is not reviewable } $title = $article->getTitle(); // convenience # Get the current revision ID $rev = Revision::newFromTitle($title, false, Revision::READ_LATEST); if (!$rev) { return true; // wtf? } $flags = null; # Is this a rollback/undo that didn't change anything? if ($baseId > 0) { $frev = FlaggedRevision::newFromTitle($title, $baseId); // base rev of null edit $pRev = Revision::newFromId($rev->getParentId()); // current rev parent $revIsNull = $pRev && $pRev->getTextId() == $rev->getTextId(); # Was the edit that we tried to revert to reviewed? # We avoid auto-reviewing null edits to avoid confusion (bug 28476). if ($frev && !$revIsNull) { # Review this revision of the page... $ok = FlaggedRevs::autoReviewEdit($article, $user, $rev, $flags); if ($ok) { FlaggedRevs::markRevisionPatrolled($rev); // reviewed -> patrolled FlaggedRevs::extraHTMLCacheUpdate($title); return true; } } } # Get edit timestamp, it must exist. $editTimestamp = $wgRequest->getVal('wpEdittime'); # Is the page checked off to be reviewed? if ($editTimestamp && $reviewEdit && $title->userCan('review')) { # Check wpEdittime against current revision's time. # If an edit was auto-merged in between, review only up to what # was the current rev when this user started editing the page. if ($rev->getTimestamp() != $editTimestamp) { $dbw = wfGetDB(DB_MASTER); $rev = Revision::loadFromTimestamp($dbw, $title, $editTimestamp); if (!$rev) { return true; // deleted? } } # Review this revision of the page... $ok = FlaggedRevs::autoReviewEdit($article, $user, $rev, $flags, false); if ($ok) { FlaggedRevs::markRevisionPatrolled($rev); // reviewed -> patrolled FlaggedRevs::extraHTMLCacheUpdate($title); } } return true; }
/** * Return the data needed to construct links for new talk page message * alerts. If there are new messages, this will return an associative array * with the following data: * wiki: The database name of the wiki * link: Root-relative link to the user's talk page * rev: The last talk page revision that the user has seen or null. This * is useful for building diff links. * If there are no new messages, it returns an empty array. * @note This function was designed to accomodate multiple talk pages, but * currently only returns a single link and revision. * @return array */ public function getNewMessageLinks() { $talks = array(); if (!Hooks::run('UserRetrieveNewTalks', array(&$this, &$talks))) { return $talks; } elseif (!$this->getNewtalk()) { return array(); } $utp = $this->getTalkPage(); $dbr = wfGetDB(DB_SLAVE); // Get the "last viewed rev" timestamp from the oldest message notification $timestamp = $dbr->selectField('user_newtalk', 'MIN(user_last_timestamp)', $this->isAnon() ? array('user_ip' => $this->getName()) : array('user_id' => $this->getID()), __METHOD__); $rev = $timestamp ? Revision::loadFromTimestamp($dbr, $utp, $timestamp) : null; return array(array('wiki' => wfWikiID(), 'link' => $utp->getLocalURL(), 'rev' => $rev)); }
/** * @note: this method is very poorly named. If the user opened the form with ?oldid=X, * one might think of X as the "base revision", which is NOT what this returns. * @return Revision Current version when the edit was started */ function getBaseRevision() { if (!$this->mBaseRevision) { $db = wfGetDB(DB_MASTER); $this->mBaseRevision = $this->editRevId ? Revision::newFromId($this->editRevId, Revision::READ_LATEST) : Revision::loadFromTimestamp($db, $this->mTitle, $this->edittime); } return $this->mBaseRevision; }
/** * @param string|number|null|bool $sectionId Section identifier as a number or string * (e.g. 0, 1 or 'T-1'), null/false or an empty string for the whole page * or 'new' for a new section. * @param Content $sectionContent New content of the section. * @param string $sectionTitle New section's subject, only if $section is "new". * @param string $edittime Revision timestamp or null to use the current revision. * * @throws MWException * @return Content|null New complete article content, or null if error. * * @since 1.21 * @deprecated since 1.24, use replaceSectionAtRev instead */ public function replaceSectionContent($sectionId, Content $sectionContent, $sectionTitle = '', $edittime = null) { $baseRevId = null; if ($edittime && $sectionId !== 'new') { $dbr = wfGetDB(DB_REPLICA); $rev = Revision::loadFromTimestamp($dbr, $this->mTitle, $edittime); // Try the master if this thread may have just added it. // This could be abstracted into a Revision method, but we don't want // to encourage loading of revisions by timestamp. if (!$rev && wfGetLB()->getServerCount() > 1 && wfGetLB()->hasOrMadeRecentMasterChanges()) { $dbw = wfGetDB(DB_MASTER); $rev = Revision::loadFromTimestamp($dbw, $this->mTitle, $edittime); } if ($rev) { $baseRevId = $rev->getId(); } } return $this->replaceSectionAtRev($sectionId, $sectionContent, $sectionTitle, $baseRevId); }
/** * @since 1.1 * * @param EditPage $editpage * * @return true */ public function onAttemptSave(EditPage $editpage) { global $wgServerName, $wgScriptPath; $urlServer = 'http://' . $wgServerName . $wgScriptPath; $ns = $editpage->mTitle->getNamespace(); if ($ns == PATCH || $ns == PUSHFEED || $ns == PULLFEED || $ns == CHANGESET) { return true; } $actualtext = $editpage->textbox1; // V2 $dbr = wfGetDB(DB_SLAVE); $lastRevision = Revision::loadFromTitle($dbr, $editpage->mTitle); if (is_null($lastRevision)) { $conctext = ""; $rev_id = 0; } elseif (($ns == NS_FILE || $ns == NS_IMAGE || $ns == NS_MEDIA) && $lastRevision->getRawText() == "") { $rev_id = 0; $conctext = $lastRevision->getText(); } else { $conctext = $lastRevision->getText(); // V1 conc $rev_id = $lastRevision->getId(); } // if there is no modification on the text if ($actualtext == $conctext) { return true; } $model = DSMWRevisionManager::loadModel($rev_id); $logoot = new logootEngine($model); // get the revision with the edittime==>V0 $rev = Revision::loadFromTimestamp($dbr, $editpage->mTitle, $editpage->edittime); if (is_null($rev)) { $text = ""; $rev_id1 = 0; } else { $text = $rev->getText(); // VO $rev_id1 = $rev->getId(); } if ($conctext != $text) { // if last revision is not V0, there is editing conflict $model1 = DSMWRevisionManager::loadModel($rev_id1); $logoot1 = new logootEngine($model1); $listOp1 = $logoot1->generate($text, $actualtext); // creation Patch P2 $tmp = serialize($listOp1); $patch = new DSMWPatch(false, false, $listOp1, $urlServer, $rev_id1); if ($editpage->mTitle->getNamespace() == 0) { $title = $editpage->mTitle->getText(); } else { $title = $editpage->mTitle->getNsText() . ':' . $editpage->mTitle->getText(); } // integration: diffs between VO and V2 into V1 $modelAfterIntegrate = $logoot->integrate($listOp1); } else { // no edition conflict $listOp = $logoot->generate($conctext, $actualtext); $modelAfterIntegrate = $logoot->getModel(); $tmp = serialize($listOp); $patch = new DSMWPatch(false, false, $listOp, $urlServer, $rev_id1); if ($editpage->mTitle->getNamespace() == 0) { $title = $editpage->mTitle->getText(); } else { $title = $editpage->mTitle->getNsText() . ':' . $editpage->mTitle->getText(); } } $revId = utils::getNewArticleRevId(); wfDebugLog('p2p', ' -> store model rev : ' . $revId . ' session ' . session_id() . ' model ' . $modelAfterIntegrate->getText()); DSMWRevisionManager::storeModel($revId + 1, $sessionId = session_id(), $modelAfterIntegrate, $blobCB = 0); $patch->storePage($title, $revId + 1); // stores the patch in a wikipage $editpage->textbox1 = $modelAfterIntegrate->getText(); return true; }
/** * @param $section null|bool|int or a section number (0, 1, 2, T1, T2...) * @param $sectionContent Content: new content of the section * @param string $sectionTitle new section's subject, only if $section is 'new' * @param string $edittime revision timestamp or null to use the current revision * * @throws MWException * @return Content new complete article content, or null if error * * @since 1.21 */ public function replaceSectionContent( $section, Content $sectionContent, $sectionTitle = '', $edittime = null ) { wfProfileIn( __METHOD__ ); if ( strval( $section ) == '' ) { // Whole-page edit; let the whole text through $newContent = $sectionContent; } else { if ( !$this->supportsSections() ) { wfProfileOut( __METHOD__ ); throw new MWException( "sections not supported for content model " . $this->getContentHandler()->getModelID() ); } // Bug 30711: always use current version when adding a new section if ( is_null( $edittime ) || $section == 'new' ) { $oldContent = $this->getContent(); } else { $dbw = wfGetDB( DB_MASTER ); $rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime ); if ( !$rev ) { wfDebug( "WikiPage::replaceSection asked for bogus section (page: " . $this->getId() . "; section: $section; edittime: $edittime)\n" ); wfProfileOut( __METHOD__ ); return null; } $oldContent = $rev->getContent(); } if ( ! $oldContent ) { wfDebug( __METHOD__ . ": no page text\n" ); wfProfileOut( __METHOD__ ); return null; } // FIXME: $oldContent might be null? $newContent = $oldContent->replaceSection( $section, $sectionContent, $sectionTitle ); } wfProfileOut( __METHOD__ ); return $newContent; }
/** * @param $section null|bool|int or a section number (0, 1, 2, T1, T2...) * @param $text String: new text of the section * @param $sectionTitle String: new section's subject, only if $section is 'new' * @param $edittime String: revision timestamp or null to use the current revision * @return string Complete article text, or null if error */ public function replaceSection($section, $text, $sectionTitle = '', $edittime = null) { wfProfileIn(__METHOD__); if (strval($section) == '') { // Whole-page edit; let the whole text through } else { // Bug 30711: always use current version when adding a new section if (is_null($edittime) || $section == 'new') { $oldtext = $this->getRawText(); if ($oldtext === false) { wfDebug(__METHOD__ . ": no page text\n"); wfProfileOut(__METHOD__); return null; } } else { $dbw = wfGetDB(DB_MASTER); $rev = Revision::loadFromTimestamp($dbw, $this->mTitle, $edittime); if (!$rev) { wfDebug("WikiPage::replaceSection asked for bogus section (page: " . $this->getId() . "; section: {$section}; edittime: {$edittime})\n"); wfProfileOut(__METHOD__); return null; } $oldtext = $rev->getText(); } if ($section == 'new') { # Inserting a new section $subject = $sectionTitle ? wfMessage('newsectionheaderdefaultlevel')->rawParams($sectionTitle)->inContentLanguage()->text() . "\n\n" : ''; if (wfRunHooks('PlaceNewSection', array($this, $oldtext, $subject, &$text))) { $text = strlen(trim($oldtext)) > 0 ? "{$oldtext}\n\n{$subject}{$text}" : "{$subject}{$text}"; } } else { # Replacing an existing section; roll out the big guns global $wgParser; $text = $wgParser->replaceSection($oldtext, $section, $text); } } wfProfileOut(__METHOD__); return $text; }