This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * This program is free software; you can redistribute it and/or modify |
||
5 | * it under the terms of the GNU General Public License as published by |
||
6 | * the Free Software Foundation; either version 2 of the License, or |
||
7 | * (at your option) any later version. |
||
8 | * |
||
9 | * This program is distributed in the hope that it will be useful, |
||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
12 | * GNU General Public License for more details. |
||
13 | * |
||
14 | * You should have received a copy of the GNU General Public License along |
||
15 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
17 | * http://www.gnu.org/copyleft/gpl.html |
||
18 | * |
||
19 | * @file |
||
20 | */ |
||
21 | |||
22 | use MediaWiki\MediaWikiServices; |
||
23 | |||
24 | /** |
||
25 | * Handles the backend logic of moving a page from one title |
||
26 | * to another. |
||
27 | * |
||
28 | * @since 1.24 |
||
29 | */ |
||
30 | class MovePage { |
||
31 | |||
32 | /** |
||
33 | * @var Title |
||
34 | */ |
||
35 | protected $oldTitle; |
||
36 | |||
37 | /** |
||
38 | * @var Title |
||
39 | */ |
||
40 | protected $newTitle; |
||
41 | |||
42 | public function __construct( Title $oldTitle, Title $newTitle ) { |
||
43 | $this->oldTitle = $oldTitle; |
||
44 | $this->newTitle = $newTitle; |
||
45 | } |
||
46 | |||
47 | public function checkPermissions( User $user, $reason ) { |
||
48 | $status = new Status(); |
||
49 | |||
50 | $errors = wfMergeErrorArrays( |
||
51 | $this->oldTitle->getUserPermissionsErrors( 'move', $user ), |
||
52 | $this->oldTitle->getUserPermissionsErrors( 'edit', $user ), |
||
53 | $this->newTitle->getUserPermissionsErrors( 'move-target', $user ), |
||
54 | $this->newTitle->getUserPermissionsErrors( 'edit', $user ) |
||
55 | ); |
||
56 | |||
57 | // Convert into a Status object |
||
58 | if ( $errors ) { |
||
59 | foreach ( $errors as $error ) { |
||
60 | call_user_func_array( [ $status, 'fatal' ], $error ); |
||
61 | } |
||
62 | } |
||
63 | |||
64 | if ( EditPage::matchSummarySpamRegex( $reason ) !== false ) { |
||
65 | // This is kind of lame, won't display nice |
||
66 | $status->fatal( 'spamprotectiontext' ); |
||
67 | } |
||
68 | |||
69 | $tp = $this->newTitle->getTitleProtection(); |
||
70 | if ( $tp !== false && !$user->isAllowed( $tp['permission'] ) ) { |
||
71 | $status->fatal( 'cantmove-titleprotected' ); |
||
72 | } |
||
73 | |||
74 | Hooks::run( 'MovePageCheckPermissions', |
||
75 | [ $this->oldTitle, $this->newTitle, $user, $reason, $status ] |
||
76 | ); |
||
77 | |||
78 | return $status; |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * Does various sanity checks that the move is |
||
83 | * valid. Only things based on the two titles |
||
84 | * should be checked here. |
||
85 | * |
||
86 | * @return Status |
||
87 | */ |
||
88 | public function isValidMove() { |
||
89 | global $wgContentHandlerUseDB; |
||
90 | $status = new Status(); |
||
91 | |||
92 | if ( $this->oldTitle->equals( $this->newTitle ) ) { |
||
93 | $status->fatal( 'selfmove' ); |
||
94 | } |
||
95 | if ( !$this->oldTitle->isMovable() ) { |
||
96 | $status->fatal( 'immobile-source-namespace', $this->oldTitle->getNsText() ); |
||
97 | } |
||
98 | if ( $this->newTitle->isExternal() ) { |
||
99 | $status->fatal( 'immobile-target-namespace-iw' ); |
||
100 | } |
||
101 | if ( !$this->newTitle->isMovable() ) { |
||
102 | $status->fatal( 'immobile-target-namespace', $this->newTitle->getNsText() ); |
||
103 | } |
||
104 | |||
105 | $oldid = $this->oldTitle->getArticleID(); |
||
106 | |||
107 | if ( strlen( $this->newTitle->getDBkey() ) < 1 ) { |
||
108 | $status->fatal( 'articleexists' ); |
||
109 | } |
||
110 | if ( |
||
111 | ( $this->oldTitle->getDBkey() == '' ) || |
||
112 | ( !$oldid ) || |
||
113 | ( $this->newTitle->getDBkey() == '' ) |
||
114 | ) { |
||
115 | $status->fatal( 'badarticleerror' ); |
||
116 | } |
||
117 | |||
118 | # The move is allowed only if (1) the target doesn't exist, or |
||
119 | # (2) the target is a redirect to the source, and has no history |
||
120 | # (so we can undo bad moves right after they're done). |
||
121 | if ( $this->newTitle->getArticleID() && !$this->isValidMoveTarget() ) { |
||
122 | $status->fatal( 'articleexists' ); |
||
123 | } |
||
124 | |||
125 | // Content model checks |
||
126 | if ( !$wgContentHandlerUseDB && |
||
127 | $this->oldTitle->getContentModel() !== $this->newTitle->getContentModel() ) { |
||
128 | // can't move a page if that would change the page's content model |
||
129 | $status->fatal( |
||
130 | 'bad-target-model', |
||
131 | ContentHandler::getLocalizedName( $this->oldTitle->getContentModel() ), |
||
132 | ContentHandler::getLocalizedName( $this->newTitle->getContentModel() ) |
||
133 | ); |
||
134 | } elseif ( |
||
135 | !ContentHandler::getForTitle( $this->oldTitle )->canBeUsedOn( $this->newTitle ) |
||
136 | ) { |
||
137 | $status->fatal( |
||
138 | 'content-not-allowed-here', |
||
139 | ContentHandler::getLocalizedName( $this->oldTitle->getContentModel() ), |
||
140 | $this->newTitle->getPrefixedText() |
||
141 | ); |
||
142 | } |
||
143 | |||
144 | // Image-specific checks |
||
145 | if ( $this->oldTitle->inNamespace( NS_FILE ) ) { |
||
146 | $status->merge( $this->isValidFileMove() ); |
||
147 | } |
||
148 | |||
149 | if ( $this->newTitle->inNamespace( NS_FILE ) && !$this->oldTitle->inNamespace( NS_FILE ) ) { |
||
150 | $status->fatal( 'nonfile-cannot-move-to-file' ); |
||
151 | } |
||
152 | |||
153 | // Hook for extensions to say a title can't be moved for technical reasons |
||
154 | Hooks::run( 'MovePageIsValidMove', [ $this->oldTitle, $this->newTitle, $status ] ); |
||
155 | |||
156 | return $status; |
||
157 | } |
||
158 | |||
159 | /** |
||
160 | * Sanity checks for when a file is being moved |
||
161 | * |
||
162 | * @return Status |
||
163 | */ |
||
164 | protected function isValidFileMove() { |
||
165 | $status = new Status(); |
||
166 | $file = wfLocalFile( $this->oldTitle ); |
||
167 | $file->load( File::READ_LATEST ); |
||
168 | if ( $file->exists() ) { |
||
169 | if ( $this->newTitle->getText() != wfStripIllegalFilenameChars( $this->newTitle->getText() ) ) { |
||
170 | $status->fatal( 'imageinvalidfilename' ); |
||
171 | } |
||
172 | if ( !File::checkExtensionCompatibility( $file, $this->newTitle->getDBkey() ) ) { |
||
0 ignored issues
–
show
The expression
\File::checkExtensionCom...->newTitle->getDBkey()) of type null|boolean is loosely compared to false ; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.
If an expression can have both $a = canBeFalseAndNull();
// Instead of
if ( ! $a) { }
// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
![]() |
|||
173 | $status->fatal( 'imagetypemismatch' ); |
||
174 | } |
||
175 | } |
||
176 | |||
177 | if ( !$this->newTitle->inNamespace( NS_FILE ) ) { |
||
178 | $status->fatal( 'imagenocrossnamespace' ); |
||
179 | } |
||
180 | |||
181 | return $status; |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * Checks if $this can be moved to a given Title |
||
186 | * - Selects for update, so don't call it unless you mean business |
||
187 | * |
||
188 | * @since 1.25 |
||
189 | * @return bool |
||
190 | */ |
||
191 | protected function isValidMoveTarget() { |
||
192 | # Is it an existing file? |
||
193 | if ( $this->newTitle->inNamespace( NS_FILE ) ) { |
||
194 | $file = wfLocalFile( $this->newTitle ); |
||
195 | $file->load( File::READ_LATEST ); |
||
196 | if ( $file->exists() ) { |
||
197 | wfDebug( __METHOD__ . ": file exists\n" ); |
||
198 | return false; |
||
199 | } |
||
200 | } |
||
201 | # Is it a redirect with no history? |
||
202 | if ( !$this->newTitle->isSingleRevRedirect() ) { |
||
203 | wfDebug( __METHOD__ . ": not a one-rev redirect\n" ); |
||
204 | return false; |
||
205 | } |
||
206 | # Get the article text |
||
207 | $rev = Revision::newFromTitle( $this->newTitle, false, Revision::READ_LATEST ); |
||
208 | if ( !is_object( $rev ) ) { |
||
209 | return false; |
||
210 | } |
||
211 | $content = $rev->getContent(); |
||
212 | # Does the redirect point to the source? |
||
213 | # Or is it a broken self-redirect, usually caused by namespace collisions? |
||
214 | $redirTitle = $content ? $content->getRedirectTarget() : null; |
||
215 | |||
216 | if ( $redirTitle ) { |
||
217 | if ( $redirTitle->getPrefixedDBkey() !== $this->oldTitle->getPrefixedDBkey() && |
||
218 | $redirTitle->getPrefixedDBkey() !== $this->newTitle->getPrefixedDBkey() ) { |
||
219 | wfDebug( __METHOD__ . ": redirect points to other page\n" ); |
||
220 | return false; |
||
221 | } else { |
||
222 | return true; |
||
223 | } |
||
224 | } else { |
||
225 | # Fail safe (not a redirect after all. strange.) |
||
226 | wfDebug( __METHOD__ . ": failsafe: database says " . $this->newTitle->getPrefixedDBkey() . |
||
227 | " is a redirect, but it doesn't contain a valid redirect.\n" ); |
||
228 | return false; |
||
229 | } |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * @param User $user |
||
234 | * @param string $reason |
||
235 | * @param bool $createRedirect |
||
236 | * @return Status |
||
237 | */ |
||
238 | public function move( User $user, $reason, $createRedirect ) { |
||
239 | global $wgCategoryCollation; |
||
240 | |||
241 | Hooks::run( 'TitleMove', [ $this->oldTitle, $this->newTitle, $user ] ); |
||
242 | |||
243 | // If it is a file, move it first. |
||
244 | // It is done before all other moving stuff is done because it's hard to revert. |
||
245 | $dbw = wfGetDB( DB_MASTER ); |
||
246 | if ( $this->oldTitle->getNamespace() == NS_FILE ) { |
||
247 | $file = wfLocalFile( $this->oldTitle ); |
||
248 | $file->load( File::READ_LATEST ); |
||
249 | if ( $file->exists() ) { |
||
250 | $status = $file->move( $this->newTitle ); |
||
251 | if ( !$status->isOK() ) { |
||
252 | return $status; |
||
253 | } |
||
254 | } |
||
255 | // Clear RepoGroup process cache |
||
256 | RepoGroup::singleton()->clearCache( $this->oldTitle ); |
||
257 | RepoGroup::singleton()->clearCache( $this->newTitle ); # clear false negative cache |
||
258 | } |
||
259 | |||
260 | $dbw->startAtomic( __METHOD__ ); |
||
261 | |||
262 | Hooks::run( 'TitleMoveStarting', [ $this->oldTitle, $this->newTitle, $user ] ); |
||
263 | |||
264 | $pageid = $this->oldTitle->getArticleID( Title::GAID_FOR_UPDATE ); |
||
265 | $protected = $this->oldTitle->isProtected(); |
||
266 | |||
267 | // Do the actual move; if this fails, it will throw an MWException(!) |
||
268 | $nullRevision = $this->moveToInternal( $user, $this->newTitle, $reason, $createRedirect ); |
||
269 | |||
270 | // Refresh the sortkey for this row. Be careful to avoid resetting |
||
271 | // cl_timestamp, which may disturb time-based lists on some sites. |
||
272 | // @todo This block should be killed, it's duplicating code |
||
273 | // from LinksUpdate::getCategoryInsertions() and friends. |
||
274 | $prefixes = $dbw->select( |
||
275 | 'categorylinks', |
||
276 | [ 'cl_sortkey_prefix', 'cl_to' ], |
||
277 | [ 'cl_from' => $pageid ], |
||
278 | __METHOD__ |
||
279 | ); |
||
280 | View Code Duplication | if ( $this->newTitle->getNamespace() == NS_CATEGORY ) { |
|
281 | $type = 'subcat'; |
||
282 | } elseif ( $this->newTitle->getNamespace() == NS_FILE ) { |
||
283 | $type = 'file'; |
||
284 | } else { |
||
285 | $type = 'page'; |
||
286 | } |
||
287 | foreach ( $prefixes as $prefixRow ) { |
||
288 | $prefix = $prefixRow->cl_sortkey_prefix; |
||
289 | $catTo = $prefixRow->cl_to; |
||
290 | $dbw->update( 'categorylinks', |
||
291 | [ |
||
292 | 'cl_sortkey' => Collation::singleton()->getSortKey( |
||
293 | $this->newTitle->getCategorySortkey( $prefix ) ), |
||
294 | 'cl_collation' => $wgCategoryCollation, |
||
295 | 'cl_type' => $type, |
||
296 | 'cl_timestamp=cl_timestamp' ], |
||
297 | [ |
||
298 | 'cl_from' => $pageid, |
||
299 | 'cl_to' => $catTo ], |
||
300 | __METHOD__ |
||
301 | ); |
||
302 | } |
||
303 | |||
304 | $redirid = $this->oldTitle->getArticleID(); |
||
305 | |||
306 | if ( $protected ) { |
||
307 | # Protect the redirect title as the title used to be... |
||
308 | $res = $dbw->select( |
||
309 | 'page_restrictions', |
||
310 | '*', |
||
311 | [ 'pr_page' => $pageid ], |
||
312 | __METHOD__, |
||
313 | 'FOR UPDATE' |
||
314 | ); |
||
315 | $rowsInsert = []; |
||
316 | foreach ( $res as $row ) { |
||
317 | $rowsInsert[] = [ |
||
318 | 'pr_page' => $redirid, |
||
319 | 'pr_type' => $row->pr_type, |
||
320 | 'pr_level' => $row->pr_level, |
||
321 | 'pr_cascade' => $row->pr_cascade, |
||
322 | 'pr_user' => $row->pr_user, |
||
323 | 'pr_expiry' => $row->pr_expiry |
||
324 | ]; |
||
325 | } |
||
326 | $dbw->insert( 'page_restrictions', $rowsInsert, __METHOD__, [ 'IGNORE' ] ); |
||
327 | |||
328 | // Build comment for log |
||
329 | $comment = wfMessage( |
||
330 | 'prot_1movedto2', |
||
331 | $this->oldTitle->getPrefixedText(), |
||
332 | $this->newTitle->getPrefixedText() |
||
333 | )->inContentLanguage()->text(); |
||
334 | if ( $reason ) { |
||
335 | $comment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $reason; |
||
336 | } |
||
337 | |||
338 | // reread inserted pr_ids for log relation |
||
339 | $insertedPrIds = $dbw->select( |
||
340 | 'page_restrictions', |
||
341 | 'pr_id', |
||
342 | [ 'pr_page' => $redirid ], |
||
343 | __METHOD__ |
||
344 | ); |
||
345 | $logRelationsValues = []; |
||
346 | foreach ( $insertedPrIds as $prid ) { |
||
347 | $logRelationsValues[] = $prid->pr_id; |
||
348 | } |
||
349 | |||
350 | // Update the protection log |
||
351 | $logEntry = new ManualLogEntry( 'protect', 'move_prot' ); |
||
352 | $logEntry->setTarget( $this->newTitle ); |
||
353 | $logEntry->setComment( $comment ); |
||
354 | $logEntry->setPerformer( $user ); |
||
355 | $logEntry->setParameters( [ |
||
356 | '4::oldtitle' => $this->oldTitle->getPrefixedText(), |
||
357 | ] ); |
||
358 | $logEntry->setRelations( [ 'pr_id' => $logRelationsValues ] ); |
||
359 | $logId = $logEntry->insert(); |
||
360 | $logEntry->publish( $logId ); |
||
361 | } |
||
362 | |||
363 | // Update *_from_namespace fields as needed |
||
364 | if ( $this->oldTitle->getNamespace() != $this->newTitle->getNamespace() ) { |
||
365 | $dbw->update( 'pagelinks', |
||
366 | [ 'pl_from_namespace' => $this->newTitle->getNamespace() ], |
||
367 | [ 'pl_from' => $pageid ], |
||
368 | __METHOD__ |
||
369 | ); |
||
370 | $dbw->update( 'templatelinks', |
||
371 | [ 'tl_from_namespace' => $this->newTitle->getNamespace() ], |
||
372 | [ 'tl_from' => $pageid ], |
||
373 | __METHOD__ |
||
374 | ); |
||
375 | $dbw->update( 'imagelinks', |
||
376 | [ 'il_from_namespace' => $this->newTitle->getNamespace() ], |
||
377 | [ 'il_from' => $pageid ], |
||
378 | __METHOD__ |
||
379 | ); |
||
380 | } |
||
381 | |||
382 | # Update watchlists |
||
383 | $oldtitle = $this->oldTitle->getDBkey(); |
||
384 | $newtitle = $this->newTitle->getDBkey(); |
||
385 | $oldsnamespace = MWNamespace::getSubject( $this->oldTitle->getNamespace() ); |
||
386 | $newsnamespace = MWNamespace::getSubject( $this->newTitle->getNamespace() ); |
||
387 | if ( $oldsnamespace != $newsnamespace || $oldtitle != $newtitle ) { |
||
388 | $store = MediaWikiServices::getInstance()->getWatchedItemStore(); |
||
389 | $store->duplicateAllAssociatedEntries( $this->oldTitle, $this->newTitle ); |
||
390 | } |
||
391 | |||
392 | Hooks::run( |
||
393 | 'TitleMoveCompleting', |
||
394 | [ $this->oldTitle, $this->newTitle, |
||
395 | $user, $pageid, $redirid, $reason, $nullRevision ] |
||
396 | ); |
||
397 | |||
398 | $dbw->endAtomic( __METHOD__ ); |
||
399 | |||
400 | $params = [ |
||
401 | &$this->oldTitle, |
||
402 | &$this->newTitle, |
||
403 | &$user, |
||
404 | $pageid, |
||
405 | $redirid, |
||
406 | $reason, |
||
407 | $nullRevision |
||
408 | ]; |
||
409 | // Keep each single hook handler atomic |
||
410 | DeferredUpdates::addUpdate( |
||
411 | new AtomicSectionUpdate( |
||
412 | $dbw, |
||
0 ignored issues
–
show
It seems like
$dbw defined by wfGetDB(DB_MASTER) on line 245 can be null ; however, AtomicSectionUpdate::__construct() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
413 | __METHOD__, |
||
414 | function () use ( $params ) { |
||
415 | Hooks::run( 'TitleMoveComplete', $params ); |
||
416 | } |
||
417 | ) |
||
418 | ); |
||
419 | |||
420 | return Status::newGood(); |
||
421 | } |
||
422 | |||
423 | /** |
||
424 | * Move page to a title which is either a redirect to the |
||
425 | * source page or nonexistent |
||
426 | * |
||
427 | * @fixme This was basically directly moved from Title, it should be split into smaller functions |
||
428 | * @param User $user the User doing the move |
||
429 | * @param Title $nt The page to move to, which should be a redirect or non-existent |
||
430 | * @param string $reason The reason for the move |
||
431 | * @param bool $createRedirect Whether to leave a redirect at the old title. Does not check |
||
432 | * if the user has the suppressredirect right |
||
433 | * @return Revision the revision created by the move |
||
434 | * @throws MWException |
||
435 | */ |
||
436 | private function moveToInternal( User $user, &$nt, $reason = '', $createRedirect = true ) { |
||
437 | global $wgContLang; |
||
438 | |||
439 | if ( $nt->exists() ) { |
||
440 | $moveOverRedirect = true; |
||
441 | $logType = 'move_redir'; |
||
442 | } else { |
||
443 | $moveOverRedirect = false; |
||
444 | $logType = 'move'; |
||
445 | } |
||
446 | |||
447 | if ( $moveOverRedirect ) { |
||
448 | $overwriteMessage = wfMessage( |
||
449 | 'delete_and_move_reason', |
||
450 | $this->oldTitle->getPrefixedText() |
||
451 | )->text(); |
||
452 | $newpage = WikiPage::factory( $nt ); |
||
453 | $errs = []; |
||
454 | $status = $newpage->doDeleteArticleReal( |
||
455 | $overwriteMessage, |
||
456 | /* $suppress */ false, |
||
457 | $nt->getArticleID(), |
||
458 | /* $commit */ false, |
||
459 | $errs, |
||
460 | $user |
||
461 | ); |
||
462 | |||
463 | if ( !$status->isGood() ) { |
||
464 | throw new MWException( 'Failed to delete page-move revision: ' . $status ); |
||
465 | } |
||
466 | |||
467 | $nt->resetArticleID( false ); |
||
468 | } |
||
469 | |||
470 | if ( $createRedirect ) { |
||
471 | if ( $this->oldTitle->getNamespace() == NS_CATEGORY |
||
472 | && !wfMessage( 'category-move-redirect-override' )->inContentLanguage()->isDisabled() |
||
473 | ) { |
||
474 | $redirectContent = new WikitextContent( |
||
475 | wfMessage( 'category-move-redirect-override' ) |
||
476 | ->params( $nt->getPrefixedText() )->inContentLanguage()->plain() ); |
||
477 | } else { |
||
478 | $contentHandler = ContentHandler::getForTitle( $this->oldTitle ); |
||
479 | $redirectContent = $contentHandler->makeRedirectContent( $nt, |
||
480 | wfMessage( 'move-redirect-text' )->inContentLanguage()->plain() ); |
||
481 | } |
||
482 | |||
483 | // NOTE: If this page's content model does not support redirects, $redirectContent will be null. |
||
484 | } else { |
||
485 | $redirectContent = null; |
||
486 | } |
||
487 | |||
488 | // Figure out whether the content model is no longer the default |
||
489 | $oldDefault = ContentHandler::getDefaultModelFor( $this->oldTitle ); |
||
490 | $contentModel = $this->oldTitle->getContentModel(); |
||
491 | $newDefault = ContentHandler::getDefaultModelFor( $nt ); |
||
492 | $defaultContentModelChanging = ( $oldDefault !== $newDefault |
||
493 | && $oldDefault === $contentModel ); |
||
494 | |||
495 | // bug 57084: log_page should be the ID of the *moved* page |
||
496 | $oldid = $this->oldTitle->getArticleID(); |
||
497 | $logTitle = clone $this->oldTitle; |
||
498 | |||
499 | $logEntry = new ManualLogEntry( 'move', $logType ); |
||
500 | $logEntry->setPerformer( $user ); |
||
501 | $logEntry->setTarget( $logTitle ); |
||
502 | $logEntry->setComment( $reason ); |
||
503 | $logEntry->setParameters( [ |
||
504 | '4::target' => $nt->getPrefixedText(), |
||
505 | '5::noredir' => $redirectContent ? '0': '1', |
||
506 | ] ); |
||
507 | |||
508 | $formatter = LogFormatter::newFromEntry( $logEntry ); |
||
509 | $formatter->setContext( RequestContext::newExtraneousContext( $this->oldTitle ) ); |
||
510 | $comment = $formatter->getPlainActionText(); |
||
511 | if ( $reason ) { |
||
512 | $comment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $reason; |
||
513 | } |
||
514 | # Truncate for whole multibyte characters. |
||
515 | $comment = $wgContLang->truncate( $comment, 255 ); |
||
516 | |||
517 | $dbw = wfGetDB( DB_MASTER ); |
||
518 | |||
519 | $oldpage = WikiPage::factory( $this->oldTitle ); |
||
520 | $oldcountable = $oldpage->isCountable(); |
||
521 | |||
522 | $newpage = WikiPage::factory( $nt ); |
||
523 | |||
524 | # Save a null revision in the page's history notifying of the move |
||
525 | $nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true, $user ); |
||
0 ignored issues
–
show
It seems like
$dbw defined by wfGetDB(DB_MASTER) on line 517 can be null ; however, Revision::newNullRevision() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
526 | if ( !is_object( $nullRevision ) ) { |
||
527 | throw new MWException( 'No valid null revision produced in ' . __METHOD__ ); |
||
528 | } |
||
529 | |||
530 | $nullRevision->insertOn( $dbw ); |
||
0 ignored issues
–
show
It seems like
$dbw defined by wfGetDB(DB_MASTER) on line 517 can be null ; however, Revision::insertOn() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
531 | |||
532 | # Change the name of the target page: |
||
533 | $dbw->update( 'page', |
||
534 | /* SET */ [ |
||
535 | 'page_namespace' => $nt->getNamespace(), |
||
536 | 'page_title' => $nt->getDBkey(), |
||
537 | ], |
||
538 | /* WHERE */ [ 'page_id' => $oldid ], |
||
539 | __METHOD__ |
||
540 | ); |
||
541 | |||
542 | if ( !$redirectContent ) { |
||
543 | // Clean up the old title *before* reset article id - bug 45348 |
||
544 | WikiPage::onArticleDelete( $this->oldTitle ); |
||
545 | } |
||
546 | |||
547 | $this->oldTitle->resetArticleID( 0 ); // 0 == non existing |
||
548 | $nt->resetArticleID( $oldid ); |
||
549 | $newpage->loadPageData( WikiPage::READ_LOCKING ); // bug 46397 |
||
550 | |||
551 | $newpage->updateRevisionOn( $dbw, $nullRevision ); |
||
0 ignored issues
–
show
It seems like
$dbw defined by wfGetDB(DB_MASTER) on line 517 can be null ; however, WikiPage::updateRevisionOn() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
552 | |||
553 | Hooks::run( 'NewRevisionFromEditComplete', |
||
554 | [ $newpage, $nullRevision, $nullRevision->getParentId(), $user ] ); |
||
555 | |||
556 | $newpage->doEditUpdates( $nullRevision, $user, |
||
557 | [ 'changed' => false, 'moved' => true, 'oldcountable' => $oldcountable ] ); |
||
558 | |||
559 | // If the default content model changes, we need to populate rev_content_model |
||
560 | if ( $defaultContentModelChanging ) { |
||
561 | $dbw->update( |
||
562 | 'revision', |
||
563 | [ 'rev_content_model' => $contentModel ], |
||
564 | [ 'rev_page' => $nt->getArticleID(), 'rev_content_model IS NULL' ], |
||
565 | __METHOD__ |
||
566 | ); |
||
567 | } |
||
568 | |||
569 | WikiPage::onArticleCreate( $nt ); |
||
570 | |||
571 | # Recreate the redirect, this time in the other direction. |
||
572 | if ( $redirectContent ) { |
||
573 | $redirectArticle = WikiPage::factory( $this->oldTitle ); |
||
574 | $redirectArticle->loadFromRow( false, WikiPage::READ_LOCKING ); // bug 46397 |
||
575 | $newid = $redirectArticle->insertOn( $dbw ); |
||
0 ignored issues
–
show
It seems like
$dbw defined by wfGetDB(DB_MASTER) on line 517 can be null ; however, WikiPage::insertOn() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
576 | if ( $newid ) { // sanity |
||
577 | $this->oldTitle->resetArticleID( $newid ); |
||
578 | $redirectRevision = new Revision( [ |
||
579 | 'title' => $this->oldTitle, // for determining the default content model |
||
580 | 'page' => $newid, |
||
581 | 'user_text' => $user->getName(), |
||
582 | 'user' => $user->getId(), |
||
583 | 'comment' => $comment, |
||
584 | 'content' => $redirectContent ] ); |
||
585 | $redirectRevision->insertOn( $dbw ); |
||
0 ignored issues
–
show
It seems like
$dbw defined by wfGetDB(DB_MASTER) on line 517 can be null ; however, Revision::insertOn() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
586 | $redirectArticle->updateRevisionOn( $dbw, $redirectRevision, 0 ); |
||
0 ignored issues
–
show
It seems like
$dbw defined by wfGetDB(DB_MASTER) on line 517 can be null ; however, WikiPage::updateRevisionOn() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
587 | |||
588 | Hooks::run( 'NewRevisionFromEditComplete', |
||
589 | [ $redirectArticle, $redirectRevision, false, $user ] ); |
||
590 | |||
591 | $redirectArticle->doEditUpdates( $redirectRevision, $user, [ 'created' => true ] ); |
||
592 | } |
||
593 | } |
||
594 | |||
595 | # Log the move |
||
596 | $logid = $logEntry->insert(); |
||
597 | $logEntry->publish( $logid ); |
||
598 | |||
599 | return $nullRevision; |
||
600 | } |
||
601 | } |
||
602 |
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: