Example #1
0
 public function loadPageData($data = 'fromdb')
 {
     $ret = parent::loadPageData($data);
     // get return code just in case.
     // At this point, we have a valid 'page id' in a local variable.
     // Use it to query the database for 'categorylinks'
     $dbr =& wfGetDB(DB_SLAVE);
     $page = $dbr->tableName('page');
     $catlinks = $dbr->tableName('categorylinks');
     $id = $this->getID();
     $query = "SELECT cl_to FROM {$catlinks} WHERE {$catlinks}.cl_from={$id}";
     $results = $dbr->query($query);
     $count = $dbr->numRows($results);
     if ($count >= 1) {
         while ($row = $dbr->fetchObject($results)) {
             $this->categories[] = $row->cl_to;
         }
     }
     $dbr->freeResult($results);
     return $ret;
 }
Example #2
0
 static function bulkLoad($rows)
 {
     // Preload subthreads
     $top_thread_ids = array();
     $all_thread_rows = $rows;
     $pageIds = array();
     $linkBatch = new LinkBatch();
     $userIds = array();
     $loadEditorsFor = array();
     $dbr = wfGetDB(DB_SLAVE);
     if (!is_array(self::$replyCacheById)) {
         self::$replyCacheById = array();
     }
     // Build a list of threads for which to pull replies, and page IDs to pull data for.
     //  Also, pre-initialise the reply cache.
     foreach ($rows as $row) {
         if ($row->thread_ancestor) {
             $top_thread_ids[] = $row->thread_ancestor;
         } else {
             $top_thread_ids[] = $row->thread_id;
         }
         // Grab page data while we're here.
         if ($row->thread_root) {
             $pageIds[] = $row->thread_root;
         }
         if ($row->thread_summary_page) {
             $pageIds[] = $row->thread_summary_page;
         }
         if (!isset(self::$replyCacheById[$row->thread_id])) {
             self::$replyCacheById[$row->thread_id] = array();
         }
     }
     $all_thread_ids = $top_thread_ids;
     // Pull replies to the threads provided, and as above, pull page IDs to pull data for,
     //  pre-initialise the reply cache, and stash the row object for later use.
     if (count($top_thread_ids)) {
         $res = $dbr->select('thread', '*', array('thread_ancestor' => $top_thread_ids, 'thread_type != ' . $dbr->addQuotes(Threads::TYPE_DELETED)), __METHOD__);
         foreach ($res as $row) {
             // Grab page data while we're here.
             if ($row->thread_root) {
                 $pageIds[] = $row->thread_root;
             }
             if ($row->thread_summary_page) {
                 $pageIds[] = $row->thread_summary_page;
             }
             $all_thread_rows[] = $row;
             $all_thread_ids[$row->thread_id] = $row->thread_id;
         }
     }
     // Pull thread reactions
     if (count($all_thread_ids)) {
         $res = $dbr->select('thread_reaction', '*', array('tr_thread' => $all_thread_ids), __METHOD__);
         foreach ($res as $row) {
             $thread_id = $row->tr_thread;
             $user = $row->tr_user_text;
             $info = array('type' => $row->tr_type, 'user-id' => $row->tr_user, 'user-name' => $row->tr_user_text, 'value' => $row->tr_value);
             $type = $info['type'];
             $user = $info['user-name'];
             if (!isset(self::$reactionCacheById[$thread_id])) {
                 self::$reactionCacheById[$thread_id] = array();
             }
             if (!isset(self::$reactionCacheById[$thread_id][$type])) {
                 self::$reactionCacheById[$thread_id][$type] = array();
             }
             self::$reactionCacheById[$thread_id][$type][$user] = $info;
         }
     }
     // Preload page data (restrictions, and preload Article object with everything from
     //  the page table. Also, precache the title and article objects for pulling later.
     $articlesById = array();
     if (count($pageIds)) {
         // Pull restriction info. Needs to come first because otherwise it's done per
         //  page by loadPageData.
         $restrictionRows = array_fill_keys($pageIds, array());
         $res = $dbr->select('page_restrictions', '*', array('pr_page' => $pageIds), __METHOD__);
         foreach ($res as $row) {
             $restrictionRows[$row->pr_page][] = $row;
         }
         $res = $dbr->select('page', '*', array('page_id' => $pageIds), __METHOD__);
         foreach ($res as $row) {
             $t = Title::newFromRow($row);
             if (isset($restrictionRows[$t->getArticleId()])) {
                 $t->loadRestrictionsFromRows($restrictionRows[$t->getArticleId()], $row->page_restrictions);
             }
             $article = new Article($t);
             $article->loadPageData($row);
             self::$titleCacheById[$t->getArticleId()] = $t;
             $articlesById[$article->getId()] = $article;
             if (count(self::$titleCacheById) > 10000) {
                 self::$titleCacheById = array();
             }
         }
     }
     // For every thread we have a row object for, load a Thread object, add the user and
     //  user talk pages to a link batch, cache the relevant user id/name pair, and
     //  populate the reply cache.
     foreach ($all_thread_rows as $row) {
         $thread = Thread::newFromRow($row, null);
         if (isset($articlesById[$thread->rootId])) {
             $thread->root = $articlesById[$thread->rootId];
         }
         // User cache data
         $t = Title::makeTitleSafe(NS_USER, $row->thread_author_name);
         $linkBatch->addObj($t);
         $t = Title::makeTitleSafe(NS_USER_TALK, $row->thread_author_name);
         $linkBatch->addObj($t);
         User::$idCacheByName[$row->thread_author_name] = $row->thread_author_id;
         $userIds[$row->thread_author_id] = true;
         if ($row->thread_editedness > Threads::EDITED_BY_AUTHOR) {
             $loadEditorsFor[$row->thread_root] = $thread;
             $thread->setEditors(array());
         }
     }
     // Pull list of users who have edited
     if (count($loadEditorsFor)) {
         $res = $dbr->select('revision', array('rev_user_text', 'rev_page'), array('rev_page' => array_keys($loadEditorsFor), 'rev_parent_id != ' . $dbr->addQuotes(0)), __METHOD__);
         foreach ($res as $row) {
             $pageid = $row->rev_page;
             $editor = $row->rev_user_text;
             $t = $loadEditorsFor[$pageid];
             $t->addEditor($editor);
         }
     }
     // Pull link batch data.
     $linkBatch->execute();
     $threads = array();
     // Fill and return an array with the threads that were actually requested.
     foreach ($rows as $row) {
         $threads[$row->thread_id] = Threads::$cache_by_id[$row->thread_id];
     }
     return $threads;
 }
