static function doIndexes($out, $parseroutput)
 {
     if (!isset($parseroutput->mIndexes)) {
         $parseroutput->mIndexes = array();
     }
     if ($parseroutput->getProperty('preview')) {
         return true;
     }
     $pageid = $out->getTitle()->getArticleID();
     $dbw = wfGetDB(DB_MASTER);
     $res = $dbw->select('indexes', array('in_namespace', 'in_title'), array('in_from' => $pageid), __METHOD__);
     $current = array();
     foreach ($res as $row) {
         $current[] = array($row->in_namespace, $row->in_title);
     }
     $toAdd = wfArrayDiff2($parseroutput->mIndexes, $current);
     $toRem = wfArrayDiff2($current, $parseroutput->mIndexes);
     if ($toAdd || $toRem) {
         $dbw->begin(__METHOD__);
         if ($toRem) {
             $delCond = "in_from = {$pageid} AND (";
             $parts = array();
             # Looking at Database::delete, it seems to turn arrays into AND statements
             # but we need to chain together groups of ANDs with ORs
             foreach ($toRem as $entry) {
                 $parts[] = "(in_namespace = " . $entry[0] . " AND in_title = " . $dbw->addQuotes($entry[1]) . ")";
             }
             $delCond .= implode(' OR ', $parts) . ")";
             $dbw->delete('indexes', array($delCond), __METHOD__);
         }
         if ($toAdd) {
             $ins = array();
             foreach ($toAdd as $entry) {
                 $ins[] = array('in_from' => $pageid, 'in_namespace' => $entry[0], 'in_title' => $entry[1]);
             }
             $dbw->insert('indexes', $ins, __METHOD__);
         }
         $dbw->commit(__METHOD__);
     }
     return true;
 }
Beispiel #2
0
 /**
  * @dataProvider provideForWfArrayDiff2
  * @covers ::wfArrayDiff2
  */
 public function testWfArrayDiff2($a, $b, $expected)
 {
     $this->assertEquals(wfArrayDiff2($a, $b), $expected);
 }
Beispiel #3
0
	/**
	 * Roll back the most recent consecutive set of edits to a page
	 * from the same user; fails if there are no eligible edits to
	 * roll back to, e.g. user is the sole contributor. This function
	 * performs permissions checks on $user, then calls commitRollback()
	 * to do the dirty work
	 *
	 * @todo Separate the business/permission stuff out from backend code
	 *
	 * @param string $fromP Name of the user whose edits to rollback.
	 * @param string $summary Custom summary. Set to default summary if empty.
	 * @param string $token Rollback token.
	 * @param $bot Boolean: If true, mark all reverted edits as bot.
	 *
	 * @param array $resultDetails contains result-specific array of additional values
	 *    'alreadyrolled' : 'current' (rev)
	 *    success        : 'summary' (str), 'current' (rev), 'target' (rev)
	 *
	 * @param $user User The user performing the rollback
	 * @return array of errors, each error formatted as
	 *   array(messagekey, param1, param2, ...).
	 * On success, the array is empty.  This array can also be passed to
	 * OutputPage::showPermissionsErrorPage().
	 */
	public function doRollback(
		$fromP, $summary, $token, $bot, &$resultDetails, User $user
	) {
		$resultDetails = null;

		// Check permissions
		$editErrors = $this->mTitle->getUserPermissionsErrors( 'edit', $user );
		$rollbackErrors = $this->mTitle->getUserPermissionsErrors( 'rollback', $user );
		$errors = array_merge( $editErrors, wfArrayDiff2( $rollbackErrors, $editErrors ) );

		if ( !$user->matchEditToken( $token, array( $this->mTitle->getPrefixedText(), $fromP ) ) ) {
			$errors[] = array( 'sessionfailure' );
		}

		if ( $user->pingLimiter( 'rollback' ) || $user->pingLimiter() ) {
			$errors[] = array( 'actionthrottledtext' );
		}

		// If there were errors, bail out now
		if ( !empty( $errors ) ) {
			return $errors;
		}

		return $this->commitRollback( $fromP, $summary, $bot, $resultDetails, $user );
	}
Beispiel #4
0
 /**
  * @return array
  */
 protected function getEditPermissionErrors()
 {
     global $wgUser;
     $permErrors = $this->mTitle->getUserPermissionsErrors('edit', $wgUser);
     # Can this title be created?
     if (!$this->mTitle->exists()) {
         $permErrors = array_merge($permErrors, wfArrayDiff2($this->mTitle->getUserPermissionsErrors('create', $wgUser), $permErrors));
     }
     # Ignore some permissions errors when a user is just previewing/viewing diffs
     $remove = array();
     foreach ($permErrors as $error) {
         if (($this->preview || $this->diff) && ($error[0] == 'blockedtext' || $error[0] == 'autoblockedtext')) {
             $remove[] = $error;
         }
     }
     $permErrors = wfArrayDiff2($permErrors, $remove);
     return $permErrors;
 }
 /**
  * Check whether the user can edit, upload and create the image. This
  * checks only against the current title; if it returns errors, it may
  * very well be that another title will not give errors. Therefore
  * isAllowed() should be called as well for generic is-user-blocked or
  * can-user-upload checking.
  *
  * @param $user User object to verify the permissions against
  * @return mixed An array as returned by getUserPermissionsErrors or true
  *               in case the user has proper permissions.
  */
 public function verifyTitlePermissions($user)
 {
     /**
      * If the image is protected, non-sysop users won't be able
      * to modify it by uploading a new revision.
      */
     $nt = $this->getTitle();
     if (is_null($nt)) {
         return true;
     }
     $permErrors = $nt->getUserPermissionsErrors('edit', $user);
     $permErrorsUpload = $nt->getUserPermissionsErrors('upload', $user);
     if (!$nt->exists()) {
         $permErrorsCreate = $nt->getUserPermissionsErrors('create', $user);
     } else {
         $permErrorsCreate = array();
     }
     if ($permErrors || $permErrorsUpload || $permErrorsCreate) {
         $permErrors = array_merge($permErrors, wfArrayDiff2($permErrorsUpload, $permErrors));
         $permErrors = array_merge($permErrors, wfArrayDiff2($permErrorsCreate, $permErrors));
         return $permErrors;
     }
     $overwriteError = $this->checkOverwrite($user);
     if ($overwriteError !== true) {
         return array($overwriteError);
     }
     return true;
 }
