Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 360 |
|
0.00% |
0 / 12 |
CRAP | |
0.00% |
0 / 1 |
WebInstallerOptions | |
0.00% |
0 / 360 |
|
0.00% |
0 / 12 |
3660 | |
0.00% |
0 / 1 |
execute | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
addPersonalizationOptions | |
0.00% |
0 / 44 |
|
0.00% |
0 / 1 |
2 | |||
addModeOptions | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
2 | |||
addEmailOptions | |
0.00% |
0 / 38 |
|
0.00% |
0 / 1 |
6 | |||
addSkinOptions | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
20 | |||
addExtensionOptions | |
0.00% |
0 / 60 |
|
0.00% |
0 / 1 |
240 | |||
addFileOptions | |
0.00% |
0 / 32 |
|
0.00% |
0 / 1 |
6 | |||
addAdvancedOptions | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
20 | |||
makeScreenshotsLink | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
12 | |||
makeMoreInfoLink | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
6 | |||
submitSkins | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
submit | |
0.00% |
0 / 60 |
|
0.00% |
0 / 1 |
420 |
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 | * @ingroup Installer |
21 | */ |
22 | |
23 | namespace MediaWiki\Installer; |
24 | |
25 | use MediaWiki\Html\Html; |
26 | use MediaWiki\Specials\SpecialVersion; |
27 | use Wikimedia\IPUtils; |
28 | |
29 | class WebInstallerOptions extends WebInstallerPage { |
30 | |
31 | /** |
32 | * @return string|null |
33 | */ |
34 | public function execute() { |
35 | if ( $this->getVar( '_SkipOptional' ) == 'skip' ) { |
36 | $this->submitSkins(); |
37 | return 'skip'; |
38 | } |
39 | if ( $this->parent->request->wasPosted() && $this->submit() ) { |
40 | return 'continue'; |
41 | } |
42 | |
43 | $this->startForm(); |
44 | $this->addModeOptions(); |
45 | $this->addEmailOptions(); |
46 | $this->addSkinOptions(); |
47 | $this->addExtensionOptions(); |
48 | $this->addFileOptions(); |
49 | $this->addPersonalizationOptions(); |
50 | $this->addAdvancedOptions(); |
51 | $this->endForm(); |
52 | |
53 | return null; |
54 | } |
55 | |
56 | private function addPersonalizationOptions() { |
57 | $parent = $this->parent; |
58 | $this->addHTML( |
59 | $this->getFieldsetStart( 'config-personalization-settings' ) . |
60 | Html::rawElement( 'div', [ |
61 | 'class' => 'config-drag-drop' |
62 | ], wfMessage( 'config-logo-summary' )->parse() ) . |
63 | Html::openElement( 'div', [ |
64 | 'class' => 'config-personalization-options' |
65 | ] ) . |
66 | Html::hidden( 'config_LogoSiteName', $this->getVar( 'wgSitename' ) ) . |
67 | $parent->getTextBox( [ |
68 | 'var' => '_LogoIcon', |
69 | // Single quotes are intentional, LocalSettingsGenerator must output this unescaped. |
70 | 'value' => '$wgResourceBasePath/resources/assets/change-your-logo.svg', |
71 | 'label' => 'config-logo-icon', |
72 | 'attribs' => [ 'dir' => 'ltr' ], |
73 | 'help' => $parent->getHelpBox( 'config-logo-icon-help' ) |
74 | ] ) . |
75 | $parent->getTextBox( [ |
76 | 'var' => '_LogoWordmark', |
77 | 'label' => 'config-logo-wordmark', |
78 | 'attribs' => [ 'dir' => 'ltr' ], |
79 | 'help' => $parent->getHelpBox( 'config-logo-wordmark-help' ) |
80 | ] ) . |
81 | $parent->getTextBox( [ |
82 | 'var' => '_LogoTagline', |
83 | 'label' => 'config-logo-tagline', |
84 | 'attribs' => [ 'dir' => 'ltr' ], |
85 | 'help' => $parent->getHelpBox( 'config-logo-tagline-help' ) |
86 | ] ) . |
87 | $parent->getTextBox( [ |
88 | 'var' => '_Logo1x', |
89 | 'label' => 'config-logo-sidebar', |
90 | 'attribs' => [ 'dir' => 'ltr' ], |
91 | 'help' => $parent->getHelpBox( 'config-logo-sidebar-help' ) |
92 | ] ) . |
93 | Html::openElement( 'div', [ |
94 | 'class' => 'logo-preview-area', |
95 | 'data-main-page' => wfMessage( 'config-logo-preview-main' ), |
96 | 'data-filedrop' => wfMessage( 'config-logo-filedrop' ) |
97 | ] ) . |
98 | Html::closeElement( 'div' ) . |
99 | Html::closeElement( 'div' ) . |
100 | $this->getFieldsetEnd() |
101 | ); |
102 | } |
103 | |
104 | /** |
105 | * Wiki mode - user rights and copyright model. |
106 | * @return void |
107 | */ |
108 | private function addModeOptions(): void { |
109 | $this->addHTML( |
110 | # User Rights |
111 | // getRadioSet() builds a set of labeled radio buttons. |
112 | // For grep: The following messages are used as the item labels: |
113 | // config-profile-wiki, config-profile-no-anon, config-profile-fishbowl, config-profile-private |
114 | $this->parent->getRadioSet( [ |
115 | 'var' => '_RightsProfile', |
116 | 'label' => 'config-profile', |
117 | 'itemLabelPrefix' => 'config-profile-', |
118 | 'values' => array_keys( $this->parent->rightsProfiles ), |
119 | ] ) . |
120 | $this->parent->getInfoBox( wfMessage( 'config-profile-help' )->plain() ) . |
121 | |
122 | # Licensing |
123 | // getRadioSet() builds a set of labeled radio buttons. |
124 | // For grep: The following messages are used as the item labels: |
125 | // config-license-cc-by, config-license-cc-by-sa, config-license-cc-by-nc-sa, |
126 | // config-license-cc-0, config-license-pd, config-license-gfdl, |
127 | // config-license-none |
128 | $this->parent->getRadioSet( [ |
129 | 'var' => '_LicenseCode', |
130 | 'label' => 'config-license', |
131 | 'itemLabelPrefix' => 'config-license-', |
132 | 'values' => array_keys( $this->parent->licenses ), |
133 | 'commonAttribs' => [ 'class' => 'licenseRadio' ], |
134 | ] ) . |
135 | $this->parent->getHelpBox( 'config-license-help' ) |
136 | ); |
137 | } |
138 | |
139 | /** |
140 | * User email options. |
141 | * @return void |
142 | */ |
143 | private function addEmailOptions(): void { |
144 | $emailwrapperStyle = $this->getVar( 'wgEnableEmail' ) ? '' : 'display: none'; |
145 | $this->addHTML( |
146 | $this->getFieldsetStart( 'config-email-settings' ) . |
147 | $this->parent->getCheckBox( [ |
148 | 'var' => 'wgEnableEmail', |
149 | 'label' => 'config-enable-email', |
150 | 'attribs' => [ 'class' => 'showHideRadio', 'rel' => 'emailwrapper' ], |
151 | ] ) . |
152 | $this->parent->getHelpBox( 'config-enable-email-help' ) . |
153 | "<div id=\"emailwrapper\" style=\"$emailwrapperStyle\">" . |
154 | $this->parent->getTextBox( [ |
155 | 'var' => 'wgPasswordSender', |
156 | 'label' => 'config-email-sender' |
157 | ] ) . |
158 | $this->parent->getHelpBox( 'config-email-sender-help' ) . |
159 | $this->parent->getCheckBox( [ |
160 | 'var' => 'wgEnableUserEmail', |
161 | 'label' => 'config-email-user', |
162 | ] ) . |
163 | $this->parent->getHelpBox( 'config-email-user-help' ) . |
164 | $this->parent->getCheckBox( [ |
165 | 'var' => 'wgEnotifUserTalk', |
166 | 'label' => 'config-email-usertalk', |
167 | ] ) . |
168 | $this->parent->getHelpBox( 'config-email-usertalk-help' ) . |
169 | $this->parent->getCheckBox( [ |
170 | 'var' => 'wgEnotifWatchlist', |
171 | 'label' => 'config-email-watchlist', |
172 | ] ) . |
173 | $this->parent->getHelpBox( 'config-email-watchlist-help' ) . |
174 | $this->parent->getCheckBox( [ |
175 | 'var' => 'wgEmailAuthentication', |
176 | 'label' => 'config-email-auth', |
177 | ] ) . |
178 | $this->parent->getHelpBox( 'config-email-auth-help' ) . |
179 | "</div>" . |
180 | $this->getFieldsetEnd() |
181 | ); |
182 | } |
183 | |
184 | /** |
185 | * Opt-in for bundled skins. |
186 | * @return void |
187 | */ |
188 | private function addSkinOptions(): void { |
189 | $skins = $this->parent->findExtensions( 'skins' )->value; |
190 | '@phan-var array[] $skins'; |
191 | $skinHtml = $this->getFieldsetStart( 'config-skins' ); |
192 | |
193 | $skinNames = array_map( 'strtolower', array_keys( $skins ) ); |
194 | $chosenSkinName = $this->getVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) ); |
195 | |
196 | if ( $skins ) { |
197 | $radioButtons = $this->parent->getRadioElements( [ |
198 | 'var' => 'wgDefaultSkin', |
199 | 'itemLabels' => array_fill_keys( $skinNames, 'config-skins-use-as-default' ), |
200 | 'values' => $skinNames, |
201 | 'value' => $chosenSkinName, |
202 | ] ); |
203 | |
204 | foreach ( $skins as $skin => $info ) { |
205 | if ( isset( $info['screenshots'] ) ) { |
206 | $screenshotText = $this->makeScreenshotsLink( $skin, $info['screenshots'] ); |
207 | } else { |
208 | $screenshotText = htmlspecialchars( $skin ); |
209 | } |
210 | $skinHtml .= |
211 | '<div class="config-skins-item">' . |
212 | $this->parent->getCheckBox( [ |
213 | 'var' => "skin-$skin", |
214 | 'rawtext' => $screenshotText . $this->makeMoreInfoLink( $info ), |
215 | 'value' => $this->getVar( "skin-$skin", true ), // all found skins enabled by default |
216 | ] ) . |
217 | '<div class="config-skins-use-as-default">' . $radioButtons[strtolower( $skin )] . '</div>' . |
218 | '</div>'; |
219 | } |
220 | } else { |
221 | $skinHtml .= |
222 | Html::warningBox( wfMessage( 'config-skins-missing' )->plain(), 'config-warning-box' ) . |
223 | Html::hidden( 'config_wgDefaultSkin', $chosenSkinName ); |
224 | } |
225 | |
226 | $skinHtml .= $this->parent->getHelpBox( 'config-skins-help' ) . |
227 | $this->getFieldsetEnd(); |
228 | $this->addHTML( $skinHtml ); |
229 | } |
230 | |
231 | /** |
232 | * Opt-in for bundled extensions. |
233 | * @return void |
234 | */ |
235 | private function addExtensionOptions(): void { |
236 | global $wgLang; |
237 | |
238 | $extensions = $this->parent->findExtensions()->value; |
239 | '@phan-var array[] $extensions'; |
240 | $dependencyMap = []; |
241 | |
242 | if ( $extensions ) { |
243 | $extHtml = $this->getFieldsetStart( 'config-extensions' ); |
244 | |
245 | $extByType = []; |
246 | $types = SpecialVersion::getExtensionTypes(); |
247 | // Sort by type first |
248 | foreach ( $extensions as $ext => $info ) { |
249 | if ( !isset( $info['type'] ) || !isset( $types[$info['type']] ) ) { |
250 | // We let extensions normally define custom types, but |
251 | // since we aren't loading extensions, we'll have to |
252 | // categorize them under other |
253 | $info['type'] = 'other'; |
254 | } |
255 | $extByType[$info['type']][$ext] = $info; |
256 | } |
257 | |
258 | foreach ( $types as $type => $message ) { |
259 | if ( !isset( $extByType[$type] ) ) { |
260 | continue; |
261 | } |
262 | $extHtml .= Html::element( 'h2', [], $message ); |
263 | foreach ( $extByType[$type] as $ext => $info ) { |
264 | $attribs = [ |
265 | 'data-name' => $ext, |
266 | 'class' => 'config-ext-input cdx-checkbox__input' |
267 | ]; |
268 | $labelAttribs = []; |
269 | if ( isset( $info['requires']['extensions'] ) ) { |
270 | $dependencyMap[$ext]['extensions'] = $info['requires']['extensions']; |
271 | $labelAttribs['class'] = 'mw-ext-with-dependencies'; |
272 | } |
273 | if ( isset( $info['requires']['skins'] ) ) { |
274 | $dependencyMap[$ext]['skins'] = $info['requires']['skins']; |
275 | $labelAttribs['class'] = 'mw-ext-with-dependencies'; |
276 | } |
277 | if ( isset( $dependencyMap[$ext] ) ) { |
278 | $links = []; |
279 | // For each dependency, link to the checkbox for each |
280 | // extension/skin that is required |
281 | if ( isset( $dependencyMap[$ext]['extensions'] ) ) { |
282 | foreach ( $dependencyMap[$ext]['extensions'] as $name ) { |
283 | $links[] = Html::element( |
284 | 'a', |
285 | [ 'href' => "#config_ext-$name" ], |
286 | $name |
287 | ); |
288 | } |
289 | } |
290 | if ( isset( $dependencyMap[$ext]['skins'] ) ) { |
291 | // @phan-suppress-next-line PhanTypeMismatchForeach Phan internal bug |
292 | foreach ( $dependencyMap[$ext]['skins'] as $name ) { |
293 | $links[] = Html::element( |
294 | 'a', |
295 | [ 'href' => "#config_skin-$name" ], |
296 | $name |
297 | ); |
298 | } |
299 | } |
300 | |
301 | $text = wfMessage( 'config-extensions-requires' ) |
302 | ->rawParams( $ext, $wgLang->commaList( $links ) ) |
303 | ->escaped(); |
304 | } else { |
305 | $text = $ext; |
306 | } |
307 | $extHtml .= $this->parent->getCheckBox( [ |
308 | 'var' => "ext-$ext", |
309 | 'rawtext' => $text . $this->makeMoreInfoLink( $info ), |
310 | 'attribs' => $attribs, |
311 | 'labelAttribs' => $labelAttribs, |
312 | ] ); |
313 | } |
314 | } |
315 | |
316 | $extHtml .= $this->parent->getHelpBox( 'config-extensions-help' ) . |
317 | $this->getFieldsetEnd(); |
318 | $this->addHTML( $extHtml ); |
319 | // Push the dependency map to the client side |
320 | $this->addHTML( Html::inlineScript( |
321 | 'var extDependencyMap = ' . Html::encodeJsVar( $dependencyMap ) |
322 | ) ); |
323 | } |
324 | } |
325 | |
326 | /** |
327 | * Image and file upload options. |
328 | * @return void |
329 | */ |
330 | private function addFileOptions(): void { |
331 | // Having / in paths in Windows looks funny :) |
332 | $this->setVar( 'wgDeletedDirectory', |
333 | str_replace( |
334 | '/', DIRECTORY_SEPARATOR, |
335 | $this->getVar( 'wgDeletedDirectory' ) |
336 | ) |
337 | ); |
338 | |
339 | $uploadwrapperStyle = $this->getVar( 'wgEnableUploads' ) ? '' : 'display: none'; |
340 | $this->addHTML( |
341 | # Uploading |
342 | $this->getFieldsetStart( 'config-upload-settings' ) . |
343 | $this->parent->getCheckBox( [ |
344 | 'var' => 'wgEnableUploads', |
345 | 'label' => 'config-upload-enable', |
346 | 'attribs' => [ 'class' => 'showHideRadio', 'rel' => 'uploadwrapper' ], |
347 | 'help' => $this->parent->getHelpBox( 'config-upload-help' ) |
348 | ] ) . |
349 | '<div id="uploadwrapper" style="' . $uploadwrapperStyle . '">' . |
350 | $this->parent->getTextBox( [ |
351 | 'var' => 'wgDeletedDirectory', |
352 | 'label' => 'config-upload-deleted', |
353 | 'attribs' => [ 'dir' => 'ltr' ], |
354 | 'help' => $this->parent->getHelpBox( 'config-upload-deleted-help' ) |
355 | ] ) . |
356 | '</div>' |
357 | ); |
358 | $this->addHTML( |
359 | $this->parent->getCheckBox( [ |
360 | 'var' => 'wgUseInstantCommons', |
361 | 'label' => 'config-instantcommons', |
362 | 'help' => $this->parent->getHelpBox( 'config-instantcommons-help' ) |
363 | ] ) . |
364 | $this->getFieldsetEnd() |
365 | ); |
366 | } |
367 | |
368 | /** |
369 | * System administration related options. |
370 | * @return void |
371 | */ |
372 | private function addAdvancedOptions(): void { |
373 | $caches = [ 'none' ]; |
374 | $cachevalDefault = 'none'; |
375 | |
376 | if ( count( $this->getVar( '_Caches' ) ) ) { |
377 | // A CACHE_ACCEL implementation is available |
378 | $caches[] = 'accel'; |
379 | $cachevalDefault = 'accel'; |
380 | } |
381 | $caches[] = 'memcached'; |
382 | |
383 | // We'll hide/show this on demand when the value changes, see config.js. |
384 | $cacheval = $this->getVar( '_MainCacheType' ); |
385 | if ( !$cacheval ) { |
386 | // We need to set a default here; but don't hardcode it |
387 | // or we lose it every time we reload the page for validation |
388 | // or going back! |
389 | $cacheval = $cachevalDefault; |
390 | } |
391 | $hidden = ( $cacheval == 'memcached' ) ? '' : 'display: none'; |
392 | $this->addHTML( |
393 | # Advanced settings |
394 | $this->getFieldsetStart( 'config-advanced-settings' ) . |
395 | # Object cache settings |
396 | // getRadioSet() builds a set of labeled radio buttons. |
397 | // For grep: The following messages are used as the item labels: |
398 | // config-cache-none, config-cache-accel, config-cache-memcached |
399 | $this->parent->getRadioSet( [ |
400 | 'var' => '_MainCacheType', |
401 | 'label' => 'config-cache-options', |
402 | 'itemLabelPrefix' => 'config-cache-', |
403 | 'values' => $caches, |
404 | 'value' => $cacheval, |
405 | ] ) . |
406 | $this->parent->getHelpBox( 'config-cache-help' ) . |
407 | "<div id=\"config-memcachewrapper\" style=\"$hidden\">" . |
408 | $this->parent->getTextArea( [ |
409 | 'var' => '_MemCachedServers', |
410 | 'label' => 'config-memcached-servers', |
411 | 'help' => $this->parent->getHelpBox( 'config-memcached-help' ) |
412 | ] ) . |
413 | '</div>' . |
414 | $this->getFieldsetEnd() |
415 | ); |
416 | } |
417 | |
418 | /** |
419 | * @param string $name |
420 | * @param array $screenshots |
421 | * @return string HTML |
422 | */ |
423 | private function makeScreenshotsLink( $name, $screenshots ) { |
424 | global $wgLang; |
425 | if ( count( $screenshots ) > 1 ) { |
426 | $links = []; |
427 | $counter = 1; |
428 | |
429 | foreach ( $screenshots as $shot ) { |
430 | $links[] = Html::element( |
431 | 'a', |
432 | [ 'href' => $shot, 'target' => '_blank' ], |
433 | $wgLang->formatNum( $counter++ ) |
434 | ); |
435 | } |
436 | return wfMessage( 'config-skins-screenshots' ) |
437 | ->rawParams( $name, $wgLang->commaList( $links ) ) |
438 | ->escaped(); |
439 | } else { |
440 | $link = Html::element( |
441 | 'a', |
442 | [ 'href' => $screenshots[0], 'target' => '_blank' ], |
443 | wfMessage( 'config-screenshot' )->text() |
444 | ); |
445 | return wfMessage( 'config-skins-screenshot', $name )->rawParams( $link )->escaped(); |
446 | } |
447 | } |
448 | |
449 | /** |
450 | * @param array $info |
451 | * @return string HTML |
452 | */ |
453 | private function makeMoreInfoLink( $info ) { |
454 | if ( !isset( $info['url'] ) ) { |
455 | return ''; |
456 | } |
457 | return ' ' . wfMessage( 'parentheses' )->rawParams( |
458 | Html::element( |
459 | 'a', |
460 | [ 'href' => $info['url'] ], |
461 | wfMessage( 'config-ext-skins-more-info' )->text() |
462 | ) |
463 | )->escaped(); |
464 | } |
465 | |
466 | /** |
467 | * If the user skips this installer page, we still need to set up the default skins, but ignore |
468 | * everything else. |
469 | * |
470 | * @return bool |
471 | */ |
472 | public function submitSkins() { |
473 | $skins = array_keys( $this->parent->findExtensions( 'skins' )->value ); |
474 | $this->parent->setVar( '_Skins', $skins ); |
475 | |
476 | if ( $skins ) { |
477 | $skinNames = array_map( 'strtolower', $skins ); |
478 | $this->parent->setVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) ); |
479 | } |
480 | |
481 | return true; |
482 | } |
483 | |
484 | /** |
485 | * @return bool |
486 | */ |
487 | public function submit() { |
488 | $this->parent->setVarsFromRequest( [ '_RightsProfile', '_LicenseCode', |
489 | 'wgEnableEmail', 'wgPasswordSender', 'wgEnableUploads', |
490 | '_Logo1x', '_LogoWordmark', '_LogoTagline', '_LogoIcon', |
491 | 'wgEnableUserEmail', 'wgEnotifUserTalk', 'wgEnotifWatchlist', |
492 | 'wgEmailAuthentication', '_MainCacheType', '_MemCachedServers', |
493 | 'wgUseInstantCommons', 'wgDefaultSkin' ] ); |
494 | |
495 | $retVal = true; |
496 | |
497 | if ( !array_key_exists( $this->getVar( '_RightsProfile' ), $this->parent->rightsProfiles ) ) { |
498 | $this->setVar( '_RightsProfile', array_key_first( $this->parent->rightsProfiles ) ); |
499 | } |
500 | |
501 | $code = $this->getVar( '_LicenseCode' ); |
502 | if ( array_key_exists( $code, $this->parent->licenses ) ) { |
503 | // Messages: |
504 | // config-license-cc-by, config-license-cc-by-sa, config-license-cc-by-nc-sa, |
505 | // config-license-cc-0, config-license-pd, config-license-gfdl, config-license-none |
506 | $entry = $this->parent->licenses[$code]; |
507 | $this->setVar( 'wgRightsText', |
508 | $entry['text'] ?? wfMessage( 'config-license-' . $code )->text() ); |
509 | $this->setVar( 'wgRightsUrl', $entry['url'] ); |
510 | $this->setVar( 'wgRightsIcon', $entry['icon'] ); |
511 | } else { |
512 | $this->setVar( 'wgRightsText', '' ); |
513 | $this->setVar( 'wgRightsUrl', '' ); |
514 | $this->setVar( 'wgRightsIcon', '' ); |
515 | } |
516 | |
517 | $skinsAvailable = array_keys( $this->parent->findExtensions( 'skins' )->value ); |
518 | $skinsToInstall = []; |
519 | foreach ( $skinsAvailable as $skin ) { |
520 | $this->parent->setVarsFromRequest( [ "skin-$skin" ] ); |
521 | if ( $this->getVar( "skin-$skin" ) ) { |
522 | $skinsToInstall[] = $skin; |
523 | } |
524 | } |
525 | $this->parent->setVar( '_Skins', $skinsToInstall ); |
526 | |
527 | if ( !$skinsToInstall && $skinsAvailable ) { |
528 | $this->parent->showError( 'config-skins-must-enable-some' ); |
529 | $retVal = false; |
530 | } |
531 | $defaultSkin = $this->getVar( 'wgDefaultSkin' ); |
532 | $skinsToInstallLowercase = array_map( 'strtolower', $skinsToInstall ); |
533 | if ( $skinsToInstall && !in_array( $defaultSkin, $skinsToInstallLowercase ) ) { |
534 | $this->parent->showError( 'config-skins-must-enable-default' ); |
535 | $retVal = false; |
536 | } |
537 | |
538 | $extsAvailable = array_keys( $this->parent->findExtensions()->value ); |
539 | $extsToInstall = []; |
540 | foreach ( $extsAvailable as $ext ) { |
541 | $this->parent->setVarsFromRequest( [ "ext-$ext" ] ); |
542 | if ( $this->getVar( "ext-$ext" ) ) { |
543 | $extsToInstall[] = $ext; |
544 | } |
545 | } |
546 | $this->parent->setVar( '_Extensions', $extsToInstall ); |
547 | |
548 | if ( $this->getVar( '_MainCacheType' ) == 'memcached' ) { |
549 | $memcServers = explode( "\n", $this->getVar( '_MemCachedServers' ) ); |
550 | // FIXME: explode() will always result in an array of at least one string, even on null (when |
551 | // the string will be empty and you'll get a PHP warning), so this has never worked? |
552 | // @phan-suppress-next-line PhanImpossibleCondition |
553 | if ( !$memcServers ) { |
554 | $this->parent->showError( 'config-memcache-needservers' ); |
555 | $retVal = false; |
556 | } |
557 | |
558 | foreach ( $memcServers as $server ) { |
559 | $memcParts = explode( ":", $server, 2 ); |
560 | if ( !isset( $memcParts[0] ) |
561 | || ( !IPUtils::isValid( $memcParts[0] ) |
562 | && ( gethostbyname( $memcParts[0] ) == $memcParts[0] ) ) |
563 | ) { |
564 | $this->parent->showError( 'config-memcache-badip', $memcParts[0] ); |
565 | $retVal = false; |
566 | } elseif ( !isset( $memcParts[1] ) ) { |
567 | $this->parent->showError( 'config-memcache-noport', $memcParts[0] ); |
568 | $retVal = false; |
569 | } elseif ( $memcParts[1] < 1 || $memcParts[1] > 65535 ) { |
570 | $this->parent->showError( 'config-memcache-badport', 1, 65535 ); |
571 | $retVal = false; |
572 | } |
573 | } |
574 | } |
575 | |
576 | return $retVal; |
577 | } |
578 | |
579 | } |