/**
  * Attempt submission (no UI)
  * @return one of the constants describing the result
  */
 function internalAttemptSave(&$result, $bot = false)
 {
     global $wgSpamRegex, $wgFilterCallback, $wgUser, $wgOut, $wgParser;
     global $wgMaxArticleSize;
     $fname = 'EditPage::attemptSave';
     wfProfileIn($fname);
     wfProfileIn("{$fname}-checks");
     if (!wfRunHooks('EditPage::attemptSave', array(&$this))) {
         wfDebug("Hook 'EditPage::attemptSave' aborted article saving");
         return self::AS_HOOK_ERROR;
     }
     # Check image redirect
     if ($this->mTitle->getNamespace() == NS_IMAGE && Title::newFromRedirect($this->textbox1) instanceof Title && !$wgUser->isAllowed('upload')) {
         if ($wgUser->isAnon()) {
             return self::AS_IMAGE_REDIRECT_ANON;
         } else {
             return self::AS_IMAGE_REDIRECT_LOGGED;
         }
     }
     # Reintegrate metadata
     if ($this->mMetaData != '') {
         $this->textbox1 .= "\n" . $this->mMetaData;
     }
     $this->mMetaData = '';
     # Check for spam
     $matches = array();
     if ($wgSpamRegex && preg_match($wgSpamRegex, $this->textbox1, $matches)) {
         $result['spam'] = $matches[0];
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return self::AS_SPAM_ERROR;
     }
     if ($wgFilterCallback && $wgFilterCallback($this->mTitle, $this->textbox1, $this->section)) {
         # Error messages or other handling should be performed by the filter function
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return self::AS_FILTERING;
     }
     if (!wfRunHooks('EditFilter', array($this, $this->textbox1, $this->section, &$this->hookError))) {
         # Error messages etc. could be handled within the hook...
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return self::AS_HOOK_ERROR;
     } elseif ($this->hookError != '') {
         # ...or the hook could be expecting us to produce an error
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return self::AS_HOOK_ERROR_EXPECTED;
     }
     if ($wgUser->isBlockedFrom($this->mTitle, false)) {
         # Check block state against master, thus 'false'.
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return self::AS_BLOCKED_PAGE_FOR_USER;
     }
     $this->kblength = (int) (strlen($this->textbox1) / 1024);
     if ($this->kblength > $wgMaxArticleSize) {
         // Error will be displayed by showEditForm()
         $this->tooBig = true;
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return self::AS_CONTENT_TOO_BIG;
     }
     if (!$wgUser->isAllowed('edit')) {
         if ($wgUser->isAnon()) {
             wfProfileOut("{$fname}-checks");
             wfProfileOut($fname);
             return self::AS_READ_ONLY_PAGE_ANON;
         } else {
             wfProfileOut("{$fname}-checks");
             wfProfileOut($fname);
             return self::AS_READ_ONLY_PAGE_LOGGED;
         }
     }
     if (wfReadOnly()) {
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return self::AS_READ_ONLY_PAGE;
     }
     if ($wgUser->pingLimiter()) {
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return self::AS_RATE_LIMITED;
     }
     # If the article has been deleted while editing, don't save it without
     # confirmation
     if ($this->deletedSinceEdit && !$this->recreate) {
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return self::AS_ARTICLE_WAS_DELETED;
     }
     wfProfileOut("{$fname}-checks");
     # If article is new, insert it.
     $aid = $this->mTitle->getArticleID(GAID_FOR_UPDATE);
     if (0 == $aid) {
         // Late check for create permission, just in case *PARANOIA*
         if (!$this->mTitle->userCan('create')) {
             wfDebug("{$fname}: no create permission\n");
             wfProfileOut($fname);
             return self::AS_NO_CREATE_PERMISSION;
         }
         # Don't save a new article if it's blank.
         if ('' == $this->textbox1) {
             wfProfileOut($fname);
             return self::AS_BLANK_ARTICLE;
         }
         // Run post-section-merge edit filter
         if (!wfRunHooks('EditFilterMerged', array($this, $this->textbox1, &$this->hookError))) {
             # Error messages etc. could be handled within the hook...
             wfProfileOut($fname);
             return self::AS_HOOK_ERROR;
         }
         $isComment = $this->section == 'new';
         $this->mArticle->insertNewArticle($this->textbox1, $this->summary, $this->minoredit, $this->watchthis, false, $isComment, $bot);
         wfProfileOut($fname);
         return self::AS_SUCCESS_NEW_ARTICLE;
     }
     # Article exists. Check for edit conflict.
     $this->mArticle->clear();
     # Force reload of dates, etc.
     $this->mArticle->forUpdate(true);
     # Lock the article
     wfDebug("timestamp: {$this->mArticle->getTimestamp()}, edittime: {$this->edittime}\n");
     if ($this->mArticle->getTimestamp() != $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("EditPage::editForm duplicate new section submission; trigger edit conflict!\n");
             } else {
                 // New comment; suppress conflict.
                 $this->isConflict = false;
                 wfDebug("EditPage::editForm conflict suppressed; new section\n");
             }
         }
     }
     $userid = $wgUser->getID();
     if ($this->isConflict) {
         wfDebug("EditPage::editForm conflict! getting section '{$this->section}' for time '{$this->edittime}' (article time '" . $this->mArticle->getTimestamp() . "')\n");
         $text = $this->mArticle->replaceSection($this->section, $this->textbox1, $this->summary, $this->edittime);
     } else {
         wfDebug("EditPage::editForm getting section '{$this->section}'\n");
         $text = $this->mArticle->replaceSection($this->section, $this->textbox1, $this->summary);
     }
     if (is_null($text)) {
         wfDebug("EditPage::editForm activating conflict; section replace failed.\n");
         $this->isConflict = true;
         $text = $this->textbox1;
     }
     # Suppress edit conflict with self, except for section edits where merging is required.
     if ($this->section == '' && 0 != $userid && $this->mArticle->getUser() == $userid) {
         wfDebug("EditPage::editForm Suppressing edit conflict, same user.\n");
         $this->isConflict = false;
     } else {
         # switch from section editing to normal editing in edit conflict
         if ($this->isConflict) {
             # Attempt merge
             if ($this->mergeChangesInto($text)) {
                 // Successful merge! Maybe we should tell the user the good news?
                 $this->isConflict = false;
                 wfDebug("EditPage::editForm Suppressing edit conflict, successful merge.\n");
             } else {
                 $this->section = '';
                 $this->textbox1 = $text;
                 wfDebug("EditPage::editForm Keeping edit conflict, failed merge.\n");
             }
         }
     }
     if ($this->isConflict) {
         wfProfileOut($fname);
         return self::AS_CONFLICT_DETECTED;
     }
     $oldtext = $this->mArticle->getContent();
     // Run post-section-merge edit filter
     if (!wfRunHooks('EditFilterMerged', array($this, $text, &$this->hookError))) {
         # Error messages etc. could be handled within the hook...
         wfProfileOut($fname);
         return self::AS_HOOK_ERROR;
     }
     # Handle the user preference to force summaries here, but not for null edits
     if ($this->section != 'new' && !$this->allowBlankSummary && $wgUser->getOption('forceeditsummary') && 0 != strcmp($oldtext, $text) && !Article::getRedirectAutosummary($text)) {
         if (md5($this->summary) == $this->autoSumm) {
             $this->missingSummary = true;
             wfProfileOut($fname);
             return self::AS_SUMMARY_NEEDED;
         }
     }
     #And a similar thing for new sections
     if ($this->section == 'new' && !$this->allowBlankSummary && $wgUser->getOption('forceeditsummary')) {
         if (trim($this->summary) == '') {
             $this->missingSummary = true;
             wfProfileOut($fname);
             return self::AS_SUMMARY_NEEDED;
         }
     }
     # All's well
     wfProfileIn("{$fname}-sectionanchor");
     $sectionanchor = '';
     if ($this->section == 'new') {
         if ($this->textbox1 == '') {
             $this->missingComment = true;
             return self::AS_TEXTBOX_EMPTY;
         }
         if ($this->summary != '') {
             $sectionanchor = $wgParser->guessSectionNameFromWikiText($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 = wfMsgForContent('newsectionsummary', $cleanSummary);
         }
     } 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 and strlen($matches[2]) > 0) {
             $sectionanchor = $wgParser->guessSectionNameFromWikiText($matches[2]);
         }
     }
     wfProfileOut("{$fname}-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 = '';
     // 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;
         wfProfileOut($fname);
         return self::AS_MAX_ARTICLE_SIZE_EXCEEDED;
     }
     # update the article here
     if ($this->mArticle->updateArticle($text, $this->summary, $this->minoredit, $this->watchthis, $bot, $sectionanchor)) {
         wfProfileOut($fname);
         return self::AS_SUCCESS_UPDATE;
     } else {
         $this->isConflict = true;
     }
     wfProfileOut($fname);
     return self::AS_END;
 }
