} $revision = new Revision(array('page' => $pageId, 'id' => $row->ar_rev_id, 'text' => $revText, 'comment' => $row->ar_comment, 'user' => $row->ar_user, 'user_text' => $row->ar_user_text, 'timestamp' => $row->ar_timestamp, 'minor_edit' => $row->ar_minor_edit, 'text_id' => $row->ar_text_id, 'len' => $row->ar_len)); $revision->insertOn($dbw); $restored++; } // Was anything restored at all? if ($restored == 0) { print "Nothing was restored\n"; exit(1); } if ($revision) { // Attach the latest revision to the page... $wasnew = $article->updateIfNewerOn($dbw, $revision, $previousRevId); if ($newid || $wasnew) { // Update site stats, link tables, etc $article->createUpdates($revision); } if ($newid) { Article::onArticleCreate($page); } else { Article::onArticleEdit($page); } if ($page->getNamespace() == NS_IMAGE) { $update = new HTMLCacheUpdate($page, 'imagelinks'); $update->doUpdate(); } } else { // Revision couldn't be created. This is very weird print "We got an unknown error\n"; exit(1); }
/** * This is the meaty bit -- restores archived revisions of the given page * to the cur/old tables. If the page currently exists, all revisions will * be stuffed into old, otherwise the most recent will go into cur. * * @param array $timestamps Pass an empty array to restore all revisions, otherwise list the ones to undelete. * @param string $comment * @param array $fileVersions * * @return int number of revisions restored */ private function undeleteRevisions($timestamps) { global $wgParser, $wgDBtype; $restoreAll = empty($timestamps); $dbw =& wfGetDB(DB_MASTER); extract($dbw->tableNames('page', 'archive')); # Does this page already exist? We'll have to update it... $article = new Article($this->title); $options = $wgDBtype == 'postgres' ? '' : 'FOR UPDATE'; $page = $dbw->selectRow('page', array('page_id', 'page_latest'), array('page_namespace' => $this->title->getNamespace(), 'page_title' => $this->title->getDBkey()), __METHOD__, $options); if ($page) { # Page already exists. Import the history, and if necessary # we'll update the latest revision field in the record. $newid = 0; $pageId = $page->page_id; $previousRevId = $page->page_latest; } else { # Have to create a new article... $newid = $article->insertOn($dbw); $pageId = $newid; $previousRevId = 0; } if ($restoreAll) { $oldones = '1 = 1'; # All revisions... } else { $oldts = implode(',', array_map(array(&$dbw, 'addQuotes'), array_map(array(&$dbw, 'timestamp'), $timestamps))); $oldones = "ar_timestamp IN ( {$oldts} )"; } /** * Restore each revision... */ $result = $dbw->select('archive', array('ar_rev_id', 'ar_text', 'ar_comment', 'ar_user', 'ar_user_text', 'ar_timestamp', 'ar_minor_edit', 'ar_flags', 'ar_text_id'), array('ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), $oldones), __METHOD__, array('ORDER BY' => 'ar_timestamp')); if ($dbw->numRows($result) < count($timestamps)) { wfDebug(__METHOD__ . ": couldn't find all requested rows\n"); return false; } $revision = null; $newRevId = $previousRevId; $restored = 0; while ($row = $dbw->fetchObject($result)) { if ($row->ar_text_id) { // Revision was deleted in 1.5+; text is in // the regular text table, use the reference. // Specify null here so the so the text is // dereferenced for page length info if needed. $revText = null; } else { // Revision was deleted in 1.4 or earlier. // Text is squashed into the archive row, and // a new text table entry will be created for it. $revText = Revision::getRevisionText($row, 'ar_'); } $revision = new Revision(array('page' => $pageId, 'id' => $row->ar_rev_id, 'text' => $revText, 'comment' => $row->ar_comment, 'user' => $row->ar_user, 'user_text' => $row->ar_user_text, 'timestamp' => $row->ar_timestamp, 'minor_edit' => $row->ar_minor_edit, 'text_id' => $row->ar_text_id)); $newRevId = $revision->insertOn($dbw); $restored++; } if ($revision) { # FIXME: Update latest if newer as well... if ($newid) { // Attach the latest revision to the page... $article->updateRevisionOn($dbw, $revision, $previousRevId); // Update site stats, link tables, etc $article->createUpdates($revision); } if ($newid) { Article::onArticleCreate($this->title); } else { Article::onArticleEdit($this->title); } } else { # Something went terribly wrong! } # Now that it's safely stored, take it out of the archive $dbw->delete('archive', array('ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), $oldones), __METHOD__); return $restored; }
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 = $dbw->selectField('revision', '1', array('rev_page' => $pageId, 'rev_timestamp' => $dbw->timestamp($this->timestamp), 'rev_user_text' => $userText, 'rev_comment' => $this->getComment()), __METHOD__); if ($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 (better for backups) # 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); # To be on the safe side... $tempTitle = $GLOBALS['wgTitle']; $GLOBALS['wgTitle'] = $this->title; 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); } $GLOBALS['wgTitle'] = $tempTitle; return true; }
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; }
/** * This is the meaty bit -- restores archived revisions of the given page * to the cur/old tables. If the page currently exists, all revisions will * be stuffed into old, otherwise the most recent will go into cur. * * @param array $timestamps Pass an empty array to restore all revisions, otherwise list the ones to undelete. * @param string $comment * @param array $fileVersions * * @return mixed number of revisions restored or false on failure */ private function undeleteRevisions($timestamps) { if (wfReadOnly()) { return false; } $restoreAll = empty($timestamps); $dbw = wfGetDB(DB_MASTER); # Does this page already exist? We'll have to update it... $article = new Article($this->title); $options = 'FOR UPDATE'; $page = $dbw->selectRow('page', array('page_id', 'page_latest'), array('page_namespace' => $this->title->getNamespace(), 'page_title' => $this->title->getDBkey()), __METHOD__, $options); if ($page) { # Page already exists. Import the history, and if necessary # we'll update the latest revision field in the record. $newid = 0; $pageId = $page->page_id; $previousRevId = $page->page_latest; } else { # Have to create a new article... $newid = $article->insertOn($dbw); $pageId = $newid; $previousRevId = 0; } if ($restoreAll) { $oldones = '1 = 1'; # All revisions... } else { $oldts = implode(',', array_map(array(&$dbw, 'addQuotes'), array_map(array(&$dbw, 'timestamp'), $timestamps))); $oldones = "ar_timestamp IN ( {$oldts} )"; } /** * Restore each revision... */ $result = $dbw->select('archive', array('ar_rev_id', 'ar_text', 'ar_comment', 'ar_user', 'ar_user_text', 'ar_timestamp', 'ar_minor_edit', 'ar_flags', 'ar_text_id', 'ar_page_id', 'ar_len'), array('ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), $oldones), __METHOD__, array('ORDER BY' => 'ar_timestamp')); if ($dbw->numRows($result) < count($timestamps)) { wfDebug(__METHOD__ . ": couldn't find all requested rows\n"); return false; } $revision = null; $restored = 0; while ($row = $dbw->fetchObject($result)) { if ($row->ar_text_id) { // Revision was deleted in 1.5+; text is in // the regular text table, use the reference. // Specify null here so the so the text is // dereferenced for page length info if needed. $revText = null; } else { // Revision was deleted in 1.4 or earlier. // Text is squashed into the archive row, and // a new text table entry will be created for it. $revText = Revision::getRevisionText($row, 'ar_'); } $revision = new Revision(array('page' => $pageId, 'id' => $row->ar_rev_id, 'text' => $revText, 'comment' => $row->ar_comment, 'user' => $row->ar_user, 'user_text' => $row->ar_user_text, 'timestamp' => $row->ar_timestamp, 'minor_edit' => $row->ar_minor_edit, 'text_id' => $row->ar_text_id, 'len' => $row->ar_len)); $revision->insertOn($dbw); $restored++; wfRunHooks('ArticleRevisionUndeleted', array(&$this->title, $revision, $row->ar_page_id)); } // Was anything restored at all? if ($restored == 0) { return 0; } if ($revision) { // Attach the latest revision to the page... $wasnew = $article->updateIfNewerOn($dbw, $revision, $previousRevId); if ($newid || $wasnew) { // Update site stats, link tables, etc $article->createUpdates($revision); } if ($newid) { wfRunHooks('ArticleUndelete', array(&$this->title, true)); Article::onArticleCreate($this->title); } else { wfRunHooks('ArticleUndelete', array(&$this->title, false)); Article::onArticleEdit($this->title); } if ($this->title->getNamespace() == NS_IMAGE) { $update = new HTMLCacheUpdate($this->title, 'imagelinks'); $update->doUpdate(); } } else { // Revision couldn't be created. This is very weird return self::UNDELETE_UNKNOWNERR; } # Now that it's safely stored, take it out of the archive $dbw->delete('archive', array('ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), $oldones), __METHOD__); return $restored; }
/** * Duplicate one page to another, including full histories * Does some basic error-catching, but not as much as the code above [should] * * @param $source Title to duplicate * @param $dest Title to save to * @return bool */ private function duplicate(&$source, &$dest) { global $wgUser, $wgBot; if (!$source->exists() || $dest->exists()) { return false; } # Source doesn't exist, or destination does $dbw = wfGetDB(DB_MASTER); $dbw->begin(); $sid = $source->getArticleId(); # Create an article representing the destination page and save it $destArticle = new Article($dest); $aid = $destArticle->insertOn($dbw); # Perform the revision duplication # An INSERT...SELECT here seems to f**k things up $res = $dbw->select('revision', '*', array('rev_page' => $sid), __METHOD__); if ($res && $dbw->numRows($res) > 0) { while ($row = $dbw->fetchObject($res)) { $values['rev_page'] = $aid; $values['rev_text_id'] = $row->rev_text_id; $values['rev_comment'] = $row->rev_comment; $values['rev_user'] = $row->rev_user; $values['rev_user_text'] = $row->rev_user_text; $values['rev_timestamp'] = $row->rev_timestamp; $values['rev_minor_edit'] = $row->rev_minor_edit; $values['rev_deleted'] = $row->rev_deleted; $dbw->insert('revision', $values, __METHOD__); } $dbw->freeResult($res); } # Update page record $latest = $dbw->selectField('revision', 'MAX(rev_id)', array('rev_page' => $aid), __METHOD__); $rev = Revision::newFromId($latest); $destArticle->updateRevisionOn($dbw, $rev); # Commit transaction $dbw->commit(); # Create a null revision with an explanation; do cache clearances, etc. $dbw->begin(); $comment = wfMsgForContent('duplicator-summary', $source->getPrefixedText()); $nr = Revision::newNullRevision($dbw, $aid, $comment, true); $nid = $nr->insertOn($dbw); $destArticle->updateRevisionOn($dbw, $nr); $destArticle->createUpdates($nr); Article::onArticleCreate($dest); $bot = $wgUser->isAllowed('bot'); RecentChange::notifyNew($nr->getTimestamp(), $dest, true, $wgUser, $comment, $bot); $dest->invalidateCache(); $dbw->commit(); return true; }
/** * This is the meaty bit -- restores archived revisions of the given page * to the cur/old tables. If the page currently exists, all revisions will * be stuffed into old, otherwise the most recent will go into cur. * * @param array $timestamps Pass an empty array to restore all revisions, otherwise list the ones to undelete. * @param string $comment * @param array $fileVersions * @param bool $unsuppress, remove all ar_deleted/fa_deleted restrictions of seletected revs * * @return mixed number of revisions restored or false on failure */ private function undeleteRevisions($timestamps, $unsuppress = false, $comment = '') { if (wfReadOnly()) { return false; } $restoreAll = empty($timestamps); $dbw = wfGetDB(DB_MASTER); # Does this page already exist? We'll have to update it... $article = new Article($this->title); $options = 'FOR UPDATE'; // lock page $page = $dbw->selectRow('page', array('page_id', 'page_latest'), array('page_namespace' => $this->title->getNamespace(), 'page_title' => $this->title->getDBkey()), __METHOD__, $options); if ($page) { $makepage = false; # Page already exists. Import the history, and if necessary # we'll update the latest revision field in the record. $newid = 0; $pageId = $page->page_id; $previousRevId = $page->page_latest; # Get the time span of this page $previousTimestamp = $dbw->selectField('revision', 'rev_timestamp', array('rev_id' => $previousRevId), __METHOD__); if ($previousTimestamp === false) { wfDebug(__METHOD__ . ": existing page refers to a page_latest that does not exist\n"); return 0; } } else { # Have to create a new article... $makepage = true; $previousRevId = 0; $previousTimestamp = 0; } if ($restoreAll) { $oldones = '1 = 1'; # All revisions... } else { $oldts = implode(',', array_map(array(&$dbw, 'addQuotes'), array_map(array(&$dbw, 'timestamp'), $timestamps))); $oldones = "ar_timestamp IN ( {$oldts} )"; } /** * Select each archived revision... */ $result = $dbw->select('archive', array('ar_rev_id', 'ar_text', 'ar_comment', 'ar_user', 'ar_user_text', 'ar_timestamp', 'ar_minor_edit', 'ar_flags', 'ar_text_id', 'ar_deleted', 'ar_page_id', 'ar_len'), array('ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), $oldones), __METHOD__, array('ORDER BY' => 'ar_timestamp')); $ret = $dbw->resultObject($result); $rev_count = $dbw->numRows($result); if (!$rev_count) { wfDebug(__METHOD__ . ": no revisions to restore\n"); return false; // ??? } $ret->seek($rev_count - 1); // move to last $row = $ret->fetchObject(); // get newest archived rev $ret->seek(0); // move back if ($makepage) { // Check the state of the newest to-be version... if (!$unsuppress && $row->ar_deleted & Revision::DELETED_TEXT) { return false; // we can't leave the current revision like this! } // Safe to insert now... $newid = $article->insertOn($dbw); $pageId = $newid; } else { // Check if a deleted revision will become the current revision... if ($row->ar_timestamp > $previousTimestamp) { // Check the state of the newest to-be version... if (!$unsuppress && $row->ar_deleted & Revision::DELETED_TEXT) { return false; // we can't leave the current revision like this! } } } $revision = null; $restored = 0; while ($row = $ret->fetchObject()) { // Check for key dupes due to shitty archive integrity. if ($row->ar_rev_id) { $exists = $dbw->selectField('revision', '1', array('rev_id' => $row->ar_rev_id), __METHOD__); if ($exists) { continue; } // don't throw DB errors } // Insert one revision at a time...maintaining deletion status // unless we are specifically removing all restrictions... $revision = Revision::newFromArchiveRow($row, array('page' => $pageId, 'deleted' => $unsuppress ? 0 : $row->ar_deleted)); $revision->insertOn($dbw); $restored++; wfRunHooks('ArticleRevisionUndeleted', array(&$this->title, $revision, $row->ar_page_id)); } # Now that it's safely stored, take it out of the archive $dbw->delete('archive', array('ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), $oldones), __METHOD__); // Was anything restored at all? if ($restored == 0) { return 0; } if ($revision) { // Attach the latest revision to the page... $wasnew = $article->updateIfNewerOn($dbw, $revision, $previousRevId); if ($newid || $wasnew) { // Update site stats, link tables, etc $article->createUpdates($revision); } if ($newid) { wfRunHooks('ArticleUndelete', array(&$this->title, true, $comment)); Article::onArticleCreate($this->title); } else { wfRunHooks('ArticleUndelete', array(&$this->title, false, $comment)); Article::onArticleEdit($this->title); } if ($this->title->getNamespace() == NS_FILE) { $update = new HTMLCacheUpdate($this->title, 'imagelinks'); $update->doUpdate(); } } else { // Revision couldn't be created. This is very weird return self::UNDELETE_UNKNOWNERR; } return $restored; }