Beispiel #6
0
 protected function doMWStore($output, $title, $editor)
 {
     $permErrors = $title->getUserPermissionsErrors('edit', $this->getUser());
     if (!$title->exists()) {
         $permErrors = array_merge($permErrors, wfArrayDiff2($title->getUserPermissionsErrors('create', $this->getUser()), $permErrors));
     }
     if ($permErrors) {
         $this->getUser()->spreadAnyEditBlock();
         foreach ($permErrors as $error) {
             $this->logMessage(call_user_func_array('wfMessage', $error)->parse());
         }
         return;
     }
     $resultDetails = false;
     # Allow bots to exempt some edits from bot flagging
     $bot = $this->getUser()->isAllowed('bot') && $editor->bot;
     $request = $editor->sfFauxRequest;
     if ($editor->tokenOk($request)) {
         $ctx = RequestContext::getMain();
         $tempTitle = $ctx->getTitle();
         $ctx->setTitle($title);
         $status = $editor->internalAttemptSave($resultDetails, $bot);
         $ctx->setTitle($tempTitle);
     } else {
         throw new MWException(wfMessage('session_fail_preview')->parse());
     }
     switch ($status->value) {
         case EditPage::AS_HOOK_ERROR_EXPECTED:
             // A hook function returned an error
         // A hook function returned an error
         case EditPage::AS_CONTENT_TOO_BIG:
             // Content too big (> $wgMaxArticleSize)
         // Content too big (> $wgMaxArticleSize)
         case EditPage::AS_ARTICLE_WAS_DELETED:
             // article was deleted while editting and param wpRecreate == false or form was not posted
         // article was deleted while editting and param wpRecreate == false or form was not posted
         case EditPage::AS_CONFLICT_DETECTED:
             // (non-resolvable) edit conflict
         // (non-resolvable) edit conflict
         case EditPage::AS_SUMMARY_NEEDED:
             // no edit summary given and the user has forceeditsummary set and the user is not editting in his own userspace or talkspace and wpIgnoreBlankSummary == false
         // no edit summary given and the user has forceeditsummary set and the user is not editting in his own userspace or talkspace and wpIgnoreBlankSummary == false
         case EditPage::AS_TEXTBOX_EMPTY:
             // user tried to create a new section without content
         // user tried to create a new section without content
         case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED:
             // article is too big (> $wgMaxArticleSize), after merging in the new section
         // article is too big (> $wgMaxArticleSize), after merging in the new section
         case EditPage::AS_END:
             // WikiPage::doEdit() was unsuccessfull
             throw new MWException(wfMessage('form_edit_fail', $this->options['title'])->parse());
         case EditPage::AS_HOOK_ERROR:
             // Article update aborted by a hook function
             $this->logMessage('Article update aborted by a hook function', self::DEBUG);
             return false;
             // success
             // TODO: This error code only exists from 1.21 onwards. It is
             // suitably handled by the default branch, but really should get its
             // own branch. Uncomment once compatibility to pre1.21 is dropped.
             //            case EditPage::AS_PARSE_ERROR: // can't parse content
             //
             //                throw new MWException( $status->getHTML() );
             //                return true; // fail
         // success
         // TODO: This error code only exists from 1.21 onwards. It is
         // suitably handled by the default branch, but really should get its
         // own branch. Uncomment once compatibility to pre1.21 is dropped.
         //            case EditPage::AS_PARSE_ERROR: // can't parse content
         //
         //                throw new MWException( $status->getHTML() );
         //                return true; // fail
         case EditPage::AS_SUCCESS_NEW_ARTICLE:
             // Article successfully created
             $output->redirect($title->getFullURL());
             return false;
             // success
         // success
         case EditPage::AS_SUCCESS_UPDATE:
             // Article successfully updated
             $output->redirect($title->getFullURL());
             return false;
             // success
         // success
         case EditPage::AS_BLANK_ARTICLE:
             // user tried to create a blank page
             $output->redirect($editor->getContextTitle()->getFullURL());
             return false;
             // success
         // success
         case EditPage::AS_SPAM_ERROR:
             // summary contained spam according to one of the regexes in $wgSummarySpamRegex
             $match = $resultDetails['spam'];
             if (is_array($match)) {
                 $match = $this->getLanguage()->listToText($match);
             }
             throw new MWException(wfMessage('spamprotectionmatch', wfEscapeWikiText($match))->parse());
             // FIXME: Include better error message
         // FIXME: Include better error message
         case EditPage::AS_BLOCKED_PAGE_FOR_USER:
             // User is blocked from editting editor page
             throw new UserBlockedError($this->getUser()->getBlock());
         case EditPage::AS_IMAGE_REDIRECT_ANON:
             // anonymous user is not allowed to upload (User::isAllowed('upload') == false)
         // anonymous user is not allowed to upload (User::isAllowed('upload') == false)
         case EditPage::AS_IMAGE_REDIRECT_LOGGED:
             // logged in user is not allowed to upload (User::isAllowed('upload') == false)
             throw new PermissionsError('upload');
         case EditPage::AS_READ_ONLY_PAGE_ANON:
             // editor anonymous user is not allowed to edit editor page
         // editor anonymous user is not allowed to edit editor page
         case EditPage::AS_READ_ONLY_PAGE_LOGGED:
             // editor logged in user is not allowed to edit editor page
             throw new PermissionsError('edit');
         case EditPage::AS_READ_ONLY_PAGE:
             // wiki is in readonly mode (wfReadOnly() == true)
             throw new ReadOnlyError();
         case EditPage::AS_RATE_LIMITED:
             // rate limiter for action 'edit' was tripped
             throw new ThrottledError();
         case EditPage::AS_NO_CREATE_PERMISSION:
             // user tried to create editor page, but is not allowed to do that ( Title->usercan('create') == false )
             $permission = $title->isTalkPage() ? 'createtalk' : 'createpage';
             throw new PermissionsError($permission);
         default:
             // We don't recognize $status->value. The only way that can happen
             // is if an extension hook aborted from inside ArticleSave.
             // Render the status object into $editor->hookError
             $editor->hookError = '<div class="error">' . $status->getWikitext() . '</div>';
             throw new MWException($status->getHTML());
     }
 }
 /**
  * Start the upload.  Note that this method always returns an object, even when it fails.
  * Make sure to check that the return value with:
  *
  *   $status->isOK()
  *
  * @param $oTitle - A title object that will be set if this call is successful
  * @return FileRepoStatus|Status - A status object representing the result of this call
  * @throws Exception
  */
 public function upload(&$oTitle)
 {
     $apiWrapper = $this->getApiWrapper();
     $thumbnailUrl = null;
     if (method_exists($apiWrapper, 'getThumbnailUrl')) {
         // Some providers will sometimes return error codes when attempting
         // to fetch a thumbnail
         try {
             $upload = $this->uploadBestThumbnail($apiWrapper->getThumbnailUrl());
         } catch (Exception $e) {
             WikiaLogger::instance()->error('Video upload failed', ['targetFile' => $this->sTargetTitle, 'externalURL' => $this->sExternalUrl, 'videoID' => $this->sVideoId, 'provider' => $this->sProvider, 'exception' => $e]);
             return Status::newFatal($e->getMessage());
         }
     } else {
         WikiaLogger::instance()->error('Api wrapper corrupted', ['targetFile' => $this->sTargetTitle, 'overrideMetadata' => $this->aOverrideMetadata, 'externalURL' => $this->sExternalUrl, 'videoID' => $this->sVideoId, 'provider' => $this->sProvider, 'apiWrapper' => get_class($apiWrapper)]);
     }
     $oTitle = Title::newFromText($this->getNormalizedDestinationTitle(), NS_FILE);
     // Check if the user has the proper permissions
     // Mimicks Special:Upload's behavior
     $user = F::app()->wg->User;
     $permErrors = $oTitle->getUserPermissionsErrors('edit', $user);
     $permErrorsUpload = $oTitle->getUserPermissionsErrors('upload', $user);
     if (!$oTitle->exists()) {
         $permErrorsCreate = $oTitle->getUserPermissionsErrors('create', $user);
     } else {
         $permErrorsCreate = [];
     }
     if ($permErrors || $permErrorsUpload || $permErrorsCreate) {
         $permErrors = array_merge($permErrors, wfArrayDiff2($permErrorsUpload, $permErrors));
         $permErrors = array_merge($permErrors, wfArrayDiff2($permErrorsCreate, $permErrors));
         $msgKey = array_shift($permErrors[0]);
         throw new Exception(wfMessage($msgKey, $permErrors[0])->parse());
     }
     if ($oTitle->exists()) {
         // @TODO
         // if video already exists make sure that we are in fact changing something
         // before generating upload (for now this only works for edits)
         $articleId = $oTitle->getArticleID();
         $article = Article::newFromID($articleId);
         // In case Article is null log more info and throw an exception
         if (is_null($article)) {
             $exception = new VideoUploadFailedException('Video upload failed');
             WikiaLogger::instance()->error('Video upload: title exists but article is null', ['Title object' => $oTitle, 'Video title' => $this->getNormalizedDestinationTitle(), 'Article ID' => $articleId, 'Title from ID' => Title::newFromID($articleId), 'exception' => $exception]);
             throw $exception;
         }
         $content = $article->getContent();
         $newcontent = $this->getDescription();
         if ($content != $newcontent) {
             $article->doEdit($newcontent, wfMessage('videos-update-edit-summary')->inContentLanguage()->text());
         }
     }
     $class = !empty($this->bUndercover) ? 'WikiaNoArticleLocalFile' : 'WikiaLocalFile';
     /** @var WikiaLocalFile $file */
     $file = new $class($oTitle, RepoGroup::singleton()->getLocalRepo());
     /* override thumbnail metadata with video metadata */
     $file->forceMime($this->getApiWrapper()->getMimeType());
     $file->setVideoId($this->getVideoId());
     /* ingestion video won't be able to load anything so we need to spoon feed it the correct data */
     if ($this->getApiWrapper()->isIngestion()) {
         $file->forceMetadata(serialize($this->getNormalizedMetadata()));
     }
     $forceMime = $file->forceMime;
     $file->getMetadata();
     //In case of video replacement - Title already exists - preserve forceMime value.
     //By default it is changed to false in WikiaLocalFileShared::afterSetProps method
     //which is called by $file->getMetadata().
     if ($oTitle->exists()) {
         $file->forceMime = $forceMime;
     }
     /* real upload */
     $result = $file->upload($upload->getTempPath(), wfMessage('videos-initial-upload-edit-summary')->inContentLanguage()->text(), \UtfNormal::toNFC($this->getDescription()), File::DELETE_SOURCE);
     wfRunHooks('AfterVideoFileUploaderUpload', array($file, $result));
     return $result;
 }