Example #3
0
 /**
  * Attempt submission (no UI)
  *
  * @param array $result Array to add statuses to, currently with the
  *   possible keys:
  *   - spam (string): Spam string from content if any spam is detected by
  *     matchSpamRegex.
  *   - sectionanchor (string): Section anchor for a section save.
  *   - nullEdit (boolean): Set if doEditContent is OK.  True if null edit,
  *     false otherwise.
  *   - redirect (bool): Set if doEditContent is OK. True if resulting
  *     revision is a redirect.
  * @param bool $bot True if edit is being made under the bot right.
  *
  * @return Status Status object, possibly with a message, but always with
  *   one of the AS_* constants in $status->value,
  *
  * @todo FIXME: This interface is TERRIBLE, but hard to get rid of due to
  *   various error display idiosyncrasies. There are also lots of cases
  *   where error metadata is set in the object and retrieved later instead
  *   of being returned, e.g. AS_CONTENT_TOO_BIG and
  *   AS_BLOCKED_PAGE_FOR_USER. All that stuff needs to be cleaned up some
  * time.
  */
 function internalAttemptSave(&$result, $bot = false)
 {
     global $wgUser, $wgRequest, $wgParser, $wgMaxArticleSize;
     $status = Status::newGood();
     wfProfileIn(__METHOD__);
     wfProfileIn(__METHOD__ . '-checks');
     if (!wfRunHooks('EditPage::attemptSave', array($this))) {
         wfDebug("Hook 'EditPage::attemptSave' aborted article saving\n");
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     $spam = $wgRequest->getText('wpAntispam');
     if ($spam !== '') {
         wfDebugLog('SimpleAntiSpam', $wgUser->getName() . ' editing "' . $this->mTitle->getPrefixedText() . '" submitted bogus field "' . $spam . '"');
         $status->fatal('spamprotectionmatch', false);
         $status->value = self::AS_SPAM_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     try {
         # Construct Content object
         $textbox_content = $this->toEditContent($this->textbox1);
     } catch (MWContentSerializationException $ex) {
         $status->fatal('content-failed-to-parse', $this->contentModel, $this->contentFormat, $ex->getMessage());
         $status->value = self::AS_PARSE_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     # Check image redirect
     if ($this->mTitle->getNamespace() == NS_FILE && $textbox_content->isRedirect() && !$wgUser->isAllowed('upload')) {
         $code = $wgUser->isAnon() ? self::AS_IMAGE_REDIRECT_ANON : self::AS_IMAGE_REDIRECT_LOGGED;
         $status->setResult(false, $code);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     # Check for spam
     $match = self::matchSummarySpamRegex($this->summary);
     if ($match === false && $this->section == 'new') {
         # $wgSpamRegex is enforced on this new heading/summary because, unlike
         # regular summaries, it is added to the actual wikitext.
         if ($this->sectiontitle !== '') {
             # This branch is taken when the API is used with the 'sectiontitle' parameter.
             $match = self::matchSpamRegex($this->sectiontitle);
         } else {
             # This branch is taken when the "Add Topic" user interface is used, or the API
             # is used with the 'summary' parameter.
             $match = self::matchSpamRegex($this->summary);
         }
     }
     if ($match === false) {
         $match = self::matchSpamRegex($this->textbox1);
     }
     if ($match !== false) {
         $result['spam'] = $match;
         $ip = $wgRequest->getIP();
         $pdbk = $this->mTitle->getPrefixedDBkey();
         $match = str_replace("\n", '', $match);
         wfDebugLog('SpamRegex', "{$ip} spam regex hit [[{$pdbk}]]: \"{$match}\"");
         $status->fatal('spamprotectionmatch', $match);
         $status->value = self::AS_SPAM_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if (!wfRunHooks('EditFilter', array($this, $this->textbox1, $this->section, &$this->hookError, $this->summary))) {
         # Error messages etc. could be handled within the hook...
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     } elseif ($this->hookError != '') {
         # ...or the hook could be expecting us to produce an error
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR_EXPECTED;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if ($wgUser->isBlockedFrom($this->mTitle, false)) {
         // Auto-block user's IP if the account was "hard" blocked
         $wgUser->spreadAnyEditBlock();
         # Check block state against master, thus 'false'.
         $status->setResult(false, self::AS_BLOCKED_PAGE_FOR_USER);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     $this->kblength = (int) (strlen($this->textbox1) / 1024);
     if ($this->kblength > $wgMaxArticleSize) {
         // Error will be displayed by showEditForm()
         $this->tooBig = true;
         $status->setResult(false, self::AS_CONTENT_TOO_BIG);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if (!$wgUser->isAllowed('edit')) {
         if ($wgUser->isAnon()) {
             $status->setResult(false, self::AS_READ_ONLY_PAGE_ANON);
             wfProfileOut(__METHOD__ . '-checks');
             wfProfileOut(__METHOD__);
             return $status;
         } else {
             $status->fatal('readonlytext');
             $status->value = self::AS_READ_ONLY_PAGE_LOGGED;
             wfProfileOut(__METHOD__ . '-checks');
             wfProfileOut(__METHOD__);
             return $status;
         }
     }
     if ($this->contentModel !== $this->mTitle->getContentModel() && !$wgUser->isAllowed('editcontentmodel')) {
         $status->setResult(false, self::AS_NO_CHANGE_CONTENT_MODEL);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if (wfReadOnly()) {
         $status->fatal('readonlytext');
         $status->value = self::AS_READ_ONLY_PAGE;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if ($wgUser->pingLimiter() || $wgUser->pingLimiter('linkpurge', 0)) {
         $status->fatal('actionthrottledtext');
         $status->value = self::AS_RATE_LIMITED;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     # If the article has been deleted while editing, don't save it without
     # confirmation
     if ($this->wasDeletedSinceLastEdit() && !$this->recreate) {
         $status->setResult(false, self::AS_ARTICLE_WAS_DELETED);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     wfProfileOut(__METHOD__ . '-checks');
     # Load the page data from the master. If anything changes in the meantime,
     # we detect it by using page_latest like a token in a 1 try compare-and-swap.
     $this->mArticle->loadPageData('fromdbmaster');
     $new = !$this->mArticle->exists();
     if ($new) {
         // Late check for create permission, just in case *PARANOIA*
         if (!$this->mTitle->userCan('create', $wgUser)) {
             $status->fatal('nocreatetext');
             $status->value = self::AS_NO_CREATE_PERMISSION;
             wfDebug(__METHOD__ . ": no create permission\n");
             wfProfileOut(__METHOD__);
             return $status;
         }
         // Don't save a new page if it's blank or if it's a MediaWiki:
         // message with content equivalent to default (allow empty pages
         // in this case to disable messages, see bug 50124)
         $defaultMessageText = $this->mTitle->getDefaultMessageText();
         if ($this->mTitle->getNamespace() === NS_MEDIAWIKI && $defaultMessageText !== false) {
             $defaultText = $defaultMessageText;
         } else {
             $defaultText = '';
         }
         if (!$this->allowBlankArticle && $this->textbox1 === $defaultText) {
             $this->blankArticle = true;
             $status->fatal('blankarticle');
             $status->setResult(false, self::AS_BLANK_ARTICLE);
             wfProfileOut(__METHOD__);
             return $status;
         }
         if (!$this->runPostMergeFilters($textbox_content, $status, $wgUser)) {
             wfProfileOut(__METHOD__);
             return $status;
         }
         $content = $textbox_content;
         $result['sectionanchor'] = '';
         if ($this->section == 'new') {
             if ($this->sectiontitle !== '') {
                 // Insert the section title above the content.
                 $content = $content->addSectionHeader($this->sectiontitle);
             } elseif ($this->summary !== '') {
                 // Insert the section title above the content.
                 $content = $content->addSectionHeader($this->summary);
             }
             $this->summary = $this->newSectionSummary($result['sectionanchor']);
         }
         $status->value = self::AS_SUCCESS_NEW_ARTICLE;
     } else {
         # not $new
         # Article exists. Check for edit conflict.
         $this->mArticle->clear();
         # Force reload of dates, etc.
         $timestamp = $this->mArticle->getTimestamp();
         wfDebug("timestamp: {$timestamp}, edittime: {$this->edittime}\n");
         if ($timestamp != $this->edittime) {
             $this->isConflict = true;
             if ($this->section == 'new') {
                 if ($this->mArticle->getUserText() == $wgUser->getName() && $this->mArticle->getComment() == $this->newSectionSummary()) {
                     // Probably a duplicate submission of a new comment.
                     // This can happen when squid resends a request after
                     // a timeout but the first one actually went through.
                     wfDebug(__METHOD__ . ": duplicate new section submission; trigger edit conflict!\n");
                 } else {
                     // New comment; suppress conflict.
                     $this->isConflict = false;
                     wfDebug(__METHOD__ . ": conflict suppressed; new section\n");
                 }
             } elseif ($this->section == '' && Revision::userWasLastToEdit(DB_MASTER, $this->mTitle->getArticleID(), $wgUser->getId(), $this->edittime)) {
                 # Suppress edit conflict with self, except for section edits where merging is required.
                 wfDebug(__METHOD__ . ": Suppressing edit conflict, same user.\n");
                 $this->isConflict = false;
             }
         }
         // If sectiontitle is set, use it, otherwise use the summary as the section title.
         if ($this->sectiontitle !== '') {
             $sectionTitle = $this->sectiontitle;
         } else {
             $sectionTitle = $this->summary;
         }
         $content = null;
         if ($this->isConflict) {
             wfDebug(__METHOD__ . ": conflict! getting section '{$this->section}' for time '{$this->edittime}'" . " (article time '{$timestamp}')\n");
             $content = $this->mArticle->replaceSectionContent($this->section, $textbox_content, $sectionTitle, $this->edittime);
         } else {
             wfDebug(__METHOD__ . ": getting section '{$this->section}'\n");
             $content = $this->mArticle->replaceSectionContent($this->section, $textbox_content, $sectionTitle);
         }
         if (is_null($content)) {
             wfDebug(__METHOD__ . ": activating conflict; section replace failed.\n");
             $this->isConflict = true;
             $content = $textbox_content;
             // do not try to merge here!
         } elseif ($this->isConflict) {
             # Attempt merge
             if ($this->mergeChangesIntoContent($content)) {
                 // Successful merge! Maybe we should tell the user the good news?
                 $this->isConflict = false;
                 wfDebug(__METHOD__ . ": Suppressing edit conflict, successful merge.\n");
             } else {
                 $this->section = '';
                 $this->textbox1 = ContentHandler::getContentText($content);
                 wfDebug(__METHOD__ . ": Keeping edit conflict, failed merge.\n");
             }
         }
         if ($this->isConflict) {
             $status->setResult(false, self::AS_CONFLICT_DETECTED);
             wfProfileOut(__METHOD__);
             return $status;
         }
         if (!$this->runPostMergeFilters($content, $status, $wgUser)) {
             wfProfileOut(__METHOD__);
             return $status;
         }
         if ($this->section == 'new') {
             // Handle the user preference to force summaries here
             if (!$this->allowBlankSummary && trim($this->summary) == '') {
                 $this->missingSummary = true;
                 $status->fatal('missingsummary');
                 // or 'missingcommentheader' if $section == 'new'. Blegh
                 $status->value = self::AS_SUMMARY_NEEDED;
                 wfProfileOut(__METHOD__);
                 return $status;
             }
             // Do not allow the user to post an empty comment
             if ($this->textbox1 == '') {
                 $this->missingComment = true;
                 $status->fatal('missingcommenttext');
                 $status->value = self::AS_TEXTBOX_EMPTY;
                 wfProfileOut(__METHOD__);
                 return $status;
             }
         } elseif (!$this->allowBlankSummary && !$content->equals($this->getOriginalContent($wgUser)) && !$content->isRedirect() && md5($this->summary) == $this->autoSumm) {
             $this->missingSummary = true;
             $status->fatal('missingsummary');
             $status->value = self::AS_SUMMARY_NEEDED;
             wfProfileOut(__METHOD__);
             return $status;
         }
         # All's well
         wfProfileIn(__METHOD__ . '-sectionanchor');
         $sectionanchor = '';
         if ($this->section == 'new') {
             $this->summary = $this->newSectionSummary($sectionanchor);
         } elseif ($this->section != '') {
             # Try to get a section anchor from the section source, redirect
             # to edited section if header found.
             # XXX: Might be better to integrate this into Article::replaceSection
             # for duplicate heading checking and maybe parsing.
             $hasmatch = preg_match("/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches);
             # We can't deal with anchors, includes, html etc in the header for now,
             # headline would need to be parsed to improve this.
             if ($hasmatch && strlen($matches[2]) > 0) {
                 $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText($matches[2]);
             }
         }
         $result['sectionanchor'] = $sectionanchor;
         wfProfileOut(__METHOD__ . '-sectionanchor');
         // Save errors may fall down to the edit form, but we've now
         // merged the section into full text. Clear the section field
         // so that later submission of conflict forms won't try to
         // replace that into a duplicated mess.
         $this->textbox1 = $this->toEditText($content);
         $this->section = '';
         $status->value = self::AS_SUCCESS_UPDATE;
     }
     // Check for length errors again now that the section is merged in
     $this->kblength = (int) (strlen($this->toEditText($content)) / 1024);
     if ($this->kblength > $wgMaxArticleSize) {
         $this->tooBig = true;
         $status->setResult(false, self::AS_MAX_ARTICLE_SIZE_EXCEEDED);
         wfProfileOut(__METHOD__);
         return $status;
     }
     $flags = EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY | ($new ? EDIT_NEW : EDIT_UPDATE) | ($this->minoredit && !$this->isNew ? EDIT_MINOR : 0) | ($bot ? EDIT_FORCE_BOT : 0);
     $doEditStatus = $this->mArticle->doEditContent($content, $this->summary, $flags, false, null, $content->getDefaultFormat());
     if (!$doEditStatus->isOK()) {
         // Failure from doEdit()
         // Show the edit conflict page for certain recognized errors from doEdit(),
         // but don't show it for errors from extension hooks
         $errors = $doEditStatus->getErrorsArray();
         if (in_array($errors[0][0], array('edit-gone-missing', 'edit-conflict', 'edit-already-exists'))) {
             $this->isConflict = true;
             // Destroys data doEdit() put in $status->value but who cares
             $doEditStatus->value = self::AS_END;
         }
         wfProfileOut(__METHOD__);
         return $doEditStatus;
     }
     $result['nullEdit'] = $doEditStatus->hasMessage('edit-no-change');
     if ($result['nullEdit']) {
         // We don't know if it was a null edit until now, so increment here
         $wgUser->pingLimiter('linkpurge');
     }
     $result['redirect'] = $content->isRedirect();
     $this->updateWatchlist();
     wfProfileOut(__METHOD__);
     return $status;
 }
 /**
  *   The main function
  */
 function execute($par)
 {
     global $wgRequest, $wgUser, $wgOut, $wgImportVideoSources;
     if ($wgUser->isBlocked()) {
         $wgOut->blockedPage();
         return;
     }
     wfLoadExtensionMessages('Importvideo');
     if ($wgRequest->getVal('popup') == 'true') {
         $wgOut->setArticleBodyOnly(true);
     }
     $this->setHeaders();
     $source = $this->mSource = $wgRequest->getVal('source', 'youtube');
     $target = isset($par) ? $par : $wgRequest->getVal('target');
     $query = $wgRequest->getVal('q');
     $me = Title::makeTitle(NS_SPECIAL, "Importvideo");
     $wasnew = $this->getRequest()->getVal('wasnew');
     // some sanity checks on the target
     if ($target && !$wasnew) {
         $title = Title::newFromURL($target);
         if (!$title || !$title->exists()) {
             $wgOut->addHTML("Error: target article does not exist.");
             return;
         } else {
             $article = new Article($title);
             $article->loadPageData();
             if ($article->mIsRedirect) {
                 $wgOut->addHTML("Error: target article is a redirect.");
                 return;
             }
         }
     }
     $wgOut->addHTML("<div id='importvideo'>");
     $wgOut->addHTML("<h2>" . wfMsg('add_a_video') . "</h2>");
     # changing target article feature
     $search = $wgRequest->getVal("dosearch", null);
     if ($search != null) {
         $this->doSearch($target, $orderby, $query, $search);
         return;
     }
     $sp = null;
     switch ($source) {
         case 'howcast':
             $sp = new ImportvideoHowcast($source);
             break;
         case 'youtube':
         default:
             $sp = new ImportvideoYoutube($source);
             break;
     }
     // handle special cases where user is adding a video to a new article or by category
     if ($wgRequest->getVal('new') || $wgRequest->getVal('wasnew')) {
         if ($wgRequest->getVal('new')) {
             $t = $this->getNewArticleWithoutVideo();
             $target = $t->getText();
         } else {
             $t = Title::newFromText($target);
         }
         $wgRequest->setVal('target', $target);
     } else {
         if ($wgRequest->getVal('category') && $target == '') {
             $t = $this->getTitleFromCategory($wgRequest->getVal('category'));
             $target = $t->getText();
             $wgRequest->setVal('target', $target);
         }
     }
     // construct base url to switch between sources
     $url = $me->getFullURL() . "?target=" . urlencode($target) . "&q=" . urlencode($query) . $this->getURLExtras() . "&source=";
     $title = Title::newFromText($target);
     if (!trim($target)) {
         $wgOut->addHTML("Error: no target specified.");
         return;
     }
     $target = $title->getText();
     //get the steps and intro to show to the user
     $r = Revision::newFromTitle($title);
     $text = "";
     if ($r) {
         $text = $r->getText();
     }
     $article = new Article($title);
     $extra = $article->getSection($text, 0);
     $steps = "";
     for ($i = 1; $i < 3; $i++) {
         $xx = $article->getSection($text, $i);
         if (preg_match("/^==[ ]+" . wfMsg('steps') . "/", $xx)) {
             $steps = $xx;
             break;
         }
     }
     $extra = preg_replace("/{{[^}]*}}/", "", $extra);
     $extra = $wgOut->parse($extra);
     $steps = $wgOut->parse($steps);
     $cancel = "";
     $nextlink = "/Special:Importvideo?new=1&skip={$title->getArticleID()}";
     if ($wgRequest->getVal('category')) {
         $nextlink = "/Special:Importvideo?category=" . urlencode($wgRequest->getVal('category'));
     }
     if ($wgRequest->getVal('popup') != 'true') {
         $wgOut->addHTML("<div class='article_title'>\n\t\t\t\t" . wfMsg('importvideo_article') . "- <a href='{$title->getFullURL()}' target='new'>" . wfMsg('howto', $title->getText()) . "</a>");
         $wgOut->addHTML("<spanid='showhide' style='font-size: 80%; text-align:right; font-weight: normal;'>\n\t\t\t\t\t(<a href='{$nextlink}' accesskey='s'>next article</a> |\n\t\t\t\t\t<a href='{$url}&dosearch=1' accesskey='s'>" . wfMsg('importvideo_searchforarticle') . "</a> {$cancel} )\n\t\t\t\t</span>");
         if ($wgRequest->getVal('category')) {
             $wgOut->addHTML("You are adding videos to articles from the \"{$wgRequest->getVal('category')}\" category.\n\t\t\t\t\t(<a href='#'>change</a>)");
         }
         $wgOut->addHTML("</div>");
         $wgOut->addHTML("<div class='video_related wh_block'>\n\t\t\t\t\t<h2>Introduction</h2>\n\t\t\t\t\t{$extra}\n\t\t\t\t\t<br clear='all'/>\n\t\t\t\t\t<div id='showhide' style='font-size: 80%; text-align:right;'>\n\t\t\t\t\t\t<span id='showsteps'><a href='#' onclick='javascript:showhidesteps(); return false;'>" . wfMsg('importvideo_showsteps') . "</a></span>\n\t\t\t\t\t\t<span id='hidesteps' style='display: none;'><a href='#' onclick='javascript:showhidesteps(); return false;'>" . wfMsg('importvideo_hidesteps') . "</a></span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div id='stepsarea' style='display: none;'>\n\t\t\t\t\t{$steps}\n\t\t\t\t\t</div>\n\t\t\t\t\t<br clear='all'/>\n\t\t\t\t</div>\n\t\t\t");
     }
     $wgOut->addHTML("<script type='text/javascript' src='" . wfGetPad('/extensions/min/f/extensions/wikihow/video/importvideo.js?rev=') . WH_SITEREV . "'> </script>\t");
     $wgOut->addHTML("<link rel='stylesheet' type='text/css' href='" . wfGetPad('/extensions/min/f/extensions/wikihow/video/importvideo.css?rev=') . WH_SITEREV . "' />");
     $wgOut->addHTML("<script type='text/javascript'>\n\t\t\tvar isPopUp = " . ($wgRequest->getVal('popup') ? "true" : "false") . ";\n\t\t\t</script>");
     if (!$wgRequest->wasPosted()) {
         $wgOut->addHTML(wfMsgWikiHtml('add_video_info'));
         # HEADER for import page
         $url = $me->getFullURL() . "?target=" . urlencode($target) . "&q=" . urlencode($query) . $this->getURLExtras() . "&source=";
         // refine form
         $orderby = $wgRequest->getVal('orderby', 'relevance');
         $wgOut->addHTML($this->refineForm($me, $target, $wgRequest->getVal('popup') == 'true', $query, $orderby));
         // sources tab
         $wgOut->addHTML("<ul id='importvideo_search_tabs'>");
         foreach ($wgImportVideoSources as $s) {
             $selected = $s == $source ? ' class="iv_selected"' : '';
             $wgOut->addHTML("<li{$selected}><a href='{$url}{$s}'>" . wfMsg('importvideo_source_' . $s) . "</a></li>");
         }
         $wgOut->addHTML("</ul>");
         $vt = Title::makeTitle(NS_VIDEO, $target);
         if ($vt->getArticleID() > 0 && $wgRequest->getVal('popup') != 'true') {
             $wgOut->addHTML("<div class='wh_block importvideo_main'>" . wfMsgExt('importvideo_videoexists', 'parse', $vt->getFullText()) . "</div>");
         }
     }
     //special class just for pop-ups
     if ($wgRequest->getVal('popup')) {
         $pop_class = 'importvideo_pop';
     }
     $wgOut->addHTML("<div class='wh_block importvideo_main {$pop_class}'>");
     $sp->execute($par);
     $wgOut->addHTML("</div>");
     //Bebeth: took out extra closing div
     $wgOut->addHTML("</div>");
     //Scott: put a brand new extra closing div in (take that, Bebeth!)
 }
Example #5
0
 /**
  * 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 $timestamps Array: pass an empty array to restore all revisions, otherwise list the ones to undelete.
  * @param $comment String
  * @param $unsuppress Boolean: 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);
     # Load latest data for the current page (bug 31179)
     $article->loadPageData('fromdbmaster');
     $oldcountable = $article->isCountable();
     $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;
     foreach ($ret as $row) {
         // 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;
     }
     $created = (bool) $newid;
     // Attach the latest revision to the page...
     $wasnew = $article->updateIfNewerOn($dbw, $revision, $previousRevId);
     if ($created || $wasnew) {
         // Update site stats, link tables, etc
         $user = User::newFromName($revision->getRawUserText(), false);
         $article->doEditUpdates($revision, $user, array('created' => $created, 'oldcountable' => $oldcountable));
     }
     wfRunHooks('ArticleUndelete', array(&$this->title, $created, $comment));
     if ($this->title->getNamespace() == NS_FILE) {
         $update = new HTMLCacheUpdate($this->title, 'imagelinks');
         $update->doUpdate();
     }
     return $restored;
 }
 function loadPageData($data = 'fromdb')
 {
     Article::loadPageData($data);
     $this->mIsRedirect = true;
 }
Example #7
0
 /**
  * Attempt submission (no UI)
  *
  * @param $result
  * @param $bot bool
  *
  * @return Status object, possibly with a message, but always with one of the AS_* constants in $status->value,
  *
  * FIXME: This interface is TERRIBLE, but hard to get rid of due to various error display idiosyncrasies. There are
  * also lots of cases where error metadata is set in the object and retrieved later instead of being returned, e.g.
  * AS_CONTENT_TOO_BIG and AS_BLOCKED_PAGE_FOR_USER. All that stuff needs to be cleaned up some time.
  */
 function internalAttemptSave(&$result, $bot = false)
 {
     global $wgUser, $wgRequest, $wgParser, $wgMaxArticleSize;
     $status = Status::newGood();
     wfProfileIn(__METHOD__);
     wfProfileIn(__METHOD__ . '-checks');
     if (!wfRunHooks('EditPage::attemptSave', array($this))) {
         wfDebug("Hook 'EditPage::attemptSave' aborted article saving\n");
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     # Check image redirect
     if ($this->mTitle->getNamespace() == NS_FILE && Title::newFromRedirect($this->textbox1) instanceof Title && !$wgUser->isAllowed('upload')) {
         $code = $wgUser->isAnon() ? self::AS_IMAGE_REDIRECT_ANON : self::AS_IMAGE_REDIRECT_LOGGED;
         $status->setResult(false, $code);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     # Check for spam
     $match = self::matchSummarySpamRegex($this->summary);
     if ($match === false) {
         $match = self::matchSpamRegex($this->textbox1);
     }
     if ($match !== false) {
         $result['spam'] = $match;
         $ip = $wgRequest->getIP();
         $pdbk = $this->mTitle->getPrefixedDBkey();
         $match = str_replace("\n", '', $match);
         wfDebugLog('SpamRegex', "{$ip} spam regex hit [[{$pdbk}]]: \"{$match}\"");
         $status->fatal('spamprotectionmatch', $match);
         $status->value = self::AS_SPAM_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if (!wfRunHooks('EditFilter', array($this, $this->textbox1, $this->section, &$this->hookError, $this->summary))) {
         # Error messages etc. could be handled within the hook...
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     } elseif ($this->hookError != '') {
         # ...or the hook could be expecting us to produce an error
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR_EXPECTED;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if ($wgUser->isBlockedFrom($this->mTitle, false)) {
         // Auto-block user's IP if the account was "hard" blocked
         $wgUser->spreadAnyEditBlock();
         # Check block state against master, thus 'false'.
         $status->setResult(false, self::AS_BLOCKED_PAGE_FOR_USER);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     $this->kblength = (int) (strlen($this->textbox1) / 1024);
     if ($this->kblength > $wgMaxArticleSize) {
         // Error will be displayed by showEditForm()
         $this->tooBig = true;
         $status->setResult(false, self::AS_CONTENT_TOO_BIG);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if (!$wgUser->isAllowed('edit')) {
         if ($wgUser->isAnon()) {
             $status->setResult(false, self::AS_READ_ONLY_PAGE_ANON);
             wfProfileOut(__METHOD__ . '-checks');
             wfProfileOut(__METHOD__);
             return $status;
         } else {
             $status->fatal('readonlytext');
             $status->value = self::AS_READ_ONLY_PAGE_LOGGED;
             wfProfileOut(__METHOD__ . '-checks');
             wfProfileOut(__METHOD__);
             return $status;
         }
     }
     if (wfReadOnly()) {
         $status->fatal('readonlytext');
         $status->value = self::AS_READ_ONLY_PAGE;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if ($wgUser->pingLimiter()) {
         $status->fatal('actionthrottledtext');
         $status->value = self::AS_RATE_LIMITED;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     # If the article has been deleted while editing, don't save it without
     # confirmation
     if ($this->wasDeletedSinceLastEdit() && !$this->recreate) {
         $status->setResult(false, self::AS_ARTICLE_WAS_DELETED);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     wfProfileOut(__METHOD__ . '-checks');
     # Load the page data from the master. If anything changes in the meantime,
     # we detect it by using page_latest like a token in a 1 try compare-and-swap.
     $this->mArticle->loadPageData('fromdbmaster');
     $new = !$this->mArticle->exists();
     if ($new) {
         // Late check for create permission, just in case *PARANOIA*
         if (!$this->mTitle->userCan('create')) {
             $status->fatal('nocreatetext');
             $status->value = self::AS_NO_CREATE_PERMISSION;
             wfDebug(__METHOD__ . ": no create permission\n");
             wfProfileOut(__METHOD__);
             return $status;
         }
         # Don't save a new article if it's blank.
         if ($this->textbox1 == '') {
             $status->setResult(false, self::AS_BLANK_ARTICLE);
             wfProfileOut(__METHOD__);
             return $status;
         }
         // Run post-section-merge edit filter
         if (!wfRunHooks('EditFilterMerged', array($this, $this->textbox1, &$this->hookError, $this->summary))) {
             # Error messages etc. could be handled within the hook...
             $status->fatal('hookaborted');
             $status->value = self::AS_HOOK_ERROR;
             wfProfileOut(__METHOD__);
             return $status;
         } elseif ($this->hookError != '') {
             # ...or the hook could be expecting us to produce an error
             $status->fatal('hookaborted');
             $status->value = self::AS_HOOK_ERROR_EXPECTED;
             wfProfileOut(__METHOD__);
             return $status;
         }
         $text = $this->textbox1;
         $result['sectionanchor'] = '';
         if ($this->section == 'new') {
             if ($this->sectiontitle !== '') {
                 // Insert the section title above the content.
                 $text = wfMessage('newsectionheaderdefaultlevel', $this->sectiontitle)->inContentLanguage()->text() . "\n\n" . $text;
                 // Jump to the new section
                 $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText($this->sectiontitle);
                 // If no edit summary was specified, create one automatically from the section
                 // title and have it link to the new section. Otherwise, respect the summary as
                 // passed.
                 if ($this->summary === '') {
                     $cleanSectionTitle = $wgParser->stripSectionName($this->sectiontitle);
                     $this->summary = wfMessage('newsectionsummary')->rawParams($cleanSectionTitle)->inContentLanguage()->text();
                 }
             } elseif ($this->summary !== '') {
                 // Insert the section title above the content.
                 $text = wfMessage('newsectionheaderdefaultlevel', $this->summary)->inContentLanguage()->text() . "\n\n" . $text;
                 // Jump to the new section
                 $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText($this->summary);
                 // Create a link to the new section from the edit summary.
                 $cleanSummary = $wgParser->stripSectionName($this->summary);
                 $this->summary = wfMessage('newsectionsummary')->rawParams($cleanSummary)->inContentLanguage()->text();
             }
         }
         $status->value = self::AS_SUCCESS_NEW_ARTICLE;
     } else {
         # Article exists. Check for edit conflict.
         $timestamp = $this->mArticle->getTimestamp();
         wfDebug("timestamp: {$timestamp}, edittime: {$this->edittime}\n");
         if ($timestamp != $this->edittime) {
             $this->isConflict = true;
             if ($this->section == 'new') {
                 if ($this->mArticle->getUserText() == $wgUser->getName() && $this->mArticle->getComment() == $this->summary) {
                     // Probably a duplicate submission of a new comment.
                     // This can happen when squid resends a request after
                     // a timeout but the first one actually went through.
                     wfDebug(__METHOD__ . ": duplicate new section submission; trigger edit conflict!\n");
                 } else {
                     // New comment; suppress conflict.
                     $this->isConflict = false;
                     wfDebug(__METHOD__ . ": conflict suppressed; new section\n");
                 }
             } elseif ($this->section == '' && Revision::userWasLastToEdit(DB_MASTER, $this->mTitle->getArticleID(), $wgUser->getId(), $this->edittime)) {
                 # Suppress edit conflict with self, except for section edits where merging is required.
                 wfDebug(__METHOD__ . ": Suppressing edit conflict, same user.\n");
                 $this->isConflict = false;
             }
         }
         // If sectiontitle is set, use it, otherwise use the summary as the section title (for
         // backwards compatibility with old forms/bots).
         if ($this->sectiontitle !== '') {
             $sectionTitle = $this->sectiontitle;
         } else {
             $sectionTitle = $this->summary;
         }
         if ($this->isConflict) {
             wfDebug(__METHOD__ . ": conflict! getting section '{$this->section}' for time '{$this->edittime}' (article time '{$timestamp}')\n");
             $text = $this->mArticle->replaceSection($this->section, $this->textbox1, $sectionTitle, $this->edittime);
         } else {
             wfDebug(__METHOD__ . ": getting section '{$this->section}'\n");
             $text = $this->mArticle->replaceSection($this->section, $this->textbox1, $sectionTitle);
         }
         if (is_null($text)) {
             wfDebug(__METHOD__ . ": activating conflict; section replace failed.\n");
             $this->isConflict = true;
             $text = $this->textbox1;
             // do not try to merge here!
         } elseif ($this->isConflict) {
             # Attempt merge
             if ($this->mergeChangesInto($text)) {
                 // Successful merge! Maybe we should tell the user the good news?
                 $this->isConflict = false;
                 wfDebug(__METHOD__ . ": Suppressing edit conflict, successful merge.\n");
             } else {
                 $this->section = '';
                 $this->textbox1 = $text;
                 wfDebug(__METHOD__ . ": Keeping edit conflict, failed merge.\n");
             }
         }
         if ($this->isConflict) {
             $status->setResult(false, self::AS_CONFLICT_DETECTED);
             wfProfileOut(__METHOD__);
             return $status;
         }
         // Run post-section-merge edit filter
         if (!wfRunHooks('EditFilterMerged', array($this, $text, &$this->hookError, $this->summary))) {
             # Error messages etc. could be handled within the hook...
             $status->fatal('hookaborted');
             $status->value = self::AS_HOOK_ERROR;
             wfProfileOut(__METHOD__);
             return $status;
         } elseif ($this->hookError != '') {
             # ...or the hook could be expecting us to produce an error
             $status->fatal('hookaborted');
             $status->value = self::AS_HOOK_ERROR_EXPECTED;
             wfProfileOut(__METHOD__);
             return $status;
         }
         # Handle the user preference to force summaries here, but not for null edits
         if ($this->section != 'new' && !$this->allowBlankSummary && $this->getOriginalContent() != $text && !Title::newFromRedirect($text)) {
             if (md5($this->summary) == $this->autoSumm) {
                 $this->missingSummary = true;
                 $status->fatal('missingsummary');
                 $status->value = self::AS_SUMMARY_NEEDED;
                 wfProfileOut(__METHOD__);
                 return $status;
             }
         }
         # And a similar thing for new sections
         if ($this->section == 'new' && !$this->allowBlankSummary) {
             if (trim($this->summary) == '') {
                 $this->missingSummary = true;
                 $status->fatal('missingsummary');
                 // or 'missingcommentheader' if $section == 'new'. Blegh
                 $status->value = self::AS_SUMMARY_NEEDED;
                 wfProfileOut(__METHOD__);
                 return $status;
             }
         }
         # All's well
         wfProfileIn(__METHOD__ . '-sectionanchor');
         $sectionanchor = '';
         if ($this->section == 'new') {
             if ($this->textbox1 == '') {
                 $this->missingComment = true;
                 $status->fatal('missingcommenttext');
                 $status->value = self::AS_TEXTBOX_EMPTY;
                 wfProfileOut(__METHOD__ . '-sectionanchor');
                 wfProfileOut(__METHOD__);
                 return $status;
             }
             if ($this->sectiontitle !== '') {
                 $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText($this->sectiontitle);
                 // If no edit summary was specified, create one automatically from the section
                 // title and have it link to the new section. Otherwise, respect the summary as
                 // passed.
                 if ($this->summary === '') {
                     $cleanSectionTitle = $wgParser->stripSectionName($this->sectiontitle);
                     $this->summary = wfMessage('newsectionsummary')->rawParams($cleanSectionTitle)->inContentLanguage()->text();
                 }
             } elseif ($this->summary !== '') {
                 $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText($this->summary);
                 # This is a new section, so create a link to the new section
                 # in the revision summary.
                 $cleanSummary = $wgParser->stripSectionName($this->summary);
                 $this->summary = wfMessage('newsectionsummary')->rawParams($cleanSummary)->inContentLanguage()->text();
             }
         } elseif ($this->section != '') {
             # Try to get a section anchor from the section source, redirect to edited section if header found
             # XXX: might be better to integrate this into Article::replaceSection
             # for duplicate heading checking and maybe parsing
             $hasmatch = preg_match("/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches);
             # we can't deal with anchors, includes, html etc in the header for now,
             # headline would need to be parsed to improve this
             if ($hasmatch && strlen($matches[2]) > 0) {
                 $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText($matches[2]);
             }
         }
         $result['sectionanchor'] = $sectionanchor;
         wfProfileOut(__METHOD__ . '-sectionanchor');
         // Save errors may fall down to the edit form, but we've now
         // merged the section into full text. Clear the section field
         // so that later submission of conflict forms won't try to
         // replace that into a duplicated mess.
         $this->textbox1 = $text;
         $this->section = '';
         $status->value = self::AS_SUCCESS_UPDATE;
     }
     // Check for length errors again now that the section is merged in
     $this->kblength = (int) (strlen($text) / 1024);
     if ($this->kblength > $wgMaxArticleSize) {
         $this->tooBig = true;
         $status->setResult(false, self::AS_MAX_ARTICLE_SIZE_EXCEEDED);
         wfProfileOut(__METHOD__);
         return $status;
     }
     $flags = EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY | ($new ? EDIT_NEW : EDIT_UPDATE) | ($this->minoredit && !$this->isNew ? EDIT_MINOR : 0) | ($bot ? EDIT_FORCE_BOT : 0);
     $doEditStatus = $this->mArticle->doEdit($text, $this->summary, $flags);
     if ($doEditStatus->isOK()) {
         $result['redirect'] = Title::newFromRedirect($text) !== null;
         $this->commitWatch();
         wfProfileOut(__METHOD__);
         return $status;
     } else {
         // Failure from doEdit()
         // Show the edit conflict page for certain recognized errors from doEdit(),
         // but don't show it for errors from extension hooks
         $errors = $doEditStatus->getErrorsArray();
         if (in_array($errors[0][0], array('edit-gone-missing', 'edit-conflict', 'edit-already-exists'))) {
             $this->isConflict = true;
             // Destroys data doEdit() put in $status->value but who cares
             $doEditStatus->value = self::AS_END;
         }
         wfProfileOut(__METHOD__);
         return $doEditStatus;
     }
 }