Completed
Branch master (939199)
by
unknown
39:35
created

includes/api/ApiMove.php (1 issue)

Upgrade to new PHP Analysis Engine

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
 *
5
 * Created on Oct 31, 2007
6
 *
7
 * Copyright © 2007 Roan Kattouw "<Firstname>.<Lastname>@gmail.com"
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 2 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License along
20
 * with this program; if not, write to the Free Software Foundation, Inc.,
21
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
 * http://www.gnu.org/copyleft/gpl.html
23
 *
24
 * @file
25
 */
26
27
/**
28
 * API Module to move pages
29
 * @ingroup API
30
 */
31
class ApiMove extends ApiBase {
32
33
	public function execute() {
34
		$this->useTransactionalTimeLimit();
35
36
		$user = $this->getUser();
37
		$params = $this->extractRequestParams();
38
39
		$this->requireOnlyOneParameter( $params, 'from', 'fromid' );
40
41 View Code Duplication
		if ( isset( $params['from'] ) ) {
42
			$fromTitle = Title::newFromText( $params['from'] );
43
			if ( !$fromTitle || $fromTitle->isExternal() ) {
44
				$this->dieUsageMsg( [ 'invalidtitle', $params['from'] ] );
45
			}
46
		} elseif ( isset( $params['fromid'] ) ) {
47
			$fromTitle = Title::newFromID( $params['fromid'] );
48
			if ( !$fromTitle ) {
49
				$this->dieUsageMsg( [ 'nosuchpageid', $params['fromid'] ] );
50
			}
51
		}
52
53
		if ( !$fromTitle->exists() ) {
0 ignored issues
show
The variable $fromTitle does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
54
			$this->dieUsageMsg( 'notanarticle' );
55
		}
56
		$fromTalk = $fromTitle->getTalkPage();
57
58
		$toTitle = Title::newFromText( $params['to'] );
59
		if ( !$toTitle || $toTitle->isExternal() ) {
60
			$this->dieUsageMsg( [ 'invalidtitle', $params['to'] ] );
61
		}
62
		$toTalk = $toTitle->getTalkPage();
63
64
		if ( $toTitle->getNamespace() == NS_FILE
65
			&& !RepoGroup::singleton()->getLocalRepo()->findFile( $toTitle )
66
			&& wfFindFile( $toTitle )
67
		) {
68
			if ( !$params['ignorewarnings'] && $user->isAllowed( 'reupload-shared' ) ) {
69
				$this->dieUsageMsg( 'sharedfile-exists' );
70
			} elseif ( !$user->isAllowed( 'reupload-shared' ) ) {
71
				$this->dieUsageMsg( 'cantoverwrite-sharedfile' );
72
			}
73
		}
74
75
		// Rate limit
76
		if ( $user->pingLimiter( 'move' ) ) {
77
			$this->dieUsageMsg( 'actionthrottledtext' );
78
		}
79
80
		// Move the page
81
		$toTitleExists = $toTitle->exists();
82
		$status = $this->movePage( $fromTitle, $toTitle, $params['reason'], !$params['noredirect'] );
83
		if ( !$status->isOK() ) {
84
			$this->dieStatus( $status );
85
		}
86
87
		$r = [
88
			'from' => $fromTitle->getPrefixedText(),
89
			'to' => $toTitle->getPrefixedText(),
90
			'reason' => $params['reason']
91
		];
92
93
		// NOTE: we assume that if the old title exists, it's because it was re-created as
94
		// a redirect to the new title. This is not safe, but what we did before was
95
		// even worse: we just determined whether a redirect should have been created,
96
		// and reported that it was created if it should have, without any checks.
97
		// Also note that isRedirect() is unreliable because of bug 37209.
98
		$r['redirectcreated'] = $fromTitle->exists();
99
100
		$r['moveoverredirect'] = $toTitleExists;
101
102
		// Move the talk page
103
		if ( $params['movetalk'] && $fromTalk->exists() && !$fromTitle->isTalkPage() ) {
104
			$toTalkExists = $toTalk->exists();
105
			$status = $this->movePage( $fromTalk, $toTalk, $params['reason'], !$params['noredirect'] );
106
			if ( $status->isOK() ) {
107
				$r['talkfrom'] = $fromTalk->getPrefixedText();
108
				$r['talkto'] = $toTalk->getPrefixedText();
109
				$r['talkmoveoverredirect'] = $toTalkExists;
110
			} else {
111
				// We're not gonna dieUsage() on failure, since we already changed something
112
				$error = $this->getErrorFromStatus( $status );
113
				$r['talkmove-error-code'] = $error[0];
114
				$r['talkmove-error-info'] = $error[1];
115
			}
116
		}
117
118
		$result = $this->getResult();
119
120
		// Move subpages
121
		if ( $params['movesubpages'] ) {
122
			$r['subpages'] = $this->moveSubpages( $fromTitle, $toTitle,
123
				$params['reason'], $params['noredirect'] );
124
			ApiResult::setIndexedTagName( $r['subpages'], 'subpage' );
125
126
			if ( $params['movetalk'] ) {
127
				$r['subpages-talk'] = $this->moveSubpages( $fromTalk, $toTalk,
128
					$params['reason'], $params['noredirect'] );
129
				ApiResult::setIndexedTagName( $r['subpages-talk'], 'subpage' );
130
			}
131
		}
132
133
		$watch = 'preferences';
134 View Code Duplication
		if ( isset( $params['watchlist'] ) ) {
135
			$watch = $params['watchlist'];
136
		} elseif ( $params['watch'] ) {
137
			$watch = 'watch';
138
		} elseif ( $params['unwatch'] ) {
139
			$watch = 'unwatch';
140
		}
141
142
		// Watch pages
143
		$this->setWatch( $watch, $fromTitle, 'watchmoves' );
144
		$this->setWatch( $watch, $toTitle, 'watchmoves' );
145
146
		$result->addValue( null, $this->getModuleName(), $r );
147
	}
148
149
	/**
150
	 * @param Title $from
151
	 * @param Title $to
152
	 * @param string $reason
153
	 * @param bool $createRedirect
154
	 * @return Status
155
	 */
156
	protected function movePage( Title $from, Title $to, $reason, $createRedirect ) {
157
		$mp = new MovePage( $from, $to );
158
		$valid = $mp->isValidMove();
159
		if ( !$valid->isOK() ) {
160
			return $valid;
161
		}
162
163
		$permStatus = $mp->checkPermissions( $this->getUser(), $reason );
164
		if ( !$permStatus->isOK() ) {
165
			return $permStatus;
166
		}
167
168
		// Check suppressredirect permission
169
		if ( !$this->getUser()->isAllowed( 'suppressredirect' ) ) {
170
			$createRedirect = true;
171
		}
172
173
		return $mp->move( $this->getUser(), $reason, $createRedirect );
174
	}
175
176
	/**
177
	 * @param Title $fromTitle
178
	 * @param Title $toTitle
179
	 * @param string $reason
180
	 * @param bool $noredirect
181
	 * @return array
182
	 */
183
	public function moveSubpages( $fromTitle, $toTitle, $reason, $noredirect ) {
184
		$retval = [];
185
		$success = $fromTitle->moveSubpages( $toTitle, true, $reason, !$noredirect );
186
		if ( isset( $success[0] ) ) {
187
			return [ 'error' => $this->parseMsg( $success ) ];
188
		}
189
190
		// At least some pages could be moved
191
		// Report each of them separately
192
		foreach ( $success as $oldTitle => $newTitle ) {
193
			$r = [ 'from' => $oldTitle ];
194
			if ( is_array( $newTitle ) ) {
195
				$r['error'] = $this->parseMsg( reset( $newTitle ) );
196
			} else {
197
				// Success
198
				$r['to'] = $newTitle;
199
			}
200
			$retval[] = $r;
201
		}
202
203
		return $retval;
204
	}
205
206
	public function mustBePosted() {
207
		return true;
208
	}
209
210
	public function isWriteMode() {
211
		return true;
212
	}
213
214
	public function getAllowedParams() {
215
		return [
216
			'from' => null,
217
			'fromid' => [
218
				ApiBase::PARAM_TYPE => 'integer'
219
			],
220
			'to' => [
221
				ApiBase::PARAM_TYPE => 'string',
222
				ApiBase::PARAM_REQUIRED => true
223
			],
224
			'reason' => '',
225
			'movetalk' => false,
226
			'movesubpages' => false,
227
			'noredirect' => false,
228
			'watch' => [
229
				ApiBase::PARAM_DFLT => false,
230
				ApiBase::PARAM_DEPRECATED => true,
231
			],
232
			'unwatch' => [
233
				ApiBase::PARAM_DFLT => false,
234
				ApiBase::PARAM_DEPRECATED => true,
235
			],
236
			'watchlist' => [
237
				ApiBase::PARAM_DFLT => 'preferences',
238
				ApiBase::PARAM_TYPE => [
239
					'watch',
240
					'unwatch',
241
					'preferences',
242
					'nochange'
243
				],
244
			],
245
			'ignorewarnings' => false
246
		];
247
	}
248
249
	public function needsToken() {
250
		return 'csrf';
251
	}
252
253
	protected function getExamplesMessages() {
254
		return [
255
			'action=move&from=Badtitle&to=Goodtitle&token=123ABC&' .
256
				'reason=Misspelled%20title&movetalk=&noredirect='
257
				=> 'apihelp-move-example-move',
258
		];
259
	}
260
261
	public function getHelpUrls() {
262
		return 'https://www.mediawiki.org/wiki/API:Move';
263
	}
264
}
265