Beispiel #8
0
 /**
  * 
  * @param Title $fileTitle
  * @param User $user
  * @return array|boolean True on success, or an array containing error message + arg if error occured 
  * @throws MWException
  */
 public function setBackground($fileTitle, $user)
 {
     if (!$user instanceof User) {
         throw new MWException('Invalid user argument');
     }
     if (!self::isTitleValidForBackground($fileTitle)) {
         throw new MWException('Invalid file title argument');
     }
     $configTitle = $this->getBackgroundConfigurationTitle();
     // as seen in EditPage->getEditPermissionErrors() ( called by EditPage->edit() )
     $permErrors = $configTitle->getUserPermissionsErrors('edit', $user);
     $permErrors = array_merge($permErrors, wfArrayDiff2($configTitle->getUserPermissionsErrors('create', $user), $permErrors));
     if ($permErrors) {
         return $permErrors[0];
         // strange, but only key 0 seems to be used by MW when reads errors
     }
     $article = new Article($configTitle);
     $status = $article->doEdit('[[' . $fileTitle->getPrefixedText() . ']]', '');
     if (!$status->isOk()) {
         // isOk() == warning ignored, ie when the new content is the same as previous
         return array('sz-internal-error');
     }
     return true;
 }
 protected function doStore(EditPage $editor)
 {
     $title = $editor->getTitle();
     // If they used redlink=1 and the page exists, redirect to the main article and send notice
     if ($this->getRequest()->getBool('redlink') && $title->exists()) {
         $this->logMessage(wfMessage('sf_autoedit_redlinkexists')->parse(), self::WARNING);
     }
     $permErrors = $title->getUserPermissionsErrors('edit', $this->getUser());
     // if this title needs to be created, user needs create rights
     if (!$title->exists()) {
         $permErrors = array_merge($permErrors, wfArrayDiff2($title->getUserPermissionsErrors('create', $this->getUser()), $permErrors));
     }
     if ($permErrors) {
         // Auto-block user's IP if the account was "hard" blocked
         $this->getUser()->spreadAnyEditBlock();
         foreach ($permErrors as $error) {
             $this->logMessage(call_user_func_array('wfMessage', $error)->parse());
         }
         return;
     }
     $resultDetails = false;
     # Allow bots to exempt some edits from bot flagging
     $bot = $this->getUser()->isAllowed('bot') && $editor->bot;
     $request = $editor->sfFauxRequest;
     if ($editor->tokenOk($request)) {
         $ctx = RequestContext::getMain();
         $tempTitle = $ctx->getTitle();
         $ctx->setTitle($title);
         $status = $editor->internalAttemptSave($resultDetails, $bot);
         $ctx->setTitle($tempTitle);
     } else {
         throw new MWException(wfMessage('session_fail_preview')->parse());
     }
     switch ($status->value) {
         case EditPage::AS_HOOK_ERROR_EXPECTED:
             // A hook function returned an error
             // show normal Edit page
             // remove Preview and Diff standard buttons from editor page
             Hooks::register('EditPageBeforeEditButtons', function (&$editor, &$buttons, &$tabindex) {
                 foreach (array_keys($buttons) as $key) {
                     if ($key !== 'save') {
                         unset($buttons[$key]);
                     }
                 }
             });
             // Context title needed for correct Cancel link
             $editor->setContextTitle($title);
             $editor->showEditForm();
             return false;
             // success
         // success
         case EditPage::AS_CONTENT_TOO_BIG:
             // Content too big (> $wgMaxArticleSize)
         // Content too big (> $wgMaxArticleSize)
         case EditPage::AS_ARTICLE_WAS_DELETED:
             // article was deleted while editting and param wpRecreate == false or form was not posted
         // article was deleted while editting and param wpRecreate == false or form was not posted
         case EditPage::AS_CONFLICT_DETECTED:
             // (non-resolvable) edit conflict
         // (non-resolvable) edit conflict
         case EditPage::AS_SUMMARY_NEEDED:
             // no edit summary given and the user has forceeditsummary set and the user is not editting in his own userspace or talkspace and wpIgnoreBlankSummary == false
         // no edit summary given and the user has forceeditsummary set and the user is not editting in his own userspace or talkspace and wpIgnoreBlankSummary == false
         case EditPage::AS_TEXTBOX_EMPTY:
             // user tried to create a new section without content
         // user tried to create a new section without content
         case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED:
             // article is too big (> $wgMaxArticleSize), after merging in the new section
         // article is too big (> $wgMaxArticleSize), after merging in the new section
         case EditPage::AS_END:
             // WikiPage::doEdit() was unsuccessfull
             throw new MWException(wfMessage('sf_autoedit_fail', $this->mOptions['target'])->parse());
         case EditPage::AS_HOOK_ERROR:
             // Article update aborted by a hook function
             $this->logMessage('Article update aborted by a hook function', self::DEBUG);
             return false;
             // success
             // TODO: This error code only exists from 1.21 onwards. It is
             // suitably handled by the default branch, but really should get its
             // own branch. Uncomment once compatibility to pre1.21 is dropped.
             //			case EditPage::AS_PARSE_ERROR: // can't parse content
             //
             //				throw new MWException( $status->getHTML() );
             //				return true; // fail
         // success
         // TODO: This error code only exists from 1.21 onwards. It is
         // suitably handled by the default branch, but really should get its
         // own branch. Uncomment once compatibility to pre1.21 is dropped.
         //			case EditPage::AS_PARSE_ERROR: // can't parse content
         //
         //				throw new MWException( $status->getHTML() );
         //				return true; // fail
         case EditPage::AS_SUCCESS_NEW_ARTICLE:
             // Article successfully created
             $query = $resultDetails['redirect'] ? 'redirect=no' : '';
             $anchor = isset($resultDetails['sectionanchor']) ? $resultDetails['sectionanchor'] : '';
             $this->getOutput()->redirect($title->getFullURL($query) . $anchor);
             $this->getResult()->addValue(NULL, 'redirect', $title->getFullURL($query) . $anchor);
             return false;
             // success
         // success
         case EditPage::AS_SUCCESS_UPDATE:
             // Article successfully updated
             $extraQuery = '';
             $sectionanchor = $resultDetails['sectionanchor'];
             // Give extensions a chance to modify URL query on update
             Hooks::run('ArticleUpdateBeforeRedirect', array($editor->getArticle(), &$sectionanchor, &$extraQuery));
             if ($resultDetails['redirect']) {
                 if ($extraQuery == '') {
                     $extraQuery = 'redirect=no';
                 } else {
                     $extraQuery = 'redirect=no&' . $extraQuery;
                 }
             }
             $this->getOutput()->redirect($title->getFullURL($extraQuery) . $sectionanchor);
             $this->getResult()->addValue(NULL, 'redirect', $title->getFullURL($extraQuery) . $sectionanchor);
             return false;
             // success
         // success
         case EditPage::AS_BLANK_ARTICLE:
             // user tried to create a blank page
             $this->logMessage('User tried to create a blank page', self::DEBUG);
             $this->getOutput()->redirect($editor->getContextTitle()->getFullURL());
             $this->getResult()->addValue(NULL, 'redirect', $editor->getContextTitle()->getFullURL());
             return false;
             // success
         // success
         case EditPage::AS_SPAM_ERROR:
             // summary contained spam according to one of the regexes in $wgSummarySpamRegex
             $match = $resultDetails['spam'];
             if (is_array($match)) {
                 $match = $this->getLanguage()->listToText($match);
             }
             throw new MWException(wfMessage('spamprotectionmatch', wfEscapeWikiText($match))->parse());
             // FIXME: Include better error message
         // FIXME: Include better error message
         case EditPage::AS_BLOCKED_PAGE_FOR_USER:
             // User is blocked from editting editor page
             throw new UserBlockedError($this->getUser()->getBlock());
         case EditPage::AS_IMAGE_REDIRECT_ANON:
             // anonymous user is not allowed to upload (User::isAllowed('upload') == false)
         // anonymous user is not allowed to upload (User::isAllowed('upload') == false)
         case EditPage::AS_IMAGE_REDIRECT_LOGGED:
             // logged in user is not allowed to upload (User::isAllowed('upload') == false)
             throw new PermissionsError('upload');
         case EditPage::AS_READ_ONLY_PAGE_ANON:
             // editor anonymous user is not allowed to edit editor page
         // editor anonymous user is not allowed to edit editor page
         case EditPage::AS_READ_ONLY_PAGE_LOGGED:
             // editor logged in user is not allowed to edit editor page
             throw new PermissionsError('edit');
         case EditPage::AS_READ_ONLY_PAGE:
             // wiki is in readonly mode (wfReadOnly() == true)
             throw new ReadOnlyError();
         case EditPage::AS_RATE_LIMITED:
             // rate limiter for action 'edit' was tripped
             throw new ThrottledError();
         case EditPage::AS_NO_CREATE_PERMISSION:
             // user tried to create editor page, but is not allowed to do that ( Title->usercan('create') == false )
             $permission = $title->isTalkPage() ? 'createtalk' : 'createpage';
             throw new PermissionsError($permission);
         default:
             // We don't recognize $status->value. The only way that can happen
             // is if an extension hook aborted from inside ArticleSave.
             // Render the status object into $editor->hookError
             $editor->hookError = '<div class="error">' . $status->getWikitext() . '</div>';
             throw new MWException($status->getHTML());
     }
 }
