wiki.techinc.nl/includes/installer/WebInstaller.php

1172 lines
29 KiB
PHP
Raw Normal View History

<?php
/**
* Core installer web interface.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup Deployment
*/
/**
* Class for the core installer web interface.
2010-10-02 07:40:54 +00:00
*
2010-07-29 18:36:39 +00:00
* @ingroup Deployment
* @since 1.17
*/
class WebInstaller extends Installer {
2010-10-02 07:40:54 +00:00
/**
* @var WebInstallerOutput
*/
2010-10-02 07:40:54 +00:00
public $output;
2010-07-21 09:34:16 +00:00
/**
* WebRequest object.
2010-10-02 07:40:54 +00:00
*
2010-07-21 09:34:16 +00:00
* @var WebRequest
*/
2010-07-19 03:16:54 +00:00
public $request;
2010-07-21 09:34:16 +00:00
/**
* Cached session array.
2010-10-02 07:40:54 +00:00
*
* @var array[]
2010-07-21 09:34:16 +00:00
*/
2011-01-28 15:00:18 +00:00
protected $session;
2010-10-02 07:40:54 +00:00
/**
* Captured PHP error text. Temporary.
*
* @var string[]
*/
2011-01-28 15:00:18 +00:00
protected $phpErrors;
/**
* The main sequence of page names. These will be displayed in turn.
*
* To add a new installer page:
* * Add it to this WebInstaller::$pageSequence property
* * Add a "config-page-<name>" message
* * Add a "WebInstaller<name>" class
*
* @var string[]
*/
2010-07-19 03:16:54 +00:00
public $pageSequence = array(
'Language',
2010-12-09 08:24:54 +00:00
'ExistingWiki',
'Welcome',
'DBConnect',
'Upgrade',
'DBSettings',
'Name',
'Options',
'Install',
'Complete',
);
/**
2010-07-19 03:16:54 +00:00
* Out of sequence pages, selectable by the user at any time.
*
* @var string[]
*/
2011-01-28 15:00:18 +00:00
protected $otherPages = array(
'Restart',
'Readme',
'ReleaseNotes',
'Copying',
'UpgradeDoc', // Can't use Upgrade due to Upgrade step
);
/**
* Array of pages which have declared that they have been submitted, have validated
2010-07-19 03:16:54 +00:00
* their input, and need no further processing.
*
* @var bool[]
*/
2011-01-28 15:00:18 +00:00
protected $happyPages;
/**
* List of "skipped" pages. These are pages that will automatically continue
* to the next page on any GET request. To avoid breaking the "back" button,
* they need to be skipped during a back operation.
*
* @var bool[]
*/
2011-01-28 15:00:18 +00:00
protected $skippedPages;
/**
2010-07-19 03:16:54 +00:00
* Flag indicating that session data may have been lost.
*
2011-01-28 15:00:18 +00:00
* @var bool
*/
2010-07-19 03:16:54 +00:00
public $showSessionWarning = false;
2011-01-28 15:00:18 +00:00
/**
* Numeric index of the page we're on
*
2011-01-28 15:00:18 +00:00
* @var int
*/
protected $tabIndex = 1;
2011-01-28 15:00:18 +00:00
/**
* Name of the page we're on
*
2011-01-28 15:00:18 +00:00
* @var string
*/
protected $currentPageName;
2010-10-02 07:40:54 +00:00
/**
2010-07-21 09:34:16 +00:00
* Constructor.
2010-10-02 07:40:54 +00:00
*
* @param WebRequest $request
2010-07-21 09:34:16 +00:00
*/
public function __construct( WebRequest $request ) {
parent::__construct();
$this->output = new WebInstallerOutput( $this );
$this->request = $request;
2011-03-20 17:54:43 +00:00
// Add parser hooks
global $wgParser;
2010-12-16 11:20:39 +00:00
$wgParser->setHook( 'downloadlink', array( $this, 'downloadLinkHook' ) );
2011-03-20 17:54:43 +00:00
$wgParser->setHook( 'doclink', array( $this, 'docLink' ) );
}
/**
* Main entry point.
2010-10-02 07:40:54 +00:00
*
* @param array[] $session initial session array
2010-10-02 07:40:54 +00:00
*
* @return array[] New session array
*/
2010-07-21 09:34:16 +00:00
public function execute( array $session ) {
$this->session = $session;
2010-10-02 07:40:54 +00:00
if ( isset( $session['settings'] ) ) {
$this->settings = $session['settings'] + $this->settings;
}
2010-10-02 07:40:54 +00:00
$this->exportVars();
$this->setupLanguage();
if ( ( $this->getVar( '_InstallDone' ) || $this->getVar( '_UpgradeDone' ) )
&& $this->request->getVal( 'localsettings' )
) {
$this->request->response()->header( 'Content-type: application/x-httpd-php' );
$this->request->response()->header(
'Content-Disposition: attachment; filename="LocalSettings.php"'
);
2010-10-02 07:40:54 +00:00
$ls = InstallerOverrides::getLocalSettingsGenerator( $this );
$rightsProfile = $this->rightsProfiles[$this->getVar( '_RightsProfile' )];
foreach ( $rightsProfile as $group => $rightsArr ) {
$ls->setGroupRights( $group, $rightsArr );
}
echo $ls->getText();
return $this->session;
}
$isCSS = $this->request->getVal( 'css' );
if ( $isCSS ) {
$this->outputCss();
return $this->session;
}
if ( isset( $session['happyPages'] ) ) {
$this->happyPages = $session['happyPages'];
} else {
$this->happyPages = array();
}
2010-10-02 07:40:54 +00:00
if ( isset( $session['skippedPages'] ) ) {
$this->skippedPages = $session['skippedPages'];
} else {
$this->skippedPages = array();
}
2010-10-02 07:40:54 +00:00
$lowestUnhappy = $this->getLowestUnhappy();
# Special case for Creative Commons partner chooser box.
if ( $this->request->getVal( 'SubmitCC' ) ) {
$page = $this->getPageByName( 'Options' );
$this->output->useShortHeader();
$this->output->allowFrames();
$page->submitCC();
return $this->finish();
}
2010-10-02 07:40:54 +00:00
if ( $this->request->getVal( 'ShowCC' ) ) {
$page = $this->getPageByName( 'Options' );
$this->output->useShortHeader();
$this->output->allowFrames();
$this->output->addHTML( $page->getCCDoneBox() );
return $this->finish();
}
# Get the page name.
$pageName = $this->request->getVal( 'page' );
2010-12-09 08:24:54 +00:00
if ( in_array( $pageName, $this->otherPages ) ) {
# Out of sequence
$pageId = false;
$page = $this->getPageByName( $pageName );
} else {
# Main sequence
if ( !$pageName || !in_array( $pageName, $this->pageSequence ) ) {
$pageId = $lowestUnhappy;
} else {
$pageId = array_search( $pageName, $this->pageSequence );
}
# If necessary, move back to the lowest-numbered unhappy page
if ( $pageId > $lowestUnhappy ) {
$pageId = $lowestUnhappy;
if ( $lowestUnhappy == 0 ) {
# Knocked back to start, possible loss of session data.
$this->showSessionWarning = true;
}
}
2010-10-02 07:40:54 +00:00
$pageName = $this->pageSequence[$pageId];
$page = $this->getPageByName( $pageName );
}
# If a back button was submitted, go back without submitting the form data.
if ( $this->request->wasPosted() && $this->request->getBool( 'submit-back' ) ) {
if ( $this->request->getVal( 'lastPage' ) ) {
$nextPage = $this->request->getVal( 'lastPage' );
} elseif ( $pageId !== false ) {
# Main sequence page
# Skip the skipped pages
$nextPageId = $pageId;
2010-10-02 07:40:54 +00:00
do {
$nextPageId--;
$nextPage = $this->pageSequence[$nextPageId];
} while ( isset( $this->skippedPages[$nextPage] ) );
} else {
$nextPage = $this->pageSequence[$lowestUnhappy];
}
2010-10-02 07:40:54 +00:00
$this->output->redirect( $this->getUrl( array( 'page' => $nextPage ) ) );
return $this->finish();
}
# Execute the page.
$this->currentPageName = $page->getName();
$this->startPageWrapper( $pageName );
2010-10-02 07:40:54 +00:00
if ( $page->isSlow() ) {
$this->disableTimeLimit();
}
$result = $page->execute();
2010-10-02 07:40:54 +00:00
$this->endPageWrapper();
if ( $result == 'skip' ) {
# Page skipped without explicit submission.
# Skip it when we click "back" so that we don't just go forward again.
$this->skippedPages[$pageName] = true;
$result = 'continue';
} else {
unset( $this->skippedPages[$pageName] );
}
# If it was posted, the page can request a continue to the next page.
if ( $result === 'continue' && !$this->output->headerDone() ) {
if ( $pageId !== false ) {
$this->happyPages[$pageId] = true;
}
2010-10-02 07:40:54 +00:00
$lowestUnhappy = $this->getLowestUnhappy();
if ( $this->request->getVal( 'lastPage' ) ) {
$nextPage = $this->request->getVal( 'lastPage' );
} elseif ( $pageId !== false ) {
$nextPage = $this->pageSequence[$pageId + 1];
} else {
$nextPage = $this->pageSequence[$lowestUnhappy];
}
2010-10-02 07:40:54 +00:00
if ( array_search( $nextPage, $this->pageSequence ) > $lowestUnhappy ) {
$nextPage = $this->pageSequence[$lowestUnhappy];
}
2010-10-02 07:40:54 +00:00
$this->output->redirect( $this->getUrl( array( 'page' => $nextPage ) ) );
}
2010-10-02 07:40:54 +00:00
return $this->finish();
}
2011-01-28 15:00:18 +00:00
/**
* Find the next page in sequence that hasn't been completed
* @return int
*/
2010-07-19 03:16:54 +00:00
public function getLowestUnhappy() {
if ( count( $this->happyPages ) == 0 ) {
return 0;
} else {
return max( array_keys( $this->happyPages ) ) + 1;
}
}
/**
* Start the PHP session. This may be called before execute() to start the PHP session.
2011-05-02 16:58:29 +00:00
*
* @throws Exception
2011-05-02 16:58:29 +00:00
* @return bool
*/
2010-07-19 03:16:54 +00:00
public function startSession() {
if ( wfIniGetBool( 'session.auto_start' ) || session_id() ) {
// Done already
return true;
}
$this->phpErrors = array();
set_error_handler( array( $this, 'errorHandler' ) );
try {
session_start();
} catch ( Exception $e ) {
restore_error_handler();
throw $e;
}
restore_error_handler();
2010-10-02 07:40:54 +00:00
if ( $this->phpErrors ) {
return false;
}
2010-10-02 07:40:54 +00:00
return true;
}
/**
* Get a hash of data identifying this MW installation.
*
* This is used by mw-config/index.php to prevent multiple installations of MW
* on the same cookie domain from interfering with each other.
2011-05-02 16:58:29 +00:00
*
* @return string
*/
public function getFingerprint() {
// Get the base URL of the installation
$url = $this->request->getFullRequestURL();
if ( preg_match( '!^(.*\?)!', $url, $m ) ) {
// Trim query string
$url = $m[1];
}
if ( preg_match( '!^(.*)/[^/]*/[^/]*$!', $url, $m ) ) {
// This... seems to try to get the base path from
// the /mw-config/index.php. Kinda scary though?
$url = $m[1];
}
return md5( serialize( array(
'local path' => dirname( __DIR__ ),
'url' => $url,
'version' => $GLOBALS['wgVersion']
) ) );
}
/**
* Show an error message in a box. Parameters are like wfMessage().
* @param string $msg
*/
2010-07-19 03:16:54 +00:00
public function showError( $msg /*...*/ ) {
$args = func_get_args();
array_shift( $args );
$args = array_map( 'htmlspecialchars', $args );
$msg = wfMessage( $msg, $args )->useDatabase( false )->plain();
$this->output->addHTML( $this->getErrorBox( $msg ) );
}
/**
2010-07-19 03:16:54 +00:00
* Temporary error handler for session start debugging.
*
* @param int $errno Unused
* @param string $errstr
*/
2010-07-19 03:16:54 +00:00
public function errorHandler( $errno, $errstr ) {
$this->phpErrors[] = $errstr;
}
/**
* Clean up from execute()
2010-10-02 07:40:54 +00:00
*
* @return array[]
*/
public function finish() {
$this->output->output();
2010-10-02 07:40:54 +00:00
$this->session['happyPages'] = $this->happyPages;
$this->session['skippedPages'] = $this->skippedPages;
$this->session['settings'] = $this->settings;
2010-10-02 07:40:54 +00:00
return $this->session;
}
2011-01-28 15:00:18 +00:00
/**
* We're restarting the installation, reset the session, happyPages, etc
*/
public function reset() {
$this->session = array();
$this->happyPages = array();
$this->settings = array();
}
/**
2010-07-19 03:16:54 +00:00
* Get a URL for submission back to the same script.
2010-10-02 07:40:54 +00:00
*
* @param string[] $query
*
2011-01-28 15:00:18 +00:00
* @return string
*/
2010-07-19 03:16:54 +00:00
public function getUrl( $query = array() ) {
$url = $this->request->getRequestURL();
# Remove existing query
$url = preg_replace( '/\?.*$/', '', $url );
2010-10-02 07:40:54 +00:00
if ( $query ) {
$url .= '?' . wfArrayToCgi( $query );
}
2010-10-02 07:40:54 +00:00
return $url;
}
/**
2010-07-19 03:16:54 +00:00
* Get a WebInstallerPage by name.
2010-10-02 07:40:54 +00:00
*
* @param string $pageName
2010-07-21 09:34:16 +00:00
* @return WebInstallerPage
*/
2010-07-19 03:16:54 +00:00
public function getPageByName( $pageName ) {
$pageClass = 'WebInstaller' . $pageName;
2010-10-02 07:40:54 +00:00
return new $pageClass( $this );
}
/**
2010-07-19 03:16:54 +00:00
* Get a session variable.
2010-10-02 07:40:54 +00:00
*
* @param string $name
* @param array $default
*
* @return array
*/
2010-07-19 03:16:54 +00:00
public function getSession( $name, $default = null ) {
if ( !isset( $this->session[$name] ) ) {
return $default;
} else {
return $this->session[$name];
}
}
/**
2010-07-19 03:16:54 +00:00
* Set a session variable.
*
* @param string $name Key for the variable
* @param mixed $value
*/
2010-07-19 03:16:54 +00:00
public function setSession( $name, $value ) {
$this->session[$name] = $value;
}
/**
2010-07-19 03:16:54 +00:00
* Get the next tabindex attribute value.
*
2011-01-28 15:00:18 +00:00
* @return int
*/
2010-07-19 03:16:54 +00:00
public function nextTabIndex() {
return $this->tabIndex++;
}
/**
2010-07-19 03:16:54 +00:00
* Initializes language-related variables.
*/
2010-07-19 03:16:54 +00:00
public function setupLanguage() {
global $wgLang, $wgContLang, $wgLanguageCode;
2010-10-02 07:40:54 +00:00
if ( $this->getSession( 'test' ) === null && !$this->request->wasPosted() ) {
$wgLanguageCode = $this->getAcceptLanguage();
$wgLang = $wgContLang = Language::factory( $wgLanguageCode );
$this->setVar( 'wgLanguageCode', $wgLanguageCode );
$this->setVar( '_UserLang', $wgLanguageCode );
} else {
$wgLanguageCode = $this->getVar( 'wgLanguageCode' );
$wgContLang = Language::factory( $wgLanguageCode );
}
}
/**
2010-07-19 03:16:54 +00:00
* Retrieves MediaWiki language from Accept-Language HTTP header.
2010-10-02 07:40:54 +00:00
*
2010-07-21 09:34:16 +00:00
* @return string
*/
2010-07-19 03:16:54 +00:00
public function getAcceptLanguage() {
global $wgLanguageCode, $wgRequest;
$mwLanguages = Language::fetchLanguageNames();
$headerLanguages = array_keys( $wgRequest->getAcceptLang() );
2010-10-02 07:40:54 +00:00
foreach ( $headerLanguages as $lang ) {
if ( isset( $mwLanguages[$lang] ) ) {
return $lang;
}
}
2010-10-02 07:40:54 +00:00
return $wgLanguageCode;
}
/**
2010-07-19 03:16:54 +00:00
* Called by execute() before page output starts, to show a page list.
2010-10-02 07:40:54 +00:00
*
* @param string $currentPageName
*/
private function startPageWrapper( $currentPageName ) {
$s = "<div class=\"config-page-wrapper\">\n";
$s .= "<div class=\"config-page\">\n";
$s .= "<div class=\"config-page-list\"><ul>\n";
$lastHappy = -1;
2010-10-02 07:40:54 +00:00
foreach ( $this->pageSequence as $id => $pageName ) {
$happy = !empty( $this->happyPages[$id] );
2010-10-02 07:40:54 +00:00
$s .= $this->getPageListItem(
$pageName,
$happy || $lastHappy == $id - 1,
$currentPageName
);
2010-10-02 07:40:54 +00:00
if ( $happy ) {
$lastHappy = $id;
}
}
2010-10-02 07:40:54 +00:00
$s .= "</ul><br/><ul>\n";
$s .= $this->getPageListItem( 'Restart', true, $currentPageName );
// End list pane
$s .= "</ul></div>\n";
// Messages:
// config-page-language, config-page-welcome, config-page-dbconnect, config-page-upgrade,
// config-page-dbsettings, config-page-name, config-page-options, config-page-install,
// config-page-complete, config-page-restart, config-page-readme, config-page-releasenotes,
// config-page-copying, config-page-upgradedoc, config-page-existingwiki
$s .= Html::element( 'h2', array(),
wfMessage( 'config-page-' . strtolower( $currentPageName ) )->text() );
$this->output->addHTMLNoFlush( $s );
}
/**
2010-07-19 03:16:54 +00:00
* Get a list item for the page list.
2010-10-02 07:40:54 +00:00
*
* @param string $pageName
* @param bool $enabled
* @param string $currentPageName
2010-10-02 07:40:54 +00:00
*
2010-07-21 09:34:16 +00:00
* @return string
*/
private function getPageListItem( $pageName, $enabled, $currentPageName ) {
$s = "<li class=\"config-page-list-item\">";
// Messages:
// config-page-language, config-page-welcome, config-page-dbconnect, config-page-upgrade,
// config-page-dbsettings, config-page-name, config-page-options, config-page-install,
// config-page-complete, config-page-restart, config-page-readme, config-page-releasenotes,
// config-page-copying, config-page-upgradedoc, config-page-existingwiki
$name = wfMessage( 'config-page-' . strtolower( $pageName ) )->text();
2010-10-02 07:40:54 +00:00
if ( $enabled ) {
$query = array( 'page' => $pageName );
2010-10-02 07:40:54 +00:00
if ( !in_array( $pageName, $this->pageSequence ) ) {
if ( in_array( $currentPageName, $this->pageSequence ) ) {
$query['lastPage'] = $currentPageName;
}
2010-10-02 07:40:54 +00:00
2010-11-04 23:23:34 +00:00
$link = Html::element( 'a',
array(
'href' => $this->getUrl( $query )
),
$name
);
} else {
$link = htmlspecialchars( $name );
}
2010-10-02 07:40:54 +00:00
if ( $pageName == $currentPageName ) {
$s .= "<span class=\"config-page-current\">$link</span>";
} else {
$s .= $link;
}
} else {
2010-11-04 23:23:34 +00:00
$s .= Html::element( 'span',
array(
'class' => 'config-page-disabled'
),
$name
);
}
2010-10-02 07:40:54 +00:00
$s .= "</li>\n";
2010-10-02 07:40:54 +00:00
return $s;
}
/**
2010-07-19 03:16:54 +00:00
* Output some stuff after a page is finished.
*/
private function endPageWrapper() {
$this->output->addHTMLNoFlush(
"<div class=\"visualClear\"></div>\n" .
"</div>\n" .
"<div class=\"visualClear\"></div>\n" .
"</div>" );
}
/**
2010-07-19 03:16:54 +00:00
* Get HTML for an error box with an icon.
2010-05-08 20:04:48 +00:00
*
* @param string $text Wikitext, get this with wfMessage()->plain()
2011-05-02 16:58:29 +00:00
*
* @return string
*/
2010-07-19 03:16:54 +00:00
public function getErrorBox( $text ) {
return $this->getInfoBox( $text, 'critical-32.png', 'config-error-box' );
}
/**
2010-07-19 03:16:54 +00:00
* Get HTML for a warning box with an icon.
2010-05-08 20:04:48 +00:00
*
* @param string $text Wikitext, get this with wfMessage()->plain()
2011-05-02 16:58:29 +00:00
*
* @return string
*/
2010-07-19 03:16:54 +00:00
public function getWarningBox( $text ) {
return $this->getInfoBox( $text, 'warning-32.png', 'config-warning-box' );
}
/**
2010-07-19 03:16:54 +00:00
* Get HTML for an info box with an icon.
2010-05-08 20:04:48 +00:00
*
* @param string $text Wikitext, get this with wfMessage()->plain()
* @param string|bool $icon Icon name, file in skins/common/images. Default: false
* @param string|bool $class Additional class name to add to the wrapper div. Default: false.
2011-05-02 16:58:29 +00:00
*
* @return string
*/
public function getInfoBox( $text, $icon = false, $class = false ) {
$text = $this->parse( $text, true );
$icon = ( $icon == false ) ?
'../skins/common/images/info-32.png' :
'../skins/common/images/' . $icon;
$alt = wfMessage( 'config-information' )->text();
return Html::infoBox( $text, $icon, $alt, $class, false );
}
/**
* Get small text indented help for a preceding form field.
* Parameters like wfMessage().
2011-05-02 16:58:29 +00:00
*
* @param string $msg
2011-05-02 16:58:29 +00:00
* @return string
*/
2010-07-19 03:16:54 +00:00
public function getHelpBox( $msg /*, ... */ ) {
$args = func_get_args();
array_shift( $args );
$args = array_map( 'htmlspecialchars', $args );
$text = wfMessage( $msg, $args )->useDatabase( false )->plain();
$html = $this->parse( $text, true );
2010-12-16 11:20:39 +00:00
return "<div class=\"mw-help-field-container\">\n" .
"<span class=\"mw-help-field-hint\" title=\"" .
wfMessage( 'config-help-tooltip' )->escaped() . "\">" .
wfMessage( 'config-help' )->escaped() . "</span>\n" .
"<span class=\"mw-help-field-data\">" . $html . "</span>\n" .
"</div>\n";
}
/**
2010-07-19 03:16:54 +00:00
* Output a help box.
* @param string $msg Key for wfMessage()
*/
2010-07-19 03:16:54 +00:00
public function showHelpBox( $msg /*, ... */ ) {
$args = func_get_args();
$html = call_user_func_array( array( $this, 'getHelpBox' ), $args );
$this->output->addHTML( $html );
}
/**
2010-07-19 03:16:54 +00:00
* Show a short informational message.
* Output looks like a list.
2010-10-02 07:40:54 +00:00
*
* @param string $msg
*/
2010-07-19 03:16:54 +00:00
public function showMessage( $msg /*, ... */ ) {
$args = func_get_args();
array_shift( $args );
$html = '<div class="config-message">' .
$this->parse( wfMessage( $msg, $args )->useDatabase( false )->plain() ) .
"</div>\n";
$this->output->addHTML( $html );
}
2010-10-02 07:40:54 +00:00
2010-07-29 17:54:44 +00:00
/**
* @param Status $status
2010-07-29 17:54:44 +00:00
*/
public function showStatusMessage( Status $status ) {
$errors = array_merge( $status->getErrorsArray(), $status->getWarningsArray() );
foreach ( $errors as $error ) {
call_user_func_array( array( $this, 'showMessage' ), $error );
}
2010-07-29 17:54:44 +00:00
}
/**
* Label a control by wrapping a config-input div around it and putting a
2010-07-19 03:16:54 +00:00
* label before it.
2011-05-02 16:58:29 +00:00
*
* @param string $msg
* @param string $forId
* @param string $contents
* @param string $helpData
2011-05-02 16:58:29 +00:00
* @return string
*/
public function label( $msg, $forId, $contents, $helpData = "" ) {
if ( strval( $msg ) == '' ) {
Remove most named character references from output Recommit of r66254 to trunk. This was just find extensions phase3 -iname '*.php' \! -iname '*.i18n.php' \! -iname 'Messages*.php' \! -iname '*_Messages.php' -exec sed -i 's/&nbsp;/\&#160;/g;s/&mdash;/―/g;s/&bull;/•/g;s/&aacute;/á/g;s/&acute;/´/g;s/&agrave;/à/g;s/&alpha;/α/g;s/&auml;/ä/g;s/&ccedil;/ç/g;s/&copy;/©/g;s/&darr;/↓/g;s/&deg;/°/g;s/&eacute;/é/g;s/&ecirc;/ê/g;s/&euml;/ë/g;s/&egrave;/è/g;s/&euro;/€/g;s/&harr;//g;s/&hellip;/…/g;s/&iacute;/í/g;s/&igrave;/ì/g;s/&larr;/←/g;s/&ldquo;/“/g;s/&middot;/·/g;s/&minus;/−/g;s/&ndash;/–/g;s/&oacute;/ó/g;s/&ocirc;/ô/g;s/&oelig;/œ/g;s/&ograve;/ò/g;s/&otilde;/õ/g;s/&ouml;/ö/g;s/&pound;/£/g;s/&prime;/′/g;s/&Prime;/″/g;s/&raquo;/»/g;s/&rarr;/→/g;s/&rdquo;/”/g;s/&Sigma;/Σ/g;s/&times;/×/g;s/&uacute;/ú/g;s/&uarr;/↑/g;s/&uuml;/ü/g;s/&yen;/¥/g' {} + followed by reading over every single line of the resulting diff and fixing a whole bunch of false positives. The reason for this change is given in <http://lists.wikimedia.org/pipermail/wikitech-l/2010-April/047617.html>. I cleared it with Tim and Brion on IRC before committing. It might cause a few problems, but I tried to be careful; please report any issues. I skipped all messages files. I plan to make a follow-up commit that alters wfMsgExt() with 'escapenoentities' to sanitize all the entities. That way, the only messages that will be problems will be ones that output raw HTML, and we want to get rid of those anyway. This should get rid of all named entities everywhere except messages. I skipped a few things like &nbsp that I noticed in manual inspection, because they weren't well-formed XML anyway. Also, to everyone who uses non-breaking spaces when they could use a normal space, or nothing at all, or CSS padding: I still hate you. Die.
2010-05-30 17:33:59 +00:00
$labelText = '&#160;';
} else {
$labelText = wfMessage( $msg )->escaped();
}
2010-10-02 07:40:54 +00:00
$attributes = array( 'class' => 'config-label' );
2010-10-02 07:40:54 +00:00
if ( $forId ) {
$attributes['for'] = $forId;
}
2010-10-02 07:40:54 +00:00
return "<div class=\"config-block\">\n" .
" <div class=\"config-block-label\">\n" .
Xml::tags( 'label',
$attributes,
$labelText
) . "\n" .
$helpData .
" </div>\n" .
" <div class=\"config-block-elements\">\n" .
$contents .
" </div>\n" .
"</div>\n";
}
/**
2010-07-19 03:16:54 +00:00
* Get a labelled text box to configure a variable.
2010-05-08 20:04:48 +00:00
*
* @param mixed[] $params
* Parameters are:
* var: The variable to be configured (required)
* label: The message name for the label (required)
* attribs: Additional attributes for the input element (optional)
* controlName: The name for the input element (optional)
* value: The current value of the variable (optional)
* help: The html for the help text (optional)
2011-05-02 16:58:29 +00:00
*
* @return string
*/
2010-07-19 03:16:54 +00:00
public function getTextBox( $params ) {
if ( !isset( $params['controlName'] ) ) {
$params['controlName'] = 'config_' . $params['var'];
}
2010-10-02 07:40:54 +00:00
if ( !isset( $params['value'] ) ) {
$params['value'] = $this->getVar( $params['var'] );
}
2010-10-02 07:40:54 +00:00
if ( !isset( $params['attribs'] ) ) {
$params['attribs'] = array();
}
if ( !isset( $params['help'] ) ) {
$params['help'] = "";
}
return $this->label(
$params['label'],
$params['controlName'],
Xml::input(
$params['controlName'],
30, // intended to be overridden by CSS
$params['value'],
$params['attribs'] + array(
'id' => $params['controlName'],
'class' => 'config-input-text',
'tabindex' => $this->nextTabIndex()
)
),
$params['help']
);
}
/**
* Get a labelled textarea to configure a variable
*
* @param mixed[] $params
* Parameters are:
* var: The variable to be configured (required)
* label: The message name for the label (required)
* attribs: Additional attributes for the input element (optional)
* controlName: The name for the input element (optional)
* value: The current value of the variable (optional)
* help: The html for the help text (optional)
2011-05-02 16:58:29 +00:00
*
* @return string
*/
public function getTextArea( $params ) {
if ( !isset( $params['controlName'] ) ) {
$params['controlName'] = 'config_' . $params['var'];
}
if ( !isset( $params['value'] ) ) {
$params['value'] = $this->getVar( $params['var'] );
}
if ( !isset( $params['attribs'] ) ) {
$params['attribs'] = array();
}
if ( !isset( $params['help'] ) ) {
$params['help'] = "";
}
return $this->label(
$params['label'],
$params['controlName'],
Xml::textarea(
$params['controlName'],
$params['value'],
30,
5,
$params['attribs'] + array(
'id' => $params['controlName'],
'class' => 'config-input-text',
'tabindex' => $this->nextTabIndex()
)
),
$params['help']
);
}
/**
2010-07-19 03:16:54 +00:00
* Get a labelled password box to configure a variable.
2010-05-08 20:04:48 +00:00
*
* Implements password hiding
* @param mixed[] $params
* Parameters are:
* var: The variable to be configured (required)
* label: The message name for the label (required)
* attribs: Additional attributes for the input element (optional)
* controlName: The name for the input element (optional)
* value: The current value of the variable (optional)
* help: The html for the help text (optional)
2011-05-02 16:58:29 +00:00
*
* @return string
*/
2010-07-19 03:16:54 +00:00
public function getPasswordBox( $params ) {
if ( !isset( $params['value'] ) ) {
$params['value'] = $this->getVar( $params['var'] );
}
2010-10-02 07:40:54 +00:00
if ( !isset( $params['attribs'] ) ) {
$params['attribs'] = array();
}
2010-10-02 07:40:54 +00:00
$params['value'] = $this->getFakePassword( $params['value'] );
$params['attribs']['type'] = 'password';
2010-10-02 07:40:54 +00:00
return $this->getTextBox( $params );
}
/**
2010-07-19 03:16:54 +00:00
* Get a labelled checkbox to configure a boolean variable.
2010-05-08 20:04:48 +00:00
*
* @param mixed[] $params
* Parameters are:
* var: The variable to be configured (required)
* label: The message name for the label (required)
* attribs: Additional attributes for the input element (optional)
* controlName: The name for the input element (optional)
* value: The current value of the variable (optional)
* help: The html for the help text (optional)
2011-05-02 16:58:29 +00:00
*
* @return string
*/
2010-07-19 03:16:54 +00:00
public function getCheckBox( $params ) {
if ( !isset( $params['controlName'] ) ) {
$params['controlName'] = 'config_' . $params['var'];
}
2010-10-02 07:40:54 +00:00
if ( !isset( $params['value'] ) ) {
$params['value'] = $this->getVar( $params['var'] );
}
2010-10-02 07:40:54 +00:00
if ( !isset( $params['attribs'] ) ) {
$params['attribs'] = array();
}
if ( !isset( $params['help'] ) ) {
$params['help'] = "";
}
if ( isset( $params['rawtext'] ) ) {
$labelText = $params['rawtext'];
} else {
$labelText = $this->parse( wfMessage( $params['label'] )->text() );
}
2010-10-02 07:40:54 +00:00
return "<div class=\"config-input-check\">\n" .
$params['help'] .
"<label>\n" .
Xml::check(
$params['controlName'],
$params['value'],
$params['attribs'] + array(
'id' => $params['controlName'],
'tabindex' => $this->nextTabIndex(),
)
) .
$labelText . "\n" .
"</label>\n" .
"</div>\n";
}
/**
2010-07-19 03:16:54 +00:00
* Get a set of labelled radio buttons.
*
* @param mixed[] $params
* Parameters are:
* var: The variable to be configured (required)
* label: The message name for the label (required)
* itemLabelPrefix: The message name prefix for the item labels (required)
* values: List of allowed values (required)
* itemAttribs: Array of attribute arrays, outer key is the value name (optional)
* commonAttribs: Attribute array applied to all items
* controlName: The name for the input element (optional)
* value: The current value of the variable (optional)
* help: The html for the help text (optional)
2011-05-02 16:58:29 +00:00
*
* @return string
*/
2010-07-19 03:16:54 +00:00
public function getRadioSet( $params ) {
if ( !isset( $params['controlName'] ) ) {
$params['controlName'] = 'config_' . $params['var'];
}
2010-10-02 07:40:54 +00:00
if ( !isset( $params['value'] ) ) {
$params['value'] = $this->getVar( $params['var'] );
}
2010-10-02 07:40:54 +00:00
if ( !isset( $params['label'] ) ) {
$label = '';
} else {
$label = $params['label'];
}
if ( !isset( $params['help'] ) ) {
$params['help'] = "";
}
$s = "<ul>\n";
foreach ( $params['values'] as $value ) {
$itemAttribs = array();
2010-10-02 07:40:54 +00:00
if ( isset( $params['commonAttribs'] ) ) {
$itemAttribs = $params['commonAttribs'];
}
2010-10-02 07:40:54 +00:00
if ( isset( $params['itemAttribs'][$value] ) ) {
$itemAttribs = $params['itemAttribs'][$value] + $itemAttribs;
}
2010-10-02 07:40:54 +00:00
$checked = $value == $params['value'];
$id = $params['controlName'] . '_' . $value;
$itemAttribs['id'] = $id;
$itemAttribs['tabindex'] = $this->nextTabIndex();
2010-10-02 07:40:54 +00:00
$s .=
'<li>' .
Xml::radio( $params['controlName'], $value, $checked, $itemAttribs ) .
Remove most named character references from output Recommit of r66254 to trunk. This was just find extensions phase3 -iname '*.php' \! -iname '*.i18n.php' \! -iname 'Messages*.php' \! -iname '*_Messages.php' -exec sed -i 's/&nbsp;/\&#160;/g;s/&mdash;/―/g;s/&bull;/•/g;s/&aacute;/á/g;s/&acute;/´/g;s/&agrave;/à/g;s/&alpha;/α/g;s/&auml;/ä/g;s/&ccedil;/ç/g;s/&copy;/©/g;s/&darr;/↓/g;s/&deg;/°/g;s/&eacute;/é/g;s/&ecirc;/ê/g;s/&euml;/ë/g;s/&egrave;/è/g;s/&euro;/€/g;s/&harr;//g;s/&hellip;/…/g;s/&iacute;/í/g;s/&igrave;/ì/g;s/&larr;/←/g;s/&ldquo;/“/g;s/&middot;/·/g;s/&minus;/−/g;s/&ndash;/–/g;s/&oacute;/ó/g;s/&ocirc;/ô/g;s/&oelig;/œ/g;s/&ograve;/ò/g;s/&otilde;/õ/g;s/&ouml;/ö/g;s/&pound;/£/g;s/&prime;/′/g;s/&Prime;/″/g;s/&raquo;/»/g;s/&rarr;/→/g;s/&rdquo;/”/g;s/&Sigma;/Σ/g;s/&times;/×/g;s/&uacute;/ú/g;s/&uarr;/↑/g;s/&uuml;/ü/g;s/&yen;/¥/g' {} + followed by reading over every single line of the resulting diff and fixing a whole bunch of false positives. The reason for this change is given in <http://lists.wikimedia.org/pipermail/wikitech-l/2010-April/047617.html>. I cleared it with Tim and Brion on IRC before committing. It might cause a few problems, but I tried to be careful; please report any issues. I skipped all messages files. I plan to make a follow-up commit that alters wfMsgExt() with 'escapenoentities' to sanitize all the entities. That way, the only messages that will be problems will be ones that output raw HTML, and we want to get rid of those anyway. This should get rid of all named entities everywhere except messages. I skipped a few things like &nbsp that I noticed in manual inspection, because they weren't well-formed XML anyway. Also, to everyone who uses non-breaking spaces when they could use a normal space, or nothing at all, or CSS padding: I still hate you. Die.
2010-05-30 17:33:59 +00:00
'&#160;' .
Xml::tags( 'label', array( 'for' => $id ), $this->parse(
wfMessage( $params['itemLabelPrefix'] . strtolower( $value ) )->plain()
) ) .
"</li>\n";
}
2010-10-02 07:40:54 +00:00
$s .= "</ul>\n";
return $this->label( $label, $params['controlName'], $s, $params['help'] );
}
/**
2010-07-19 03:16:54 +00:00
* Output an error or warning box using a Status object.
2011-05-28 14:52:55 +00:00
*
* @param Status $status
*/
2010-07-19 03:16:54 +00:00
public function showStatusBox( $status ) {
if ( !$status->isGood() ) {
$text = $status->getWikiText();
2010-10-02 07:40:54 +00:00
if ( $status->isOk() ) {
$box = $this->getWarningBox( $text );
} else {
$box = $this->getErrorBox( $text );
}
2010-10-02 07:40:54 +00:00
$this->output->addHTML( $box );
}
}
/**
* Convenience function to set variables based on form data.
* Assumes that variables containing "password" in the name are (potentially
* fake) passwords.
2010-05-08 20:04:48 +00:00
*
* @param string[] $varNames
* @param string $prefix The prefix added to variables to obtain form names
2011-05-02 16:58:29 +00:00
*
* @return string[]
*/
2010-07-19 03:16:54 +00:00
public function setVarsFromRequest( $varNames, $prefix = 'config_' ) {
$newValues = array();
2010-10-02 07:40:54 +00:00
foreach ( $varNames as $name ) {
$value = trim( $this->request->getVal( $prefix . $name ) );
$newValues[$name] = $value;
2010-10-02 07:40:54 +00:00
if ( $value === null ) {
// Checkbox?
$this->setVar( $name, false );
} else {
if ( stripos( $name, 'password' ) !== false ) {
$this->setPassword( $name, $value );
} else {
$this->setVar( $name, $value );
}
}
}
2010-10-02 07:40:54 +00:00
return $newValues;
}
/**
* Helper for Installer::docLink()
2011-05-02 16:58:29 +00:00
*
* @param string $page
*
2011-05-02 16:58:29 +00:00
* @return string
*/
protected function getDocUrl( $page ) {
$url = "{$_SERVER['PHP_SELF']}?page=" . urlencode( $page );
2010-10-02 07:40:54 +00:00
if ( in_array( $this->currentPageName, $this->pageSequence ) ) {
$url .= '&lastPage=' . urlencode( $this->currentPageName );
}
2010-10-02 07:40:54 +00:00
return $url;
}
2010-10-02 07:40:54 +00:00
2011-03-20 17:54:43 +00:00
/**
* Extension tag hook for a documentation link.
2011-05-02 16:58:29 +00:00
*
* @param string $linkText
* @param string[] $attribs
* @param Parser $parser Unused
*
2011-05-02 16:58:29 +00:00
* @return string
2011-03-20 17:54:43 +00:00
*/
public function docLink( $linkText, $attribs, $parser ) {
$url = $this->getDocUrl( $attribs['href'] );
2011-03-20 17:54:43 +00:00
return '<a href="' . htmlspecialchars( $url ) . '">' .
htmlspecialchars( $linkText ) .
'</a>';
}
2011-05-20 18:20:16 +00:00
2011-01-28 15:00:18 +00:00
/**
* Helper for "Download LocalSettings" link on WebInstall_Complete
2011-05-20 18:20:16 +00:00
*
* @param string $text Unused
* @param string[] $attribs Unused
* @param Parser $parser Unused
*
* @return string Html for download link
2011-01-28 15:00:18 +00:00
*/
public function downloadLinkHook( $text, $attribs, $parser ) {
2010-12-16 11:20:39 +00:00
$anchor = Html::rawElement( 'a',
array( 'href' => $this->getURL( array( 'localsettings' => 1 ) ) ),
wfMessage( 'config-download-localsettings' )->parse()
);
return Html::rawElement( 'div', array( 'class' => 'config-download-link' ), $anchor );
}
2011-11-22 16:31:33 +00:00
/**
* @return bool
*/
public function envCheckPath() {
// PHP_SELF isn't available sometimes, such as when PHP is CGI but
// cgi.fix_pathinfo is disabled. In that case, fall back to SCRIPT_NAME
// to get the path to the current script... hopefully it's reliable. SIGH
$path = false;
if ( !empty( $_SERVER['PHP_SELF'] ) ) {
$path = $_SERVER['PHP_SELF'];
} elseif ( !empty( $_SERVER['SCRIPT_NAME'] ) ) {
$path = $_SERVER['SCRIPT_NAME'];
}
if ( $path !== false ) {
$uri = preg_replace( '{^(.*)/(mw-)?config.*$}', '$1', $path );
$this->setVar( 'wgScriptPath', $uri );
} else {
$this->showError( 'config-no-uri' );
return false;
}
return parent::envCheckPath();
}
/**
* @return string
*/
protected function envGetDefaultServer() {
return WebRequest::detectServer();
}
/**
* Output stylesheet for web installer pages
*/
public function outputCss() {
$this->request->response()->header( 'Content-type: text/css' );
echo $this->output->getCSS();
}
/**
* @return string[]
*/
public function getPhpErrors() {
return $this->phpErrors;
}
}