Example #2
0
 /**
  * Attempt submission
  * @return bool false if output is done, true if the rest of the form should be displayed
  */
 function attemptSave()
 {
     global $wgSpamRegex, $wgFilterCallback, $wgUser, $wgOut;
     global $wgMaxArticleSize;
     $fname = 'EditPage::attemptSave';
     wfProfileIn($fname);
     wfProfileIn("{$fname}-checks");
     if (!wfRunHooks('EditPage::attemptSave', array(&$this))) {
         wfDebug("Hook 'EditPage::attemptSave' aborted article saving");
         return false;
     }
     # Reintegrate metadata
     if ($this->mMetaData != '') {
         $this->textbox1 .= "\n" . $this->mMetaData;
     }
     $this->mMetaData = '';
     # Check for spam
     $matches = array();
     if ($wgSpamRegex && preg_match($wgSpamRegex, $this->textbox1, $matches)) {
         $this->spamPage($matches[0]);
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return false;
     }
     if ($wgFilterCallback && $wgFilterCallback($this->mTitle, $this->textbox1, $this->section)) {
         # Error messages or other handling should be performed by the filter function
         wfProfileOut($fname);
         wfProfileOut("{$fname}-checks");
         return false;
     }
     if (!wfRunHooks('EditFilter', array($this, $this->textbox1, $this->section, &$this->hookError))) {
         # Error messages etc. could be handled within the hook...
         wfProfileOut($fname);
         wfProfileOut("{$fname}-checks");
         return false;
     } elseif ($this->hookError != '') {
         # ...or the hook could be expecting us to produce an error
         wfProfileOut("{$fname}-checks ");
         wfProfileOut($fname);
         return true;
     }
     if ($wgUser->isBlockedFrom($this->mTitle, false)) {
         # Check block state against master, thus 'false'.
         $this->blockedPage();
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return false;
     }
     $this->kblength = (int) (strlen($this->textbox1) / 1024);
     if ($this->kblength > $wgMaxArticleSize) {
         // Error will be displayed by showEditForm()
         $this->tooBig = true;
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return true;
     }
     if (!$wgUser->isAllowed('edit')) {
         if ($wgUser->isAnon()) {
             $this->userNotLoggedInPage();
             wfProfileOut("{$fname}-checks");
             wfProfileOut($fname);
             return false;
         } else {
             $wgOut->readOnlyPage();
             wfProfileOut("{$fname}-checks");
             wfProfileOut($fname);
             return false;
         }
     }
     if (wfReadOnly()) {
         $wgOut->readOnlyPage();
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return false;
     }
     if ($wgUser->pingLimiter()) {
         $wgOut->rateLimited();
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return false;
     }
     # If the article has been deleted while editing, don't save it without
     # confirmation
     if ($this->deletedSinceEdit && !$this->recreate) {
         wfProfileOut("{$fname}-checks");
         wfProfileOut($fname);
         return true;
     }
     wfProfileOut("{$fname}-checks");
     # If article is new, insert it.
     $aid = $this->mTitle->getArticleID(GAID_FOR_UPDATE);
     if (0 == $aid) {
         // Late check for create permission, just in case *PARANOIA*
         if (!$this->mTitle->userCanCreate()) {
             wfDebug("{$fname}: no create permission\n");
             $this->noCreatePermission();
             wfProfileOut($fname);
             return;
         }
         # Don't save a new article if it's blank.
         if ('' == $this->textbox1) {
             $wgOut->redirect($this->mTitle->getFullURL());
             wfProfileOut($fname);
             return false;
         }
         $isComment = $this->section == 'new';
         $this->mArticle->insertNewArticle($this->textbox1, $this->summary, $this->minoredit, $this->watchthis, false, $isComment);
         wfProfileOut($fname);
         return false;
     }
     # Article exists. Check for edit conflict.
     $this->mArticle->clear();
     # Force reload of dates, etc.
     $this->mArticle->forUpdate(true);
     # Lock the article
     if ($this->mArticle->getTimestamp() != $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("EditPage::editForm duplicate new section submission; trigger edit conflict!\n");
             } else {
                 // New comment; suppress conflict.
                 $this->isConflict = false;
                 wfDebug("EditPage::editForm conflict suppressed; new section\n");
             }
         }
     }
     $userid = $wgUser->getID();
     if ($this->isConflict) {
         wfDebug("EditPage::editForm conflict! getting section '{$this->section}' for time '{$this->edittime}' (article time '" . $this->mArticle->getTimestamp() . "'\n");
         $text = $this->mArticle->replaceSection($this->section, $this->textbox1, $this->summary, $this->edittime);
     } else {
         wfDebug("EditPage::editForm getting section '{$this->section}'\n");
         $text = $this->mArticle->replaceSection($this->section, $this->textbox1, $this->summary);
     }
     if (is_null($text)) {
         wfDebug("EditPage::editForm activating conflict; section replace failed.\n");
         $this->isConflict = true;
         $text = $this->textbox1;
     }
     # Suppress edit conflict with self, except for section edits where merging is required.
     if ($this->section == '' && 0 != $userid && $this->mArticle->getUser() == $userid) {
         wfDebug("Suppressing edit conflict, same user.\n");
         $this->isConflict = false;
     } else {
         # switch from section editing to normal editing in edit conflict
         if ($this->isConflict) {
             # Attempt merge
             if ($this->mergeChangesInto($text)) {
                 // Successful merge! Maybe we should tell the user the good news?
                 $this->isConflict = false;
                 wfDebug("Suppressing edit conflict, successful merge.\n");
             } else {
                 $this->section = '';
                 $this->textbox1 = $text;
                 wfDebug("Keeping edit conflict, failed merge.\n");
             }
         }
     }
     if ($this->isConflict) {
         wfProfileOut($fname);
         return true;
     }
     $oldtext = $this->mArticle->getContent();
     # Handle the user preference to force summaries here, but not for null edits
     if ($this->section != 'new' && !$this->allowBlankSummary && $wgUser->getOption('forceeditsummary') && 0 != strcmp($oldtext, $text) && !Article::getRedirectAutosummary($text)) {
         if (md5($this->summary) == $this->autoSumm) {
             $this->missingSummary = true;
             wfProfileOut($fname);
             return true;
         }
     }
     #And a similar thing for new sections
     if ($this->section == 'new' && !$this->allowBlankSummary && $wgUser->getOption('forceeditsummary')) {
         if (trim($this->summary) == '') {
             $this->missingSummary = true;
             wfProfileOut($fname);
             return true;
         }
     }
     # All's well
     wfProfileIn("{$fname}-sectionanchor");
     $sectionanchor = '';
     if ($this->section == 'new') {
         if ($this->textbox1 == '') {
             $this->missingComment = true;
             return true;
         }
         if ($this->summary != '') {
             $sectionanchor = $this->sectionAnchor($this->summary);
         }
     } 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 and strlen($matches[2]) > 0) {
             $sectionanchor = $this->sectionAnchor($matches[2]);
         }
     }
     wfProfileOut("{$fname}-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 = '';
     // 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;
         wfProfileOut($fname);
         return true;
     }
     # update the article here
     if ($this->mArticle->updateArticle($text, $this->summary, $this->minoredit, $this->watchthis, '', $sectionanchor)) {
         wfProfileOut($fname);
         return false;
     } else {
         $this->isConflict = true;
     }
     wfProfileOut($fname);
     return true;
 }