Beispiel #10
0
 /**
  * Really do the upload
  * Checks are made in SpecialUpload::execute()
  *
  * @param array $resultDetails contains result-specific dict of additional values
  *
  * @access private
  */
 function internalProcessUpload(&$resultDetails)
 {
     global $wgUser;
     if (!wfRunHooks('UploadForm:BeforeProcessing', array(&$this))) {
         wfDebug("Hook 'UploadForm:BeforeProcessing' broke processing the file.\n");
         return self::BEFORE_PROCESSING;
     }
     /**
      * If there was no filename or a zero size given, give up quick.
      */
     if (trim($this->mSrcName) == '' || empty($this->mFileSize)) {
         return self::EMPTY_FILE;
     }
     /* Check for curl error */
     if ($this->mCurlError) {
         return self::BEFORE_PROCESSING;
     }
     /**
      * Chop off any directories in the given filename. Then
      * filter out illegal characters, and try to make a legible name
      * out of it. We'll strip some silently that Title would die on.
      */
     if ($this->mDesiredDestName) {
         $basename = $this->mDesiredDestName;
     } else {
         $basename = $this->mSrcName;
     }
     $filtered = wfStripIllegalFilenameChars($basename);
     /* Normalize to title form before we do any further processing */
     $nt = Title::makeTitleSafe(NS_FILE, $filtered);
     if (is_null($nt)) {
         $resultDetails = array('filtered' => $filtered);
         return self::ILLEGAL_FILENAME;
     }
     $filtered = $nt->getDBkey();
     /**
      * We'll want to blacklist against *any* 'extension', and use
      * only the final one for the whitelist.
      */
     list($partname, $ext) = $this->splitExtensions($filtered);
     if (count($ext)) {
         $finalExt = $ext[count($ext) - 1];
     } else {
         $finalExt = '';
     }
     # If there was more than one "extension", reassemble the base
     # filename to prevent bogus complaints about length
     if (count($ext) > 1) {
         for ($i = 0; $i < count($ext) - 1; $i++) {
             $partname .= '.' . $ext[$i];
         }
     }
     if (strlen($partname) < 1) {
         return self::MIN_LENGTH_PARTNAME;
     }
     $this->mLocalFile = wfLocalFile($nt);
     $this->mDestName = $this->mLocalFile->getName();
     /**
      * If the image is protected, non-sysop users won't be able
      * to modify it by uploading a new revision.
      */
     $permErrors = $nt->getUserPermissionsErrors('edit', $wgUser);
     $permErrorsUpload = $nt->getUserPermissionsErrors('upload', $wgUser);
     $permErrorsCreate = $nt->exists() ? array() : $nt->getUserPermissionsErrors('create', $wgUser);
     if ($permErrors || $permErrorsUpload || $permErrorsCreate) {
         // merge all the problems into one list, avoiding duplicates
         $permErrors = array_merge($permErrors, wfArrayDiff2($permErrorsUpload, $permErrors));
         $permErrors = array_merge($permErrors, wfArrayDiff2($permErrorsCreate, $permErrors));
         $resultDetails = array('permissionserrors' => $permErrors);
         return self::PROTECTED_PAGE;
     }
     /**
      * In some cases we may forbid overwriting of existing files.
      */
     $overwrite = $this->checkOverwrite($this->mDestName);
     if ($overwrite !== true) {
         $resultDetails = array('overwrite' => $overwrite);
         return self::OVERWRITE_EXISTING_FILE;
     }
     /* Don't allow users to override the blacklist (check file extension) */
     global $wgCheckFileExtensions, $wgStrictFileExtensions;
     global $wgFileExtensions, $wgFileBlacklist;
     if ($finalExt == '') {
         return self::FILETYPE_MISSING;
     } elseif ($this->checkFileExtensionList($ext, $wgFileBlacklist) || $wgCheckFileExtensions && $wgStrictFileExtensions && !$this->checkFileExtension($finalExt, $wgFileExtensions)) {
         $resultDetails = array('finalExt' => $finalExt);
         return self::FILETYPE_BADTYPE;
     }
     /**
      * Look at the contents of the file; if we can recognize the
      * type but it's corrupt or data of the wrong type, we should
      * probably not accept it.
      */
     if (!$this->mStashed) {
         $this->mFileProps = File::getPropsFromPath($this->mTempPath, $finalExt);
         $this->checkMacBinary();
         $veri = $this->verify($this->mTempPath, $finalExt);
         if ($veri !== true) {
             //it's a wiki error...
             $resultDetails = array('veri' => $veri);
             return self::VERIFICATION_ERROR;
         }
         /**
          * Provide an opportunity for extensions to add further checks
          */
         $error = '';
         if (!wfRunHooks('UploadVerification', array($this->mDestName, $this->mTempPath, &$error))) {
             $resultDetails = array('error' => $error);
             return self::UPLOAD_VERIFICATION_ERROR;
         }
     }
     /**
      * Check for non-fatal conditions
      */
     if (!$this->mIgnoreWarning) {
         $warning = '';
         $comparableName = str_replace(' ', '_', $basename);
         global $wgCapitalLinks, $wgContLang;
         if ($wgCapitalLinks) {
             $comparableName = $wgContLang->ucfirst($comparableName);
         }
         if ($comparableName !== $filtered) {
             $warning .= '<li>' . wfMsgHtml('badfilename', htmlspecialchars($this->mDestName)) . '</li>';
         }
         global $wgCheckFileExtensions;
         if ($wgCheckFileExtensions) {
             if (!$this->checkFileExtension($finalExt, $wgFileExtensions)) {
                 global $wgLang;
                 $warning .= '<li>' . wfMsgExt('filetype-unwanted-type', array('parseinline'), htmlspecialchars($finalExt), $wgLang->commaList($wgFileExtensions), $wgLang->formatNum(count($wgFileExtensions))) . '</li>';
             }
         }
         global $wgUploadSizeWarning;
         if ($wgUploadSizeWarning && $this->mFileSize > $wgUploadSizeWarning) {
             $skin = $wgUser->getSkin();
             $wsize = $skin->formatSize($wgUploadSizeWarning);
             $asize = $skin->formatSize($this->mFileSize);
             $warning .= '<li>' . wfMsgHtml('large-file', $wsize, $asize) . '</li>';
         }
         if ($this->mFileSize == 0) {
             $warning .= '<li>' . wfMsgHtml('emptyfile') . '</li>';
         }
         if (!$this->mDestWarningAck) {
             $warning .= self::getExistsWarning($this->mLocalFile);
         }
         $warning .= $this->getDupeWarning($this->mTempPath, $finalExt, $nt);
         if ($warning != '') {
             /**
              * Stash the file in a temporary location; the user can choose
              * to let it through and we'll complete the upload then.
              */
             $resultDetails = array('warning' => $warning);
             return self::UPLOAD_WARNING;
         }
     }
     /**
      * Try actually saving the thing...
      * It will show an error form on failure.
      */
     if (!$this->mForReUpload) {
         $pageText = self::getInitialPageText($this->mComment, $this->mLicense, $this->mCopyrightStatus, $this->mCopyrightSource);
     }
     $status = $this->mLocalFile->upload($this->mTempPath, $this->mComment, $pageText, File::DELETE_SOURCE, $this->mFileProps);
     if (!$status->isGood()) {
         $resultDetails = array('internal' => $status->getWikiText());
         return self::INTERNAL_ERROR;
     } else {
         if ($this->mWatchthis) {
             global $wgUser;
             $wgUser->addWatch($this->mLocalFile->getTitle());
         }
         // Success, redirect to description page
         $img = null;
         // @todo: added to avoid passing a ref to null - should this be defined somewhere?
         wfRunHooks('UploadComplete', array(&$this));
         return self::SUCCESS;
     }
 }
    /**
     * Show the special page.
     *
     * @param $par Mixed: parameter passed to the special page or null
     */
    public function execute($par)
    {
        global $wgRequest, $wgOut, $wgUser;
        if (wfReadOnly()) {
            $wgOut->readOnlyPage();
            return;
        }
        $this->setHeaders();
        if ($wgRequest->wasPosted()) {
            // 1. Retrieve POST vars. First, we want "crOrigTitle", holding the
            // title of the page we're writing to, and "crRedirectTitle",
            // holding the title of the page we're redirecting to.
            $crOrigTitle = $wgRequest->getText('crOrigTitle');
            $crRedirectTitle = $wgRequest->getText('crRedirectTitle');
            // 2. We need to construct a "FauxRequest", or fake a request that
            // MediaWiki would otherwise get naturally by a client browser to
            // do whatever it has to do. Let's put together the params.
            $title = $crOrigTitle;
            // a. We know our title, so we can instantiate a "Title" and
            // "Article" object. We don't actually plug this into the
            // FauxRequest, but they're required for the writing process,
            // and they contain important information on the article in
            // question that's being edited.
            $crEditTitle = Title::newFromText($crOrigTitle);
            // First, construct "Title". "Article" relies on the former object being set.
            $crEditArticle = new Article($crEditTitle, 0);
            // Then, construct "Article". This is where most of the article's information is.
            $wpStarttime = wfTimestampNow();
            // POST var "wpStarttime" stores when the edit was started.
            $wpEdittime = $crEditArticle->getTimestamp();
            // POST var "wpEdittime" stores when the article was ''last edited''. This is used to check against edit conflicts, and also why we needed to construct "Article" so early. "Article" contains the article's last edittime.
            $wpTextbox1 = "#REDIRECT [[{$crRedirectTitle}]]\r\n";
            // POST var "wpTextbox1" stores the content that's actually going to be written. This is where we write the #REDIRECT [[Article]] stuff. We plug in $crRedirectTitle here.
            $wpSave = 1;
            $wpMinoredit = 1;
            // TODO: Decide on this; should this really be marked and hardcoded as a minor edit, or not? Or should we provide an option? --Digi 11/4/07
            $wpEditToken = htmlspecialchars($wgUser->editToken());
            // 3. Put together the params that we'll use in "FauxRequest" into a single array.
            $crRequestParams = array('title' => $title, 'wpStarttime' => $wpStarttime, 'wpEdittime' => $wpEdittime, 'wpTextbox1' => $wpTextbox1, 'wpSave' => $wpSave, 'wpMinoredit' => $wpMinoredit, 'wpEditToken' => $wpEditToken);
            // 4. Construct "FauxRequest"! Using a FauxRequest object allows
            // for a transparent interface of generated request params that
            // aren't retrieved from the client itself (i.e. $_REQUEST).
            // It's a very useful tool.
            $crRequest = new FauxRequest($crRequestParams, true);
            // 5. Construct "EditPage", which contains routines to write all
            // the data. This is where all the magic happens.
            $crEdit = new EditPage($crEditArticle);
            // We plug in the "Article" object here so EditPage can center on the article that we need to edit.
            // a. We have to plug in the correct information that we just
            // generated. While we fed EditPage with the correct "Article"
            // object, it doesn't have the correct "Title" object.
            // The "Title" object actually points to Special:CreateRedirect,
            // which don't do us any good. Instead, explicitly plug in the
            // correct objects; the objects "Article" and "Title" that we
            // generated earlier. This will center EditPage on the correct article.
            $crEdit->mArticle = $crEditArticle;
            $crEdit->mTitle = $crEditTitle;
            // b. Then import the "form data" (or the FauxRequest object that
            // we just constructed). EditPage now has all the information we
            // generated.
            $crEdit->importFormData($crRequest);
            $permErrors = $crEditTitle->getUserPermissionsErrors('edit', $wgUser);
            // Can this title be created?
            if (!$crEditTitle->exists()) {
                $permErrors = array_merge($permErrors, wfArrayDiff2($crEditTitle->getUserPermissionsErrors('create', $wgUser), $permErrors));
            }
            if ($permErrors) {
                wfDebug(__METHOD__ . ": User can't edit\n");
                $wgOut->addWikiText($crEdit->formatPermissionsErrorMessage($permErrors, 'edit'));
                wfProfileOut(__METHOD__);
                return;
            }
            $resultDetails = false;
            $status = $crEdit->internalAttemptSave($resultDetails, $wgUser->isAllowed('bot') && $wgRequest->getBool('bot', true));
            $value = $status->value;
            if ($value == EditPage::AS_SUCCESS_UPDATE || $value == EditPage::AS_SUCCESS_NEW_ARTICLE) {
                $wgOut->wrapWikiMsg("<div class=\"mw-createredirect-done\">\n\$1</div>", array('createredirect-redirect-done', $crOrigTitle, $crRedirectTitle));
            }
            switch ($value) {
                case EditPage::AS_SPAM_ERROR:
                    $crEdit->spamPageWithContent($resultDetails['spam']);
                    return;
                case EditPage::AS_BLOCKED_PAGE_FOR_USER:
                    $crEdit->blockedPage();
                    return;
                case EditPage::AS_READ_ONLY_PAGE_ANON:
                    $crEdit->userNotLoggedInPage();
                    return;
                case EditPage::AS_READ_ONLY_PAGE_LOGGED:
                case EditPage::AS_READ_ONLY_PAGE:
                    $wgOut->readOnlyPage();
                    return;
                case EditPage::AS_RATE_LIMITED:
                    $wgOut->rateLimited();
                    break;
                case EditPage::AS_NO_CREATE_PERMISSION:
                    $crEdit->noCreatePermission();
                    return;
            }
            $wgOut->mRedirect = '';
            $wgOut->mRedirectCode = '';
            // TODO: Implement error handling (i.e. "Edit conflict!" or "You don't have permissions to edit this page!") --Digi 11/4/07
        }
        $action = htmlspecialchars($this->getTitle()->getLocalURL());
        // Also retrieve "crTitle". If this GET var is found, we autofill the
        // "Redirect to:" field with that text.
        $crTitle = $wgRequest->getText('crRedirectTitle', $wgRequest->getText('crTitle', $par));
        $crTitle = Title::newFromText($crTitle);
        $crTitle = htmlspecialchars(isset($crTitle) ? $crTitle->getPrefixedText() : '');
        $msgPageTitle = wfMsgHtml('createredirect-page-title');
        $msgRedirectTo = wfMsgHtml('createredirect-redirect-to');
        $msgSave = wfMsgHtml('createredirect-save');
        // 2. Start rendering the output! The output is entirely the form.
        // It's all HTML, and may be self-explanatory.
        $wgOut->addHTML(wfMsgHtml('createredirect-instructions'));
        $wgOut->addHTML(<<<END
<form id="redirectform" name="redirectform" method="post" action="{$action}">
<table>
<tr>
<td><label for="crOrigTitle">{$msgPageTitle}</label></td>
<td><input type="text" name="crOrigTitle" id="crOrigTitle" size="60" tabindex="1" /></td>
</tr>
<tr>
<td><label for="crRedirectTitle">{$msgRedirectTo}</label></td>
<td><input type="text" name="crRedirectTitle" id="crRedirectTitle" value="{$crTitle}" size="60" tabindex="2" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" name="crWrite" id="crWrite" value="{$msgSave}" tabindex="4" /></td>
</tr>
</table>
</form>
END
);
    }
