Go to the documentation of this file.
45 $titleObj = $pageObj->getTitle();
48 if ( $params[
'redirect'] ) {
49 if ( $params[
'prependtext'] ===
null && $params[
'appendtext'] ===
null
50 && $params[
'section'] !==
'new'
54 if ( $titleObj->isRedirect() ) {
55 $oldTitle = $titleObj;
58 ->getContent( RevisionRecord::FOR_THIS_USER, $user )
65 foreach ( $titles as $id => $newTitle ) {
66 $titles[$id - 1] = $titles[$id - 1] ?? $oldTitle;
69 'from' => $titles[$id - 1]->getPrefixedText(),
70 'to' => $newTitle->getPrefixedText()
73 $titleObj = $newTitle;
76 if ( $titleObj->isExternal() || !$titleObj->canExist() ) {
77 $redirValues[count( $redirValues ) - 1][
'to'] = $titleObj->getFullText();
80 'apierror-edit-invalidredirect',
81 Message::plaintextParam( $oldTitle->getPrefixedText() ),
82 Message::plaintextParam( $titleObj->getFullText() ),
84 'edit-invalidredirect',
85 [
'redirects' => $redirValues ]
91 $apiResult->addValue(
null,
'redirects', $redirValues );
98 if ( !isset( $params[
'contentmodel'] ) || $params[
'contentmodel'] ==
'' ) {
99 $contentHandler = $pageObj->getContentHandler();
103 $contentModel = $contentHandler->getModelID();
105 $name = $titleObj->getPrefixedDBkey();
106 $model = $contentHandler->getModelID();
108 if ( $params[
'undo'] > 0 ) {
110 } elseif ( $contentHandler->supportsDirectApiEditing() === false ) {
111 $this->
dieWithError( [
'apierror-no-direct-editing', $model, $name ] );
114 if ( !isset( $params[
'contentformat'] ) || $params[
'contentformat'] ==
'' ) {
115 $contentFormat = $contentHandler->getDefaultFormat();
117 $contentFormat = $params[
'contentformat'];
120 if ( !$contentHandler->isSupportedFormat( $contentFormat ) ) {
121 $this->
dieWithError( [
'apierror-badformat', $contentFormat, $model, $name ] );
124 if ( $params[
'createonly'] && $titleObj->exists() ) {
127 if ( $params[
'nocreate'] && !$titleObj->exists() ) {
134 $titleObj->exists() ?
'edit' : [
'edit',
'create' ],
135 [
'autoblock' =>
true ]
138 $toMD5 = $params[
'text'];
139 if ( !is_null( $params[
'appendtext'] ) || !is_null( $params[
'prependtext'] ) ) {
144 # If this is a MediaWiki:x message, then load the messages
145 # and return the message value for x.
146 $text = $titleObj->getDefaultMessageText();
147 if ( $text ===
false ) {
155 'wrap' =>
ApiMessage::create(
'apierror-contentserializationexception',
'parseerror' )
160 # Otherwise, make a new empty content.
161 $content = $contentHandler->makeEmptyContent();
168 $modelName = $contentHandler->getModelID();
169 $this->
dieWithError( [
'apierror-appendnotsupported', $modelName ] );
172 if ( !is_null( $params[
'section'] ) ) {
173 if ( !$contentHandler->supportsSections() ) {
174 $modelName = $contentHandler->getModelID();
175 $this->
dieWithError( [
'apierror-sectionsnotsupported', $modelName ] );
178 if ( $params[
'section'] ==
'new' ) {
183 $section = $params[
'section'];
195 $text =
$content->serialize( $contentFormat );
198 $params[
'text'] = $params[
'prependtext'] . $text . $params[
'appendtext'];
199 $toMD5 = $params[
'prependtext'] . $params[
'appendtext'];
202 if ( $params[
'undo'] > 0 ) {
203 if ( $params[
'undoafter'] > 0 ) {
204 if ( $params[
'undo'] < $params[
'undoafter'] ) {
205 list( $params[
'undo'], $params[
'undoafter'] ) =
206 [ $params[
'undoafter'], $params[
'undo'] ];
211 if ( is_null( $undoRev ) || $undoRev->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
212 $this->
dieWithError( [
'apierror-nosuchrevid', $params[
'undo'] ] );
215 if ( $params[
'undoafter'] == 0 ) {
216 $undoafterRev = $undoRev->getPrevious();
218 if ( is_null( $undoafterRev ) || $undoafterRev->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
219 $this->
dieWithError( [
'apierror-nosuchrevid', $params[
'undoafter'] ] );
222 if ( $undoRev->getPage() != $pageObj->getId() ) {
223 $this->
dieWithError( [
'apierror-revwrongpage', $undoRev->getId(),
224 $titleObj->getPrefixedText() ] );
226 if ( $undoafterRev->getPage() != $pageObj->getId() ) {
227 $this->
dieWithError( [
'apierror-revwrongpage', $undoafterRev->getId(),
228 $titleObj->getPrefixedText() ] );
231 $newContent = $contentHandler->getUndoContent(
232 $pageObj->getRevision(),
237 if ( !$newContent ) {
240 if ( empty( $params[
'contentmodel'] )
241 && empty( $params[
'contentformat'] )
248 if ( !$newContent->isSupportedFormat( $contentFormat ) ) {
249 $contentFormat = $undoafterRev->getContentFormat();
252 $contentModel = $newContent->getModel();
254 $params[
'text'] = $newContent->serialize( $contentFormat );
258 if ( is_null( $params[
'summary'] ) ) {
259 $nextRev = MediaWikiServices::getInstance()->getRevisionLookup()
260 ->getNextRevision( $undoafterRev->getRevisionRecord() );
261 if ( $nextRev && $nextRev->getId() == $params[
'undo'] ) {
262 $params[
'summary'] =
wfMessage(
'undo-summary' )
263 ->params( $params[
'undo'], $undoRev->getUserText() )
264 ->inContentLanguage()->text();
270 if ( !is_null( $params[
'md5'] ) && md5( $toMD5 ) !== $params[
'md5'] ) {
277 'wpTextbox1' => $params[
'text'],
278 'format' => $contentFormat,
279 'model' => $contentModel,
280 'wpEditToken' => $params[
'token'],
281 'wpIgnoreBlankSummary' =>
true,
282 'wpIgnoreBlankArticle' =>
true,
283 'wpIgnoreSelfRedirect' =>
true,
284 'bot' => $params[
'bot'],
288 if ( !is_null( $params[
'summary'] ) ) {
289 $requestArray[
'wpSummary'] = $params[
'summary'];
292 if ( !is_null( $params[
'sectiontitle'] ) ) {
293 $requestArray[
'wpSectionTitle'] = $params[
'sectiontitle'];
297 if ( $params[
'undo'] > 0 ) {
298 $requestArray[
'wpUndidRevision'] = $params[
'undo'];
303 if ( $params[
'basetimestamp'] !==
null && (
bool)$this->
getMain()->getVal(
'basetimestamp' ) ) {
304 $requestArray[
'wpEdittime'] = $params[
'basetimestamp'];
306 $requestArray[
'wpEdittime'] = $pageObj->getTimestamp();
309 if ( $params[
'starttimestamp'] !==
null ) {
310 $requestArray[
'wpStarttime'] = $params[
'starttimestamp'];
315 if ( $params[
'minor'] || ( !$params[
'notminor'] && $user->getOption(
'minordefault' ) ) ) {
316 $requestArray[
'wpMinoredit'] =
'';
319 if ( $params[
'recreate'] ) {
320 $requestArray[
'wpRecreate'] =
'';
323 if ( !is_null( $params[
'section'] ) ) {
324 $section = $params[
'section'];
325 if ( !preg_match(
'/^((T-)?\d+|new)$/', $section ) ) {
329 if ( $section !==
'0' && $section !=
'new'
332 $this->
dieWithError( [
'apierror-nosuchsection', $section ] );
334 $requestArray[
'wpSection'] = $params[
'section'];
336 $requestArray[
'wpSection'] =
'';
342 if ( $params[
'watch'] ) {
344 } elseif ( $params[
'unwatch'] ) {
349 $requestArray[
'wpWatchthis'] =
'';
353 if ( $params[
'tags'] ) {
355 if ( $tagStatus->isOK() ) {
356 $requestArray[
'wpChangeTags'] = implode(
',', $params[
'tags'] );
364 $requestArray += $this->
getRequest()->getValues();
376 $articleContext->setWikiPage( $pageObj );
377 $articleContext->setUser( $this->
getUser() );
382 $ep =
new EditPage( $articleObject );
384 $ep->setApiEditOverride(
true );
385 $ep->setContextTitle( $titleObj );
386 $ep->importFormData( $req );
390 $oldRevId = $articleObject->getRevIdFetched();
397 $status = $ep->attemptSave( $result );
404 if ( isset(
$status->apiHookResult ) ) {
406 $r[
'result'] =
'Failure';
413 $status->fatal(
'hookaborted' );
434 $r[
'result'] =
'Success';
435 $r[
'pageid'] = (int)$titleObj->getArticleID();
436 $r[
'title'] = $titleObj->getPrefixedText();
437 $r[
'contentmodel'] = $articleObject->getContentModel();
438 $newRevId = $articleObject->getLatest();
439 if ( $newRevId == $oldRevId ) {
440 $r[
'nochange'] =
true;
442 $r[
'oldrevid'] = (int)$oldRevId;
443 $r[
'newrevid'] = (int)$newRevId;
445 $pageObj->getTimestamp() );
456 $status->fatal(
'apierror-noimageredirect-anon' );
459 $status->fatal(
'apierror-noimageredirect' );
463 $status->fatal(
'apierror-contenttoobig', $this->
getConfig()->
get(
'MaxArticleSize' ) );
466 $status->fatal(
'apierror-noedit-anon' );
469 $status->fatal(
'apierror-cantchangecontentmodel' );
472 $status->fatal(
'apierror-pagedeleted' );
475 $status->fatal(
'editconflict' );
483 $status->fatal(
'apierror-spamdetected', $result[
'spam'] );
486 $status->fatal(
'apierror-noedit' );
489 $status->fatal(
'apierror-ratelimited' );
492 $status->fatal(
'nocreate-loggedin' );
495 $status->fatal(
'apierror-emptypage' );
498 $status->fatal(
'apierror-emptynewsection' );
501 $status->fatal(
'apierror-summaryrequired' );
504 wfWarn( __METHOD__ .
": Unknown EditPage code {$status->value} with no message" );
505 $status->fatal(
'apierror-unknownerror-editpage',
$status->value );
549 'starttimestamp' => [
553 'createonly' =>
false,
612 'action=edit&title=Test&summary=test%20summary&' .
613 'text=article%20content&basetimestamp=2007-08-24T12:34:54Z&token=123ABC'
614 =>
'apihelp-edit-example-edit',
615 'action=edit&title=Test&summary=NOTOC&minor=&' .
616 'prependtext=__NOTOC__%0A&basetimestamp=2007-08-24T12:34:54Z&token=123ABC'
617 =>
'apihelp-edit-example-prepend',
618 'action=edit&title=Test&undo=13585&undoafter=13579&' .
619 'basetimestamp=2007-08-24T12:34:54Z&token=123ABC'
620 =>
'apihelp-edit-example-undo',
625 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Edit';
A module that allows for editing and creating pages.
Similar to FauxRequest, but only fakes URL parameters and method (POST or GET) and use the base reque...
static getForModelID( $modelId)
Returns the ContentHandler singleton for the given model ID.
const AS_BLANK_ARTICLE
Status: user tried to create a blank page and wpIgnoreBlankArticle == false.
static getAllContentFormats()
getExamplesMessages()
Returns usage examples for this module.
setRequest(WebRequest $request)
static newFromId( $id, $flags=0)
Load a page revision from a given revision ID number.
getHelpUrls()
Return links to more detailed help pages about the module.
const AS_READ_ONLY_PAGE_ANON
Status: this anonymous user is not allowed to edit this page.
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
getTitleOrPageId( $params, $load=false)
Get a WikiPage object from a title or pageid param, if possible.
const PARAM_TYPE
(string|string[]) Either an array of allowed value strings, or a string type as described below.
getResult()
Get the result object.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
dieBlocked(AbstractBlock $block)
Throw an ApiUsageException, which will (if uncaught) call the main module's error handler and die wit...
const AS_HOOK_ERROR
Status: Article update aborted by a hook function.
const AS_CONTENT_TOO_BIG
Status: Content too big (> $wgMaxArticleSize)
if(! $wgRequest->checkUrlExtension()) if(isset( $_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] !='') $wgTitle
checkTitleUserPermissions(LinkTarget $linkTarget, $actions, $options=[])
Helper function for permission-denied errors.
mustBePosted()
Indicates whether this module must be called with a POST request.
const AS_BLOCKED_PAGE_FOR_USER
Status: User is blocked from editing this page.
const AS_SUMMARY_NEEDED
Status: no edit summary given and the user has forceeditsummary set and the user is not editing in hi...
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
const AS_NO_CREATE_PERMISSION
Status: user tried to create this page, but is not allowed to do that ( Title->userCan('create') == f...
This abstract class implements many basic API functions, and is the base of all API classes.
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given link target.
const PARAM_DEPRECATED
(boolean) Is the parameter deprecated (will show a warning)?
const PARAM_MIN
(integer) Lowest value allowed for the parameter, for PARAM_TYPE 'integer' and 'limit'.
const AS_SUCCESS_NEW_ARTICLE
Status: Article successfully created.
static newFromWikiPage(WikiPage $page, IContextSource $context)
Create an Article object of the appropriate class for the given page.
const UNICODE_CHECK
Used for Unicode support checks.
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
static getContentModels()
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Exception representing a failure to serialize or unserialize a content object.
dieWithException( $exception, array $options=[])
Abort execution with an error derived from an exception.
const AS_NO_CHANGE_CONTENT_MODEL
Status: user tried to modify the content model, but is not allowed to do that ( User::isAllowed('edit...
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
const AS_READ_ONLY_PAGE
Status: wiki is in readonly mode (wfReadOnly() == true)
const AS_SPAM_ERROR
Status: summary contained spam according to one of the regexes in $wgSummarySpamRegex.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Group all the pieces relevant to the context of a request into one instance.
const AS_MAX_ARTICLE_SIZE_EXCEEDED
Status: article is too big (> $wgMaxArticleSize), after merging in the new section.
static create( $msg, $code=null, array $data=null)
Create an IApiMessage for the message.
getWatchlistValue( $watchlist, $titleObj, $userOption=null)
Return true if we're to watch the page, false if not, null if no change.
static makeContent( $text, Title $title=null, $modelId=null, $format=null)
Convenience function for creating a Content object from a given textual representation.
const AS_SUCCESS_UPDATE
Status: Article successfully updated.
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
dieReadOnly()
Helper function for readonly errors.
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
const AS_IMAGE_REDIRECT_LOGGED
Status: logged in user is not allowed to upload (User::isAllowed('upload') == false)
isWriteMode()
Indicates whether this module requires write mode.
Content object implementation for representing flat text.
The edit page/HTML interface (split from Article) The actual database and text munging is still in Ar...
const PARAM_RANGE_ENFORCE
(boolean) For PARAM_TYPE 'integer', enforce PARAM_MIN and PARAM_MAX?
requireAtLeastOneParameter( $params, $required)
Die if none of a certain set of parameters is set and not false.
Represents a title within MediaWiki.
const PARAM_DFLT
(null|boolean|integer|string) Default value of the parameter.
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
getModuleName()
Get the name of the module being executed by this instance.
const PARAM_ISMULTI
(boolean) Accept multiple pipe-separated values for this parameter (e.g.
const AS_READ_ONLY_PAGE_LOGGED
Status: this logged in user is not allowed to edit this page.
const AS_CONFLICT_DETECTED
Status: (non-resolvable) edit conflict.
const AS_RATE_LIMITED
Status: rate limiter for action 'edit' was tripped.
getMain()
Get the main module.
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
const AS_IMAGE_REDIRECT_ANON
Status: anonymous user is not allowed to upload (User::isAllowed('upload') == false)
if(! $wgDBerrorLogTZ) $wgRequest
needsToken()
Returns the token type this module requires in order to execute.
const AS_ARTICLE_WAS_DELETED
Status: article was deleted while editing and param wpRecreate == false or form was not posted.
const AS_HOOK_ERROR_EXPECTED
Status: A hook function returned an error.
const AS_TEXTBOX_EMPTY
Status: user tried to create a new section without content.