getVar( '_SkipOptional' ) == 'skip' ) { $this->submitSkins(); return 'skip'; } if ( $this->parent->request->wasPosted() && $this->submit() ) { return 'continue'; } $emailwrapperStyle = $this->getVar( 'wgEnableEmail' ) ? '' : 'display: none'; $this->startForm(); $this->addHTML( # User Rights // getRadioSet() builds a set of labeled radio buttons. // For grep: The following messages are used as the item labels: // config-profile-wiki, config-profile-no-anon, config-profile-fishbowl, config-profile-private $this->parent->getRadioSet( [ 'var' => '_RightsProfile', 'label' => 'config-profile', 'itemLabelPrefix' => 'config-profile-', 'values' => array_keys( $this->parent->rightsProfiles ), ] ) . $this->parent->getInfoBox( wfMessage( 'config-profile-help' )->plain() ) . # Licensing // getRadioSet() builds a set of labeled radio buttons. // For grep: The following messages are used as the item labels: // config-license-cc-by, config-license-cc-by-sa, config-license-cc-by-nc-sa, // config-license-cc-0, config-license-pd, config-license-gfdl, // config-license-none, config-license-cc-choose $this->parent->getRadioSet( [ 'var' => '_LicenseCode', 'label' => 'config-license', 'itemLabelPrefix' => 'config-license-', 'values' => array_keys( $this->parent->licenses ), 'commonAttribs' => [ 'class' => 'licenseRadio' ], ] ) . $this->getCCChooser() . $this->parent->getHelpBox( 'config-license-help' ) . # E-mail $this->getFieldsetStart( 'config-email-settings' ) . $this->parent->getCheckBox( [ 'var' => 'wgEnableEmail', 'label' => 'config-enable-email', 'attribs' => [ 'class' => 'showHideRadio', 'rel' => 'emailwrapper' ], ] ) . $this->parent->getHelpBox( 'config-enable-email-help' ) . "
" . $this->parent->getTextBox( [ 'var' => 'wgPasswordSender', 'label' => 'config-email-sender' ] ) . $this->parent->getHelpBox( 'config-email-sender-help' ) . $this->parent->getCheckBox( [ 'var' => 'wgEnableUserEmail', 'label' => 'config-email-user', ] ) . $this->parent->getHelpBox( 'config-email-user-help' ) . $this->parent->getCheckBox( [ 'var' => 'wgEnotifUserTalk', 'label' => 'config-email-usertalk', ] ) . $this->parent->getHelpBox( 'config-email-usertalk-help' ) . $this->parent->getCheckBox( [ 'var' => 'wgEnotifWatchlist', 'label' => 'config-email-watchlist', ] ) . $this->parent->getHelpBox( 'config-email-watchlist-help' ) . $this->parent->getCheckBox( [ 'var' => 'wgEmailAuthentication', 'label' => 'config-email-auth', ] ) . $this->parent->getHelpBox( 'config-email-auth-help' ) . "
" . $this->getFieldsetEnd() ); $skins = $this->parent->findExtensions( 'skins' )->value; '@phan-var array[] $skins'; $skinHtml = $this->getFieldsetStart( 'config-skins' ); $skinNames = array_map( 'strtolower', array_keys( $skins ) ); $chosenSkinName = $this->getVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) ); if ( $skins ) { $radioButtons = $this->parent->getRadioElements( [ 'var' => 'wgDefaultSkin', 'itemLabels' => array_fill_keys( $skinNames, 'config-skins-use-as-default' ), 'values' => $skinNames, 'value' => $chosenSkinName, ] ); foreach ( $skins as $skin => $info ) { if ( isset( $info['screenshots'] ) ) { $screenshotText = $this->makeScreenshotsLink( $skin, $info['screenshots'] ); } else { $screenshotText = htmlspecialchars( $skin ); } $skinHtml .= '
' . $this->parent->getCheckBox( [ 'var' => "skin-$skin", 'rawtext' => $screenshotText, 'value' => $this->getVar( "skin-$skin", true ), // all found skins enabled by default ] ) . '
' . $radioButtons[strtolower( $skin )] . '
' . '
'; } } else { $skinHtml .= Html::warningBox( wfMessage( 'config-skins-missing' )->plain(), 'config-warning-box' ) . Html::hidden( 'config_wgDefaultSkin', $chosenSkinName ); } $skinHtml .= $this->parent->getHelpBox( 'config-skins-help' ) . $this->getFieldsetEnd(); $this->addHTML( $skinHtml ); $extensions = $this->parent->findExtensions()->value; '@phan-var array[] $extensions'; $dependencyMap = []; if ( $extensions ) { $extHtml = $this->getFieldsetStart( 'config-extensions' ); $extByType = []; $types = SpecialVersion::getExtensionTypes(); // Sort by type first foreach ( $extensions as $ext => $info ) { if ( !isset( $info['type'] ) || !isset( $types[$info['type']] ) ) { // We let extensions normally define custom types, but // since we aren't loading extensions, we'll have to // categorize them under other $info['type'] = 'other'; } $extByType[$info['type']][$ext] = $info; } foreach ( $types as $type => $message ) { if ( !isset( $extByType[$type] ) ) { continue; } $extHtml .= Html::element( 'h2', [], $message ); foreach ( $extByType[$type] as $ext => $info ) { $urlText = ''; if ( isset( $info['url'] ) ) { $urlText = ' ' . Html::element( 'a', [ 'href' => $info['url'] ], '(more information)' ); } $attribs = [ 'data-name' => $ext, 'class' => 'config-ext-input' ]; $labelAttribs = []; $fullDepList = []; if ( isset( $info['requires']['extensions'] ) ) { $dependencyMap[$ext]['extensions'] = $info['requires']['extensions']; $labelAttribs['class'] = 'mw-ext-with-dependencies'; } if ( isset( $info['requires']['skins'] ) ) { $dependencyMap[$ext]['skins'] = $info['requires']['skins']; $labelAttribs['class'] = 'mw-ext-with-dependencies'; } if ( isset( $dependencyMap[$ext] ) ) { $links = []; // For each dependency, link to the checkbox for each // extension/skin that is required if ( isset( $dependencyMap[$ext]['extensions'] ) ) { foreach ( $dependencyMap[$ext]['extensions'] as $name ) { $links[] = Html::element( 'a', [ 'href' => "#config_ext-$name" ], $name ); } } if ( isset( $dependencyMap[$ext]['skins'] ) ) { foreach ( $dependencyMap[$ext]['skins'] as $name ) { $links[] = Html::element( 'a', [ 'href' => "#config_skin-$name" ], $name ); } } $text = wfMessage( 'config-extensions-requires' ) ->rawParams( $ext, $wgLang->commaList( $links ) ) ->escaped(); } else { $text = $ext; } $extHtml .= $this->parent->getCheckBox( [ 'var' => "ext-$ext", 'rawtext' => $text, 'attribs' => $attribs, 'labelAttribs' => $labelAttribs, ] ); } } $extHtml .= $this->parent->getHelpBox( 'config-extensions-help' ) . $this->getFieldsetEnd(); $this->addHTML( $extHtml ); // Push the dependency map to the client side $this->addHTML( Html::inlineScript( 'var extDependencyMap = ' . Xml::encodeJsVar( $dependencyMap ) ) ); } // Having / in paths in Windows looks funny :) $this->setVar( 'wgDeletedDirectory', str_replace( '/', DIRECTORY_SEPARATOR, $this->getVar( 'wgDeletedDirectory' ) ) ); $uploadwrapperStyle = $this->getVar( 'wgEnableUploads' ) ? '' : 'display: none'; $this->addHTML( # Uploading $this->getFieldsetStart( 'config-upload-settings' ) . $this->parent->getCheckBox( [ 'var' => 'wgEnableUploads', 'label' => 'config-upload-enable', 'attribs' => [ 'class' => 'showHideRadio', 'rel' => 'uploadwrapper' ], 'help' => $this->parent->getHelpBox( 'config-upload-help' ) ] ) . '
' . $this->parent->getTextBox( [ 'var' => 'wgDeletedDirectory', 'label' => 'config-upload-deleted', 'attribs' => [ 'dir' => 'ltr' ], 'help' => $this->parent->getHelpBox( 'config-upload-deleted-help' ) ] ) . '
' . $this->parent->getTextBox( [ 'var' => '_Logo', 'label' => 'config-logo', 'attribs' => [ 'dir' => 'ltr' ], 'help' => $this->parent->getHelpBox( 'config-logo-help' ) ] ) ); $this->addHTML( $this->parent->getCheckBox( [ 'var' => 'wgUseInstantCommons', 'label' => 'config-instantcommons', 'help' => $this->parent->getHelpBox( 'config-instantcommons-help' ) ] ) . $this->getFieldsetEnd() ); $caches = [ 'none' ]; $cachevalDefault = 'none'; if ( count( $this->getVar( '_Caches' ) ) ) { // A CACHE_ACCEL implementation is available $caches[] = 'accel'; $cachevalDefault = 'accel'; } $caches[] = 'memcached'; // We'll hide/show this on demand when the value changes, see config.js. $cacheval = $this->getVar( '_MainCacheType' ); if ( !$cacheval ) { // We need to set a default here; but don't hardcode it // or we lose it every time we reload the page for validation // or going back! $cacheval = $cachevalDefault; } $hidden = ( $cacheval == 'memcached' ) ? '' : 'display: none'; $this->addHTML( # Advanced settings $this->getFieldsetStart( 'config-advanced-settings' ) . # Object cache settings // getRadioSet() builds a set of labeled radio buttons. // For grep: The following messages are used as the item labels: // config-cache-none, config-cache-accel, config-cache-memcached $this->parent->getRadioSet( [ 'var' => '_MainCacheType', 'label' => 'config-cache-options', 'itemLabelPrefix' => 'config-cache-', 'values' => $caches, 'value' => $cacheval, ] ) . $this->parent->getHelpBox( 'config-cache-help' ) . "
" . $this->parent->getTextArea( [ 'var' => '_MemCachedServers', 'label' => 'config-memcached-servers', 'help' => $this->parent->getHelpBox( 'config-memcached-help' ) ] ) . '
' . $this->getFieldsetEnd() ); $this->endForm(); return null; } /** * @param string $name * @param array $screenshots * @return string HTML */ private function makeScreenshotsLink( $name, $screenshots ) { global $wgLang; if ( count( $screenshots ) > 1 ) { $links = []; $counter = 1; foreach ( $screenshots as $shot ) { $links[] = Html::element( 'a', [ 'href' => $shot, 'target' => '_blank' ], $wgLang->formatNum( $counter++ ) ); } return wfMessage( 'config-skins-screenshots' ) ->rawParams( $name, $wgLang->commaList( $links ) ) ->escaped(); } else { $link = Html::element( 'a', [ 'href' => $screenshots[0], 'target' => '_blank' ], wfMessage( 'config-screenshot' )->text() ); return wfMessage( 'config-skins-screenshot', $name )->rawParams( $link )->escaped(); } } /** * @return string */ public function getCCPartnerUrl() { $server = $this->getVar( 'wgServer' ); $exitUrl = $server . $this->parent->getUrl( [ 'page' => 'Options', 'SubmitCC' => 'indeed', 'config__LicenseCode' => 'cc', 'config_wgRightsUrl' => '[license_url]', 'config_wgRightsText' => '[license_name]', 'config_wgRightsIcon' => '[license_button]', ] ); $styleUrl = $server . dirname( dirname( $this->parent->getUrl() ) ) . '/mw-config/config-cc.css'; $iframeUrl = 'https://creativecommons.org/license/?' . wfArrayToCgi( [ 'partner' => 'MediaWiki', 'exit_url' => $exitUrl, 'lang' => $this->getVar( '_UserLang' ), 'stylesheet' => $styleUrl, ] ); return $iframeUrl; } /** * @return string */ public function getCCChooser() { $iframeAttribs = [ 'class' => 'config-cc-iframe', 'name' => 'config-cc-iframe', 'id' => 'config-cc-iframe', 'frameborder' => 0, 'width' => '100%', 'height' => '100%', ]; if ( $this->getVar( '_CCDone' ) ) { $iframeAttribs['src'] = $this->parent->getUrl( [ 'ShowCC' => 'yes' ] ); } else { $iframeAttribs['src'] = $this->getCCPartnerUrl(); } $wrapperStyle = ( $this->getVar( '_LicenseCode' ) == 'cc-choose' ) ? '' : 'display: none'; return "
\n" . Html::element( 'iframe', $iframeAttribs ) . "
\n"; } /** * @return string */ public function getCCDoneBox() { $js = "parent.document.getElementById('config-cc-wrapper').style.height = '$1';"; // If you change this height, also change it in config.css $expandJs = str_replace( '$1', '54em', $js ); $reduceJs = str_replace( '$1', '70px', $js ); return '

' . Html::element( 'img', [ 'src' => $this->getVar( 'wgRightsIcon' ) ] ) . "\u{00A0}\u{00A0}" . htmlspecialchars( $this->getVar( 'wgRightsText' ) ) . "

\n" . "

" . Html::element( 'a', [ 'href' => $this->getCCPartnerUrl(), 'onclick' => $expandJs, ], wfMessage( 'config-cc-again' )->text() ) . "

\n" . "\n"; } public function submitCC() { $newValues = $this->parent->setVarsFromRequest( [ 'wgRightsUrl', 'wgRightsText', 'wgRightsIcon' ] ); if ( count( $newValues ) != 3 ) { $this->parent->showError( 'config-cc-error' ); return; } $this->setVar( '_CCDone', true ); $this->addHTML( $this->getCCDoneBox() ); } /** * If the user skips this installer page, we still need to set up the default skins, but ignore * everything else. * * @return bool */ public function submitSkins() { $skins = array_keys( $this->parent->findExtensions( 'skins' )->value ); $this->parent->setVar( '_Skins', $skins ); if ( $skins ) { $skinNames = array_map( 'strtolower', $skins ); $this->parent->setVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) ); } return true; } /** * @return bool */ public function submit() { $this->parent->setVarsFromRequest( [ '_RightsProfile', '_LicenseCode', 'wgEnableEmail', 'wgPasswordSender', 'wgEnableUploads', '_Logo', 'wgEnableUserEmail', 'wgEnotifUserTalk', 'wgEnotifWatchlist', 'wgEmailAuthentication', '_MainCacheType', '_MemCachedServers', 'wgUseInstantCommons', 'wgDefaultSkin' ] ); $retVal = true; if ( !array_key_exists( $this->getVar( '_RightsProfile' ), $this->parent->rightsProfiles ) ) { reset( $this->parent->rightsProfiles ); $this->setVar( '_RightsProfile', key( $this->parent->rightsProfiles ) ); } // If this is empty, either the default got lost internally // or the user blanked it if ( strval( $this->getVar( '_Logo' ) ) === '' ) { $this->parent->showError( 'config-install-logo-blank' ); $retVal = false; } $code = $this->getVar( '_LicenseCode' ); if ( $code == 'cc-choose' ) { if ( !$this->getVar( '_CCDone' ) ) { $this->parent->showError( 'config-cc-not-chosen' ); $retVal = false; } } elseif ( array_key_exists( $code, $this->parent->licenses ) ) { // Messages: // config-license-cc-by, config-license-cc-by-sa, config-license-cc-by-nc-sa, // config-license-cc-0, config-license-pd, config-license-gfdl, config-license-none, // config-license-cc-choose $entry = $this->parent->licenses[$code]; $this->setVar( 'wgRightsText', $entry['text'] ?? wfMessage( 'config-license-' . $code )->text() ); $this->setVar( 'wgRightsUrl', $entry['url'] ); $this->setVar( 'wgRightsIcon', $entry['icon'] ); } else { $this->setVar( 'wgRightsText', '' ); $this->setVar( 'wgRightsUrl', '' ); $this->setVar( 'wgRightsIcon', '' ); } $skinsAvailable = array_keys( $this->parent->findExtensions( 'skins' )->value ); $skinsToInstall = []; foreach ( $skinsAvailable as $skin ) { $this->parent->setVarsFromRequest( [ "skin-$skin" ] ); if ( $this->getVar( "skin-$skin" ) ) { $skinsToInstall[] = $skin; } } $this->parent->setVar( '_Skins', $skinsToInstall ); if ( !$skinsToInstall && $skinsAvailable ) { $this->parent->showError( 'config-skins-must-enable-some' ); $retVal = false; } $defaultSkin = $this->getVar( 'wgDefaultSkin' ); $skinsToInstallLowercase = array_map( 'strtolower', $skinsToInstall ); if ( $skinsToInstall && array_search( $defaultSkin, $skinsToInstallLowercase ) === false ) { $this->parent->showError( 'config-skins-must-enable-default' ); $retVal = false; } $extsAvailable = array_keys( $this->parent->findExtensions()->value ); $extsToInstall = []; foreach ( $extsAvailable as $ext ) { $this->parent->setVarsFromRequest( [ "ext-$ext" ] ); if ( $this->getVar( "ext-$ext" ) ) { $extsToInstall[] = $ext; } } $this->parent->setVar( '_Extensions', $extsToInstall ); if ( $this->getVar( '_MainCacheType' ) == 'memcached' ) { $memcServers = explode( "\n", $this->getVar( '_MemCachedServers' ) ); if ( !$memcServers ) { $this->parent->showError( 'config-memcache-needservers' ); $retVal = false; } foreach ( $memcServers as $server ) { $memcParts = explode( ":", $server, 2 ); if ( !isset( $memcParts[0] ) || ( !IPUtils::isValid( $memcParts[0] ) && ( gethostbyname( $memcParts[0] ) == $memcParts[0] ) ) ) { $this->parent->showError( 'config-memcache-badip', $memcParts[0] ); $retVal = false; } elseif ( !isset( $memcParts[1] ) ) { $this->parent->showError( 'config-memcache-noport', $memcParts[0] ); $retVal = false; } elseif ( $memcParts[1] < 1 || $memcParts[1] > 65535 ) { $this->parent->showError( 'config-memcache-badport', 1, 65535 ); $retVal = false; } } } return $retVal; } }