Beispiel #12
0
 /**
  *
  * @param Title $related_title The title the talk is related to
  * @param User $user
  * @param string $content
  * @return Title
  */
 public static function createTalk($related_title, $user, $content = '-')
 {
     if (!$related_title instanceof Title || !$user instanceof User) {
         throw new MWException('Cannot create talk page (wrong argument)');
     }
     if (!$related_title->canTalk()) {
         return array('sz-internal-error');
     }
     $talk = $related_title->getTalkPage();
     if (!$talk instanceof Title) {
         return array('sz-internal-error');
     }
     if ($talk->isKnown()) {
         return array('wp-title-already-exists');
     }
     // as seen in EditPage->getEditPermissionErrors() ( called by EditPage->edit() )
     $permErrors = $talk->getUserPermissionsErrors('edit', $user);
     $permErrors = array_merge($permErrors, wfArrayDiff2($talk->getUserPermissionsErrors('create', $user), $permErrors));
     if ($permErrors) {
         // creation impossible
         return $permErrors[0];
         // strange, but only key 0 seems to be used by MW when reading errors
     }
     // now store the new page in mediawiki, this will trigger the WikiplaceHook, wich will
     // allow the page saving
     $article = new Article($talk);
     $status = $article->doEdit($content, '', EDIT_NEW, false, $user);
     if (!$status->isgood()) {
         return array('sz-internal-error');
     }
     return $talk;
 }