MediaWiki master
WebInstaller.php
Go to the documentation of this file.
1<?php
24namespace MediaWiki\Installer;
25
26use Exception;
27use HtmlArmor;
39
46class WebInstaller extends Installer {
47
51 public $output;
52
58 public $request;
59
65 protected $session;
66
72 protected $phpErrors;
73
84 public $pageSequence = [
85 'Language',
86 'ExistingWiki',
87 'Welcome',
88 'DBConnect',
89 'Upgrade',
90 'DBSettings',
91 'Name',
92 'Options',
93 'Install',
94 'Complete',
95 ];
96
102 protected $otherPages = [
103 'Restart',
104 'ReleaseNotes',
105 'Copying',
106 'UpgradeDoc', // Can't use Upgrade due to Upgrade step
107 ];
108
115 protected $happyPages;
116
124 protected $skippedPages;
125
131 public $showSessionWarning = false;
132
138 protected $tabIndex = 1;
139
145 protected $helpBoxId = 1;
146
153
154 public function __construct( WebRequest $request ) {
155 parent::__construct();
156 $this->output = new WebInstallerOutput( $this );
157 $this->request = $request;
158 }
159
167 public function execute( array $session ) {
168 $this->session = $session;
169
170 if ( isset( $session['settings'] ) ) {
171 $this->settings = $session['settings'] + $this->settings;
172 // T187586 MediaWikiServices works with globals
173 foreach ( $this->settings as $key => $val ) {
174 $GLOBALS[$key] = $val;
175 }
176 }
177
178 $this->setupLanguage();
179
180 if ( ( $this->getVar( '_InstallDone' ) || $this->getVar( '_UpgradeDone' ) )
181 && $this->request->getVal( 'localsettings' )
182 ) {
183 $this->outputLS();
184 return $this->session;
185 }
186
187 $isCSS = $this->request->getCheck( 'css' );
188 if ( $isCSS ) {
189 $this->outputCss();
190 return $this->session;
191 }
192
193 $this->happyPages = $session['happyPages'] ?? [];
194
195 $this->skippedPages = $session['skippedPages'] ?? [];
196
197 $lowestUnhappy = $this->getLowestUnhappy();
198
199 # Get the page name.
200 $pageName = $this->request->getVal( 'page', '' );
201
202 if ( in_array( $pageName, $this->otherPages ) ) {
203 # Out of sequence
204 $pageId = false;
205 $page = $this->getPageByName( $pageName );
206 } else {
207 # Main sequence
208 if ( !$pageName || !in_array( $pageName, $this->pageSequence ) ) {
209 $pageId = $lowestUnhappy;
210 } else {
211 $pageId = array_search( $pageName, $this->pageSequence );
212 }
213
214 # If necessary, move back to the lowest-numbered unhappy page
215 if ( $pageId > $lowestUnhappy ) {
216 $pageId = $lowestUnhappy;
217 if ( $lowestUnhappy == 0 ) {
218 # Knocked back to start, possible loss of session data.
219 $this->showSessionWarning = true;
220 }
221 }
222
223 $pageName = $this->pageSequence[$pageId];
224 $page = $this->getPageByName( $pageName );
225 }
226
227 # If a back button was submitted, go back without submitting the form data.
228 if ( $this->request->wasPosted() && $this->request->getBool( 'submit-back' ) ) {
229 if ( $this->request->getVal( 'lastPage' ) ) {
230 $nextPage = $this->request->getVal( 'lastPage' );
231 } elseif ( $pageId !== false ) {
232 # Main sequence page
233 # Skip the skipped pages
234 $nextPageId = $pageId;
235
236 do {
237 $nextPageId--;
238 $nextPage = $this->pageSequence[$nextPageId];
239 } while ( isset( $this->skippedPages[$nextPage] ) );
240 } else {
241 $nextPage = $this->pageSequence[$lowestUnhappy];
242 }
243
244 $this->output->redirect( $this->getUrl( [ 'page' => $nextPage ] ) );
245
246 return $this->finish();
247 }
248
249 # Execute the page.
250 $this->currentPageName = $page->getName();
251 $this->startPageWrapper( $pageName );
252
253 if ( $page->isSlow() ) {
254 $this->disableTimeLimit();
255 }
256
257 $result = $page->execute();
258
259 $this->endPageWrapper();
260
261 if ( $result == 'skip' ) {
262 # Page skipped without explicit submission.
263 # Skip it when we click "back" so that we don't just go forward again.
264 $this->skippedPages[$pageName] = true;
265 $result = 'continue';
266 } else {
267 unset( $this->skippedPages[$pageName] );
268 }
269
270 # If it was posted, the page can request a continue to the next page.
271 if ( $result === 'continue' && !$this->output->headerDone() ) {
272 if ( $pageId !== false ) {
273 $this->happyPages[$pageId] = true;
274 }
275
276 $lowestUnhappy = $this->getLowestUnhappy();
277
278 if ( $this->request->getVal( 'lastPage' ) ) {
279 $nextPage = $this->request->getVal( 'lastPage' );
280 } elseif ( $pageId !== false ) {
281 $nextPage = $this->pageSequence[$pageId + 1];
282 } else {
283 $nextPage = $this->pageSequence[$lowestUnhappy];
284 }
285
286 if ( array_search( $nextPage, $this->pageSequence ) > $lowestUnhappy ) {
287 $nextPage = $this->pageSequence[$lowestUnhappy];
288 }
289
290 $this->output->redirect( $this->getUrl( [ 'page' => $nextPage ] ) );
291 }
292
293 return $this->finish();
294 }
295
300 public function getLowestUnhappy() {
301 if ( count( $this->happyPages ) == 0 ) {
302 return 0;
303 } else {
304 return max( array_keys( $this->happyPages ) ) + 1;
305 }
306 }
307
314 public function startSession() {
315 if ( wfIniGetBool( 'session.auto_start' ) || session_id() ) {
316 // Done already
317 return true;
318 }
319
320 // Use secure cookies if we are on HTTPS
321 $options = [];
322 if ( $this->request->getProtocol() === 'https' ) {
323 $options['cookie_secure'] = '1';
324 }
325
326 $this->phpErrors = [];
327 set_error_handler( [ $this, 'errorHandler' ] );
328 try {
329 session_name( 'mw_installer_session' );
330 session_start( $options );
331 } catch ( Exception $e ) {
332 restore_error_handler();
333 throw $e;
334 }
335 restore_error_handler();
336
337 if ( $this->phpErrors ) {
338 return false;
339 }
340
341 return true;
342 }
343
352 public function getFingerprint() {
353 // Get the base URL of the installation
354 $url = $this->request->getFullRequestURL();
355 if ( preg_match( '!^(.*\?)!', $url, $m ) ) {
356 // Trim query string
357 $url = $m[1];
358 }
359 if ( preg_match( '!^(.*)/[^/]*/[^/]*$!', $url, $m ) ) {
360 // This... seems to try to get the base path from
361 // the /mw-config/index.php. Kinda scary though?
362 $url = $m[1];
363 }
364
365 return md5( serialize( [
366 'local path' => dirname( __DIR__ ),
367 'url' => $url,
368 'version' => MW_VERSION
369 ] ) );
370 }
371
372 public function showError( $msg, ...$params ) {
373 if ( !( $msg instanceof Message ) ) {
374 $msg = wfMessage(
375 $msg,
376 array_map( 'htmlspecialchars', $params )
377 );
378 }
379 $text = $msg->useDatabase( false )->parse();
380 $box = Html::errorBox( $text, '', 'config-error-box' );
381 $this->output->addHTML( $box );
382 }
383
390 public function errorHandler( $errno, $errstr ) {
391 $this->phpErrors[] = $errstr;
392 }
393
399 public function finish() {
400 $this->output->output();
401
402 $this->session['happyPages'] = $this->happyPages;
403 $this->session['skippedPages'] = $this->skippedPages;
404 $this->session['settings'] = $this->settings;
405
406 return $this->session;
407 }
408
412 public function reset() {
413 $this->session = [];
414 $this->happyPages = [];
415 $this->settings = [];
416 }
417
425 public function getUrl( $query = [] ) {
426 $url = $this->request->getRequestURL();
427 # Remove existing query
428 $url = preg_replace( '/\?.*$/', '', $url );
429
430 if ( $query ) {
431 $url .= '?' . wfArrayToCgi( $query );
432 }
433
434 return $url;
435 }
436
443 public function getPageByName( $pageName ) {
444 $pageClass = 'MediaWiki\\Installer\\WebInstaller' . $pageName;
445
446 return new $pageClass( $this );
447 }
448
457 public function getSession( $name, $default = null ) {
458 return $this->session[$name] ?? $default;
459 }
460
467 public function setSession( $name, $value ) {
468 $this->session[$name] = $value;
469 }
470
476 public function nextTabIndex() {
477 return $this->tabIndex++;
478 }
479
483 public function setupLanguage() {
484 global $wgLang, $wgLanguageCode;
485
486 if ( $this->getSession( 'test' ) === null && !$this->request->wasPosted() ) {
488 $wgLang = MediaWikiServices::getInstance()->getLanguageFactory()
489 ->getLanguage( $wgLanguageCode );
490 RequestContext::getMain()->setLanguage( $wgLang );
491 $this->setVar( 'wgLanguageCode', $wgLanguageCode );
492 $this->setVar( '_UserLang', $wgLanguageCode );
493 } else {
494 $wgLanguageCode = $this->getVar( 'wgLanguageCode' );
495 }
496 }
497
504 public function getAcceptLanguage() {
505 global $wgLanguageCode;
506
507 $mwLanguages = MediaWikiServices::getInstance()
508 ->getLanguageNameUtils()
509 ->getLanguageNames( LanguageNameUtils::AUTONYMS, LanguageNameUtils::SUPPORTED );
510 $headerLanguages = array_keys( $this->request->getAcceptLang() );
511
512 foreach ( $headerLanguages as $lang ) {
513 if ( isset( $mwLanguages[$lang] ) ) {
514 return $lang;
515 }
516 }
517
518 return $wgLanguageCode;
519 }
520
526 private function startPageWrapper( $currentPageName ) {
527 $s = "<div class=\"config-page-wrapper\">\n";
528 $s .= "<div class=\"config-page\">\n";
529 $s .= "<div class=\"config-page-list cdx-card\"><span class=\"cdx-card__text\">";
530 $s .= "<span class=\"cdx-card__text__description\"><ul>\n";
531 $lastHappy = -1;
532
533 foreach ( $this->pageSequence as $id => $pageName ) {
534 $happy = !empty( $this->happyPages[$id] );
535 $s .= $this->getPageListItem(
536 $pageName,
537 $happy || $lastHappy == $id - 1,
539 );
540
541 if ( $happy ) {
542 $lastHappy = $id;
543 }
544 }
545
546 $s .= "</ul><br/><ul>\n";
547 $s .= $this->getPageListItem( 'Restart', true, $currentPageName );
548 // End list pane
549 $s .= "</ul></span></span></div>\n";
550
551 // Messages:
552 // config-page-language, config-page-welcome, config-page-dbconnect, config-page-upgrade,
553 // config-page-dbsettings, config-page-name, config-page-options, config-page-install,
554 // config-page-complete, config-page-restart, config-page-releasenotes,
555 // config-page-copying, config-page-upgradedoc, config-page-existingwiki
556 $s .= Html::element( 'h2', [],
557 wfMessage( 'config-page-' . strtolower( $currentPageName ) )->text() );
558
559 $this->output->addHTMLNoFlush( $s );
560 }
561
571 private function getPageListItem( $pageName, $enabled, $currentPageName ) {
572 $s = "<li class=\"config-page-list-item\">";
573
574 // Messages:
575 // config-page-language, config-page-welcome, config-page-dbconnect, config-page-upgrade,
576 // config-page-dbsettings, config-page-name, config-page-options, config-page-install,
577 // config-page-complete, config-page-restart, config-page-releasenotes,
578 // config-page-copying, config-page-upgradedoc, config-page-existingwiki
579 $name = wfMessage( 'config-page-' . strtolower( $pageName ) )->text();
580
581 if ( $enabled ) {
582 $query = [ 'page' => $pageName ];
583
584 if ( !in_array( $pageName, $this->pageSequence ) ) {
585 if ( in_array( $currentPageName, $this->pageSequence ) ) {
586 $query['lastPage'] = $currentPageName;
587 }
588
589 $link = Html::element( 'a',
590 [
591 'href' => $this->getUrl( $query )
592 ],
593 $name
594 );
595 } else {
596 $link = htmlspecialchars( $name );
597 }
598
599 if ( $pageName == $currentPageName ) {
600 $s .= "<span class=\"config-page-current\">$link</span>";
601 } else {
602 $s .= $link;
603 }
604 } else {
605 $s .= Html::element( 'span',
606 [
607 'class' => 'config-page-disabled'
608 ],
609 $name
610 );
611 }
612
613 $s .= "</li>\n";
614
615 return $s;
616 }
617
621 private function endPageWrapper() {
622 $this->output->addHTMLNoFlush(
623 "<div class=\"visualClear\"></div>\n" .
624 "</div>\n" .
625 "<div class=\"visualClear\"></div>\n" .
626 "</div>" );
627 }
628
638 public function getHelpBox( $msg, ...$params ) {
639 $params = array_map( 'htmlspecialchars', $params );
640 $text = wfMessage( $msg, $params )->useDatabase( false )->plain();
641 $html = $this->parse( $text, true );
642
643 return "<div class=\"config-help-field-container\">\n" .
644 "<a class=\"config-help-field-hint\" title=\"" .
645 wfMessage( 'config-help-tooltip' )->escaped() . "\">ℹ️ " .
646 wfMessage( 'config-help' )->escaped() . "</a>\n" .
647 "<div class=\"config-help-field-content config-help-field-content-hidden " .
648 "cdx-message cdx-message--block cdx-message--notice\" style=\"margin: 10px\">" .
649 "<div class=\"cdx-message__content\">" . $html . "</div></div>\n" .
650 "</div>\n";
651 }
652
659 public function getInfoBox( $text ) {
660 $html = ( $text instanceof HtmlArmor ) ?
661 HtmlArmor::getHtml( $text ) :
662 $this->parse( $text, true );
663 return '<div class="cdx-message cdx-message--block cdx-message--notice">' .
664 '<span class="cdx-message__icon"></span><div class="cdx-message__content">' .
665 '<p><strong>' . wfMessage( 'config-information' )->escaped() . '</strong></p>' .
666 $html .
667 "</div></div>\n";
668 }
669
670 public function showSuccess( $msg, ...$params ) {
671 $html = '<div class="cdx-message cdx-message--block cdx-message--success">' .
672 '<span class="cdx-message__icon"></span><div class="cdx-message__content">' .
673 $this->parse( wfMessage( $msg, $params )->useDatabase( false )->plain() ) .
674 "</div></div>\n";
675 $this->output->addHTML( $html );
676 }
677
678 public function showMessage( $msg, ...$params ) {
679 $html = '<div class="cdx-message cdx-message--block cdx-message--notice">' .
680 '<span class="cdx-message__icon"></span><div class="cdx-message__content">' .
681 $this->parse( wfMessage( $msg, $params )->useDatabase( false )->plain() ) .
682 "</div></div>\n";
683 $this->output->addHTML( $html );
684 }
685
686 public function showWarning( $msg, ...$params ) {
687 $html = '<div class="cdx-message cdx-message--block cdx-message--warning">' .
688 '<span class="cdx-message__icon"></span><div class="cdx-message__content">' .
689 $this->parse( wfMessage( $msg, $params )->useDatabase( false )->plain() ) .
690 "</div></div>\n";
691 $this->output->addHTML( $html );
692 }
693
694 public function showStatusMessage( Status $status ) {
695 // Show errors at the top in web installer to make them easier to notice
696 foreach ( $status->getMessages( 'error' ) as $msg ) {
697 $this->showWarning( $msg );
698 }
699 foreach ( $status->getMessages( 'warning' ) as $msg ) {
700 $this->showWarning( $msg );
701 }
702 }
703
715 public function label( $msg, $forId, $contents, $helpData = "" ) {
716 if ( strval( $msg ) == '' ) {
717 $labelText = "\u{00A0}";
718 } else {
719 $labelText = wfMessage( $msg )->escaped();
720 }
721
722 $attributes = [ 'class' => 'config-label' ];
723
724 if ( $forId ) {
725 $attributes['for'] = $forId;
726 }
727
728 return "<div class=\"config-block\">\n" .
729 " <div class=\"config-block-label\">\n" .
730 Xml::tags( 'label',
731 $attributes,
732 $labelText
733 ) . "\n" .
734 $helpData .
735 " </div>\n" .
736 " <div class=\"config-block-elements\">\n" .
737 $contents .
738 " </div>\n" .
739 "</div>\n";
740 }
741
757 public function getTextBox( $params ) {
758 if ( !isset( $params['controlName'] ) ) {
759 $params['controlName'] = 'config_' . $params['var'];
760 }
761
762 if ( !isset( $params['value'] ) ) {
763 $params['value'] = $this->getVar( $params['var'] );
764 }
765
766 if ( !isset( $params['attribs'] ) ) {
767 $params['attribs'] = [];
768 }
769 if ( !isset( $params['help'] ) ) {
770 $params['help'] = "";
771 }
772
773 return $this->label(
774 $params['label'],
775 $params['controlName'],
776 "<div class=\"cdx-text-input\">" .
778 $params['controlName'],
779 30, // intended to be overridden by CSS
780 $params['value'],
781 $params['attribs'] + [
782 'id' => $params['controlName'],
783 'class' => 'cdx-text-input__input',
784 'tabindex' => $this->nextTabIndex()
785 ]
786 ) . "</div>",
787 $params['help']
788 );
789 }
790
805 public function getTextArea( $params ) {
806 if ( !isset( $params['controlName'] ) ) {
807 $params['controlName'] = 'config_' . $params['var'];
808 }
809
810 if ( !isset( $params['value'] ) ) {
811 $params['value'] = $this->getVar( $params['var'] );
812 }
813
814 if ( !isset( $params['attribs'] ) ) {
815 $params['attribs'] = [];
816 }
817 if ( !isset( $params['help'] ) ) {
818 $params['help'] = "";
819 }
820
821 return $this->label(
822 $params['label'],
823 $params['controlName'],
825 $params['controlName'],
826 $params['value'],
827 30,
828 5,
829 $params['attribs'] + [
830 'id' => $params['controlName'],
831 'class' => 'config-input-text',
832 'tabindex' => $this->nextTabIndex()
833 ]
834 ),
835 $params['help']
836 );
837 }
838
855 public function getPasswordBox( $params ) {
856 if ( !isset( $params['value'] ) ) {
857 $params['value'] = $this->getVar( $params['var'] );
858 }
859
860 if ( !isset( $params['attribs'] ) ) {
861 $params['attribs'] = [];
862 }
863
864 $params['value'] = $this->getFakePassword( $params['value'] );
865 $params['attribs']['type'] = 'password';
866
867 return $this->getTextBox( $params );
868 }
869
877 private static function addClassAttrib( &$attribs, $class ) {
878 if ( isset( $attribs['class'] ) ) {
879 $attribs['class'] .= ' ' . $class;
880 } else {
881 $attribs['class'] = $class;
882 }
883 }
884
901 public function getCheckBox( $params ) {
902 if ( !isset( $params['controlName'] ) ) {
903 $params['controlName'] = 'config_' . $params['var'];
904 }
905
906 if ( !isset( $params['value'] ) ) {
907 $params['value'] = $this->getVar( $params['var'] );
908 }
909
910 if ( !isset( $params['attribs'] ) ) {
911 $params['attribs'] = [];
912 }
913 if ( !isset( $params['help'] ) ) {
914 $params['help'] = "";
915 }
916 if ( !isset( $params['labelAttribs'] ) ) {
917 $params['labelAttribs'] = [];
918 }
919 $labelText = $params['rawtext'] ?? $this->parse( wfMessage( $params['label'] )->plain() );
920 $labelText = '<span class="cdx-label__label__text"> ' . $labelText . '</span>';
921 self::addClassAttrib( $params['attribs'], 'cdx-checkbox__input' );
922 self::addClassAttrib( $params['labelAttribs'], 'cdx-label__label' );
923
924 return "<div class=\"cdx-checkbox\" style=\"margin-top: 12px; margin-bottom: 2px;\">" .
925 "<div class=\"cdx-checkbox__wrapper\">\n" .
927 $params['controlName'],
928 $params['value'],
929 $params['attribs'] + [
930 'id' => $params['controlName'],
931 'tabindex' => $this->nextTabIndex()
932 ]
933 ) .
934 "<span class=\"cdx-checkbox__icon\"></span>" .
935 "<div class=\"cdx-checkbox__label cdx-label\">" .
936 Html::rawElement(
937 'label',
938 $params['labelAttribs'] + [
939 'for' => $params['controlName']
940 ],
941 $labelText
942 ) .
943 "</div></div></div>\n" . $params['help'];
944 }
945
966 public function getRadioSet( $params ) {
967 $items = $this->getRadioElements( $params );
968
969 $label = $params['label'] ?? '';
970
971 if ( !isset( $params['controlName'] ) ) {
972 $params['controlName'] = 'config_' . $params['var'];
973 }
974
975 if ( !isset( $params['help'] ) ) {
976 $params['help'] = "";
977 }
978
979 $s = "";
980 foreach ( $items as $item ) {
981 $s .= "$item\n";
982 }
983
984 return $this->label( $label, $params['controlName'], $s, $params['help'] );
985 }
986
996 public function getRadioElements( $params ) {
997 if ( !isset( $params['controlName'] ) ) {
998 $params['controlName'] = 'config_' . $params['var'];
999 }
1000
1001 if ( !isset( $params['value'] ) ) {
1002 $params['value'] = $this->getVar( $params['var'] );
1003 }
1004
1005 $items = [];
1006
1007 foreach ( $params['values'] as $value ) {
1008 $itemAttribs = [];
1009
1010 if ( isset( $params['commonAttribs'] ) ) {
1011 $itemAttribs = $params['commonAttribs'];
1012 }
1013
1014 if ( isset( $params['itemAttribs'][$value] ) ) {
1015 $itemAttribs = $params['itemAttribs'][$value] + $itemAttribs;
1016 }
1017
1018 $checked = $value == $params['value'];
1019 $id = $params['controlName'] . '_' . $value;
1020 $itemAttribs['id'] = $id;
1021 $itemAttribs['tabindex'] = $this->nextTabIndex();
1022 self::addClassAttrib( $itemAttribs, 'cdx-radio__input' );
1023
1024 $radioText = $this->parse(
1025 isset( $params['itemLabels'] ) ?
1026 wfMessage( $params['itemLabels'][$value] )->plain() :
1027 wfMessage( $params['itemLabelPrefix'] . strtolower( $value ) )->plain()
1028 );
1029 $items[$value] =
1030 '<span class="cdx-radio">' .
1031 '<span class="cdx-radio__wrapper">' .
1032 Xml::radio( $params['controlName'], $value, $checked, $itemAttribs ) .
1033 '<span class="cdx-radio__icon"></span>' .
1034 '<span class="cdx-radio__label cdx-label">' .
1035 Xml::tags(
1036 'label',
1037 [ 'for' => $id, 'class' => 'cdx-label__label' ],
1038 '<span class="cdx-label__label__text">' . $radioText . '</span>'
1039 ) . '</span></span></span>';
1040 }
1041
1042 return $items;
1043 }
1044
1050 public function showStatusBox( $status ) {
1051 if ( !$status->isGood() ) {
1052 $html = $status->getHTML();
1053
1054 if ( $status->isOK() ) {
1055 $box = Html::warningBox( $html, 'config-warning-box' );
1056 } else {
1057 $box = Html::errorBox( $html, '', 'config-error-box' );
1058 }
1059
1060 $this->output->addHTML( $box );
1061 }
1062 }
1063
1074 public function setVarsFromRequest( $varNames, $prefix = 'config_' ) {
1075 $newValues = [];
1076
1077 foreach ( $varNames as $name ) {
1078 $value = $this->request->getVal( $prefix . $name );
1079 // T32524, do not trim passwords
1080 if ( $value !== null && stripos( $name, 'password' ) === false ) {
1081 $value = trim( $value );
1082 }
1083 $newValues[$name] = $value;
1084
1085 if ( $value === null ) {
1086 // Checkbox?
1087 $this->setVar( $name, false );
1088 } elseif ( stripos( $name, 'password' ) !== false ) {
1089 $this->setPassword( $name, $value );
1090 } else {
1091 $this->setVar( $name, $value );
1092 }
1093 }
1094
1095 return $newValues;
1096 }
1097
1105 public function getDocUrl( $page ) {
1106 $query = [ 'page' => $page ];
1107
1108 if ( in_array( $this->currentPageName, $this->pageSequence ) ) {
1109 $query['lastPage'] = $this->currentPageName;
1110 }
1111
1112 return $this->getUrl( $query );
1113 }
1114
1123 public function makeLinkItem( $url, $linkText ) {
1124 return Html::rawElement( 'li', [],
1125 Html::element( 'a', [ 'href' => $url ], $linkText )
1126 );
1127 }
1128
1139 public function getLocalSettingsLocation() {
1140 return false;
1141 }
1142
1146 public function envCheckPath() {
1147 // PHP_SELF isn't available sometimes, such as when PHP is CGI but
1148 // cgi.fix_pathinfo is disabled. In that case, fall back to SCRIPT_NAME
1149 // to get the path to the current script... hopefully it's reliable. SIGH
1150 $path = false;
1151 if ( !empty( $_SERVER['PHP_SELF'] ) ) {
1152 $path = $_SERVER['PHP_SELF'];
1153 } elseif ( !empty( $_SERVER['SCRIPT_NAME'] ) ) {
1154 $path = $_SERVER['SCRIPT_NAME'];
1155 }
1156 if ( $path === false ) {
1157 $this->showError( 'config-no-uri' );
1158 return false;
1159 }
1160
1161 return parent::envCheckPath();
1162 }
1163
1164 protected function detectWebPaths() {
1165 // PHP_SELF isn't available sometimes, such as when PHP is CGI but
1166 // cgi.fix_pathinfo is disabled. In that case, fall back to SCRIPT_NAME
1167 // to get the path to the current script... hopefully it's reliable. SIGH
1168 $path = false;
1169 if ( !empty( $_SERVER['PHP_SELF'] ) ) {
1170 $path = $_SERVER['PHP_SELF'];
1171 } elseif ( !empty( $_SERVER['SCRIPT_NAME'] ) ) {
1172 $path = $_SERVER['SCRIPT_NAME'];
1173 }
1174 if ( $path !== false ) {
1175 $scriptPath = preg_replace( '{^(.*)/(mw-)?config.*$}', '$1', $path );
1176
1177 return [
1178 'wgScriptPath' => "$scriptPath",
1179 // Update variables set from Setup.php that are derived from wgScriptPath
1180 'wgScript' => "$scriptPath/index.php",
1181 'wgLoadScript' => "$scriptPath/load.php",
1182 'wgStylePath' => "$scriptPath/skins",
1183 'wgLocalStylePath' => "$scriptPath/skins",
1184 'wgExtensionAssetsPath' => "$scriptPath/extensions",
1185 'wgUploadPath' => "$scriptPath/images",
1186 'wgResourceBasePath' => "$scriptPath",
1187 ];
1188 }
1189 return [];
1190 }
1191
1195 protected function envGetDefaultServer() {
1196 $assumeProxiesUseDefaultProtocolPorts =
1197 $this->getVar( 'wgAssumeProxiesUseDefaultProtocolPorts' );
1198
1199 return WebRequest::detectServer( $assumeProxiesUseDefaultProtocolPorts );
1200 }
1201
1205 public function getDefaultServer() {
1206 return $this->envGetDefaultServer();
1207 }
1208
1212 private function outputLS() {
1213 $this->request->response()->header( 'Content-type: application/x-httpd-php' );
1214 $this->request->response()->header(
1215 'Content-Disposition: attachment; filename="LocalSettings.php"'
1216 );
1217
1219 $rightsProfile = $this->rightsProfiles[$this->getVar( '_RightsProfile' )];
1220 foreach ( $rightsProfile as $group => $rightsArr ) {
1221 $ls->setGroupRights( $group, $rightsArr );
1222 }
1223 echo $ls->getText();
1224 }
1225
1229 public function outputCss() {
1230 $this->request->response()->header( 'Content-type: text/css' );
1231 echo $this->output->getCSS();
1232 }
1233
1237 public function getPhpErrors() {
1238 return $this->phpErrors;
1239 }
1240
1247 public function needsUpgrade() {
1248 return $this->getDBInstaller()->needsUpgrade();
1249 }
1250
1256 public function doUpgrade() {
1257 $dbInstaller = $this->getDBInstaller();
1258 $dbInstaller->preUpgrade();
1259
1260 $taskList = new TaskList;
1261 $taskFactory = $this->getTaskFactory();
1262 $taskFactory->registerWebUpgradeTasks( $taskList );
1263 $taskRunner = new TaskRunner( $taskList, $taskFactory, TaskFactory::PROFILE_WEB_UPGRADE );
1264
1265 ob_start( [ $this, 'outputHandler' ] );
1266 try {
1267 $status = $taskRunner->execute();
1268 $ret = $status->isOK();
1269
1270 $this->setVar( '_UpgradeDone', true );
1271 } catch ( Exception $e ) {
1272 // TODO: Should this use MWExceptionRenderer?
1273 echo "\nAn error occurred:\n";
1274 echo $e->getMessage();
1275 $ret = false;
1276 }
1277 ob_end_flush();
1278
1279 return $ret;
1280 }
1281
1282 public function outputHandler( $string ) {
1283 return htmlspecialchars( $string );
1284 }
1285
1286}
const MW_VERSION
The running version of MediaWiki.
Definition Defines.php:37
wfIniGetBool( $setting)
Safety wrapper around ini_get() for boolean settings.
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined( 'MW_NO_SESSION') &&MW_ENTRY_POINT !=='cli' $wgLang
Definition Setup.php:562
Marks HTML that shouldn't be escaped.
Definition HtmlArmor.php:30
Group all the pieces relevant to the context of a request into one instance.
This class is a collection of static functions that serve two purposes:
Definition Html.php:56
static check( $name, $checked=false, array $attribs=[])
Convenience function to produce a checkbox (input element with type=checkbox)
Definition Html.php:672
static radio( $name, $checked=false, array $attribs=[])
Convenience function to produce a radio button (input element with type=radio)
Definition Html.php:812
static input( $name, $value='', $type='text', array $attribs=[])
Convenience function to produce an <input> element.
Definition Html.php:657
static textarea( $name, $value='', array $attribs=[])
Convenience function to produce a <textarea> element.
Definition Html.php:867
static getLocalSettingsGenerator(Installer $installer)
Instantiates and returns an instance of LocalSettingsGenerator or its descendant classes.
Base installer class.
Definition Installer.php:84
setVar( $name, $value)
Set a MW configuration variable, or internal installer configuration variable.
getFakePassword( $realPassword)
Get a fake password for sending back to the user in HTML.
disableTimeLimit()
Disable the time limit for execution.
setPassword( $name, $value)
Set a variable which stores a password, except if the new value is a fake password in which case leav...
parse( $text, $lineStart=false)
Convert wikitext $text to HTML.
getDBInstaller( $type=false)
Get an instance of DatabaseInstaller for the specified DB type.
getVar( $name, $default=null)
Get an MW configuration variable, or internal installer configuration variable.
Factory for installer tasks.
A container for tasks, with sorting of tasks by their declared dependencies.
Definition TaskList.php:13
Output class modelled on OutputPage.
Class for the core installer web interface.
int $tabIndex
Numeric index of the page we're on.
string[] $otherPages
Out of sequence pages, selectable by the user at any time.
detectWebPaths()
This is overridden by the web installer to provide the detected wgScriptPath.
getPageByName( $pageName)
Get a WebInstallerPage by name.
getLocalSettingsLocation()
If the software package wants the LocalSettings.php file to be placed in a specific location,...
errorHandler( $errno, $errstr)
Temporary error handler for session start debugging.
outputCss()
Output stylesheet for web installer pages.
showStatusMessage(Status $status)
Show a message to the installing user by using a Status object.
needsUpgrade()
Determine whether the current database needs to be upgraded, i.e.
string $currentPageName
Name of the page we're on.
array[] $session
Cached session array.
showSuccess( $msg,... $params)
Display a success message.
getUrl( $query=[])
Get a URL for submission back to the same script.
getFingerprint()
Get a hash of data identifying this MW installation.
makeLinkItem( $url, $linkText)
Helper for sidebar links.
string[] $pageSequence
The main sequence of page names.
getTextArea( $params)
Get a labelled textarea to configure a variable.
setupLanguage()
Initializes language-related variables.
reset()
We're restarting the installation, reset the session, happyPages, etc.
getRadioSet( $params)
Get a set of labelled radio buttons.
setSession( $name, $value)
Set a session variable.
getSession( $name, $default=null)
Get a session variable.
finish()
Clean up from execute()
label( $msg, $forId, $contents, $helpData="")
Label a control by wrapping a config-input div around it and putting a label before it.
startSession()
Start the PHP session.
__construct(WebRequest $request)
getRadioElements( $params)
Get a set of labelled radio buttons.
setVarsFromRequest( $varNames, $prefix='config_')
Convenience function to set variables based on form data.
getPasswordBox( $params)
Get a labelled password box to configure a variable.
getTextBox( $params)
Get a labelled text box to configure a variable.
getHelpBox( $msg,... $params)
Get small text indented help for a preceding form field.
bool $showSessionWarning
Flag indicating that session data may have been lost.
execute(array $session)
Main entry point.
int $helpBoxId
Numeric index of the help box.
getDocUrl( $page)
Helper for WebInstallerOutput.
bool[] $skippedPages
List of "skipped" pages.
showStatusBox( $status)
Output an error or warning box using a Status object.
WebRequest $request
WebRequest object.
getAcceptLanguage()
Retrieves MediaWiki language from Accept-Language HTTP header.
getInfoBox( $text)
Get HTML for an information message box.
string[] $phpErrors
Captured PHP error text.
showWarning( $msg,... $params)
Display a warning message.
doUpgrade()
Perform database upgrades.
getCheckBox( $params)
Get a labelled checkbox to configure a boolean variable.
bool[] $happyPages
Array of pages which have declared that they have been submitted, have validated their input,...
showMessage( $msg,... $params)
Display a short neutral message.
nextTabIndex()
Get the next tabindex attribute value.
getLowestUnhappy()
Find the next page in sequence that hasn't been completed.
showError( $msg,... $params)
Display an error message.
A service that provides utilities to do with language names and codes.
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:155
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form,...
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54
Module of static functions for generating XML.
Definition Xml.php:37
getMessages(?string $type=null)
Returns a list of error messages, optionally only those of the given type.
$wgLanguageCode
Config variable stub for the LanguageCode setting, for use by phpdoc and IDEs.
element(SerializerNode $parent, SerializerNode $node, $contents)