Index: branches/new-installer/phase3/includes/installer/WebInstaller.php |
— | — | @@ -0,0 +1,818 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class WebInstaller extends Installer { |
| 5 | + /** WebRequest object */ |
| 6 | + var $request; |
| 7 | + |
| 8 | + /** Cached session array */ |
| 9 | + var $session; |
| 10 | + |
| 11 | + /** Captured PHP error text. Temporary. |
| 12 | + */ |
| 13 | + var $phpErrors; |
| 14 | + |
| 15 | + /** |
| 16 | + * The main sequence of page names. These will be displayed in turn. |
| 17 | + * To add one: |
| 18 | + * * Add it here |
| 19 | + * * Add a config-page-<name> message |
| 20 | + * * Add a WebInstaller_<name> class |
| 21 | + */ |
| 22 | + var $pageSequence = array( |
| 23 | + 'Language', |
| 24 | + 'Environment', |
| 25 | + 'DBConnect', |
| 26 | + 'Upgrade', |
| 27 | + 'DBSettings', |
| 28 | + 'Identity', |
| 29 | + 'License', |
| 30 | + 'Email', |
| 31 | + 'Install', |
| 32 | + 'Complete', |
| 33 | + ); |
| 34 | + |
| 35 | + /** |
| 36 | + * Out of sequence pages, selectable by the user at any time |
| 37 | + */ |
| 38 | + var $otherPages = array( |
| 39 | + 'Restart', |
| 40 | + ); |
| 41 | + |
| 42 | + /** |
| 43 | + * Array of pages which have declared that they have been submitted, have validated |
| 44 | + * their input, and need no further processing |
| 45 | + */ |
| 46 | + var $happyPages; |
| 47 | + |
| 48 | + /** |
| 49 | + * List of "skipped" pages. These are pages that will automatically continue |
| 50 | + * to the next page on any GET request. To avoid breaking the "back" button, |
| 51 | + * they need to be skipped during a back operation. |
| 52 | + */ |
| 53 | + var $skippedPages; |
| 54 | + |
| 55 | + /** |
| 56 | + * Flag indicating that session data may have been lost |
| 57 | + */ |
| 58 | + var $showSessionWarning = false; |
| 59 | + |
| 60 | + /** Constructor */ |
| 61 | + function __construct( $request ) { |
| 62 | + parent::__construct(); |
| 63 | + $this->output = new WebInstallerOutput( $this ); |
| 64 | + $this->request = $request; |
| 65 | + $this->internalDefaults['_UserLang'] = 'en'; |
| 66 | + } |
| 67 | + |
| 68 | + /** |
| 69 | + * Main entry point. |
| 70 | + * @param array $session Initial session array |
| 71 | + * @return array New session array |
| 72 | + */ |
| 73 | + function execute( $session ) { |
| 74 | + $this->session = $session; |
| 75 | + if ( isset( $session['settings'] ) ) { |
| 76 | + $this->settings = $session['settings'] + $this->settings; |
| 77 | + } |
| 78 | + if ( isset( $session['happyPages'] ) ) { |
| 79 | + $this->happyPages = $session['happyPages']; |
| 80 | + } else { |
| 81 | + $this->happyPages = array(); |
| 82 | + } |
| 83 | + if ( isset( $session['skippedPages'] ) ) { |
| 84 | + $this->skippedPages = $session['skippedPages']; |
| 85 | + } else { |
| 86 | + $this->skippedPages = array(); |
| 87 | + } |
| 88 | + $lowestUnhappy = $this->getLowestUnhappy(); |
| 89 | + |
| 90 | + |
| 91 | + # Get the page name |
| 92 | + $pageName = $this->request->getVal( 'page' ); |
| 93 | + |
| 94 | + if ( in_array( $pageName, $this->otherPages ) ) { |
| 95 | + # Out of sequence |
| 96 | + $pageId = false; |
| 97 | + $page = $this->getPageByName( $pageName ); |
| 98 | + } else { |
| 99 | + # Main sequence |
| 100 | + if ( !$pageName || !in_array( $pageName, $this->pageSequence ) ) { |
| 101 | + $pageId = $lowestUnhappy; |
| 102 | + } else { |
| 103 | + $pageId = array_search( $pageName, $this->pageSequence ); |
| 104 | + } |
| 105 | + |
| 106 | + # If necessary, move back to the lowest-numbered unhappy page |
| 107 | + if ( $pageId > $lowestUnhappy ) { |
| 108 | + $pageId = $lowestUnhappy; |
| 109 | + if ( $lowestUnhappy == 0 ) { |
| 110 | + # Knocked back to start, possible loss of session data |
| 111 | + $this->showSessionWarning = true; |
| 112 | + } |
| 113 | + } |
| 114 | + $pageName = $this->pageSequence[$pageId]; |
| 115 | + $page = $this->getPageByName( $pageName ); |
| 116 | + } |
| 117 | + |
| 118 | + # If a back button was submitted, go back without submitting the form data |
| 119 | + if ( $this->request->wasPosted() && $this->request->getBool( 'submit-back' ) ) { |
| 120 | + if ( $this->request->getVal( 'lastPage' ) ) { |
| 121 | + $nextPage = $this->request->getVal( 'lastPage' ); |
| 122 | + } elseif ( $pageId !== false ) { |
| 123 | + # Main sequence page |
| 124 | + # Skip the skipped pages |
| 125 | + $nextPageId = $pageId; |
| 126 | + do { |
| 127 | + $nextPageId--; |
| 128 | + $nextPage = $this->pageSequence[$nextPageId]; |
| 129 | + } while( isset( $this->skippedPages[$nextPage] ) ); |
| 130 | + } else { |
| 131 | + $nextPage = $this->pageSequence[$lowestUnhappy]; |
| 132 | + } |
| 133 | + $this->output->redirect( $this->getUrl( array( 'page' => $nextPage ) ) ); |
| 134 | + return $this->finish(); |
| 135 | + } |
| 136 | + |
| 137 | + # Execute the page |
| 138 | + $this->startPageWrapper( $pageName ); |
| 139 | + $result = $page->execute(); |
| 140 | + $this->endPageWrapper(); |
| 141 | + |
| 142 | + if ( $result == 'skip' ) { |
| 143 | + # Page skipped without explicit submission |
| 144 | + # Skip it when we click "back" so that we don't just go forward again |
| 145 | + $this->skippedPages[$pageName] = true; |
| 146 | + $result = 'continue'; |
| 147 | + } else { |
| 148 | + unset( $this->skippedPages[$pageName] ); |
| 149 | + } |
| 150 | + |
| 151 | + # If it was posted, the page can request a continue to the next page |
| 152 | + if ( $result === 'continue' ) { |
| 153 | + if ( $pageId !== false ) { |
| 154 | + $this->happyPages[$pageId] = true; |
| 155 | + } |
| 156 | + $lowestUnhappy = $this->getLowestUnhappy(); |
| 157 | + |
| 158 | + if ( $this->request->getVal( 'lastPage' ) ) { |
| 159 | + $nextPage = $this->request->getVal( 'lastPage' ); |
| 160 | + } elseif ( $pageId !== false ) { |
| 161 | + $nextPage = $this->pageSequence[$pageId + 1]; |
| 162 | + } else { |
| 163 | + $nextPage = $this->pageSequence[$lowestUnhappy]; |
| 164 | + } |
| 165 | + if ( array_search( $nextPage, $this->pageSequence ) > $lowestUnhappy ) { |
| 166 | + $nextPage = $this->pageSequence[$lowestUnhappy]; |
| 167 | + } |
| 168 | + $this->output->redirect( $this->getUrl( array( 'page' => $nextPage ) ) ); |
| 169 | + } |
| 170 | + return $this->finish(); |
| 171 | + } |
| 172 | + |
| 173 | + function getLowestUnhappy() { |
| 174 | + if ( count( $this->happyPages ) == 0 ) { |
| 175 | + return 0; |
| 176 | + } else { |
| 177 | + return max( array_keys( $this->happyPages ) ) + 1; |
| 178 | + } |
| 179 | + } |
| 180 | + |
| 181 | + /** |
| 182 | + * Start the PHP session. This may be called before execute() to start the PHP session. |
| 183 | + */ |
| 184 | + function startSession() { |
| 185 | + if( wfIniGetBool( 'session.auto_start' ) || session_id() ) { |
| 186 | + // Done already |
| 187 | + return true; |
| 188 | + } |
| 189 | + |
| 190 | + $this->phpErrors = array(); |
| 191 | + set_error_handler( array( $this, 'errorHandler' ) ); |
| 192 | + session_start(); |
| 193 | + restore_error_handler(); |
| 194 | + if ( $this->phpErrors ) { |
| 195 | + $this->showError( 'config-session-error', $this->phpErrors[0] ); |
| 196 | + return false; |
| 197 | + } |
| 198 | + return true; |
| 199 | + } |
| 200 | + |
| 201 | + /** |
| 202 | + * Show an error message in a box. Parameters are like wfMsg(). |
| 203 | + */ |
| 204 | + function showError( $msg /*...*/ ) { |
| 205 | + $args = func_get_args(); |
| 206 | + array_shift( $args ); |
| 207 | + $args = array_map( 'htmlspecialchars', $args ); |
| 208 | + $msg = wfMsgReal( $msg, $args ); |
| 209 | + $this->output->addHTML( "<div class=\"config-error-top\">\n$msg\n</div>\n" ); |
| 210 | + } |
| 211 | + |
| 212 | + /** |
| 213 | + * Temporary error handler for session start debugging |
| 214 | + */ |
| 215 | + function errorHandler( $errno, $errstr ) { |
| 216 | + $this->phpErrors[] = $errstr; |
| 217 | + } |
| 218 | + |
| 219 | + /** |
| 220 | + * Clean up from execute() |
| 221 | + * @private. |
| 222 | + */ |
| 223 | + function finish() { |
| 224 | + $this->output->output(); |
| 225 | + $this->session['happyPages'] = $this->happyPages; |
| 226 | + $this->session['skippedPages'] = $this->skippedPages; |
| 227 | + $this->session['settings'] = $this->settings; |
| 228 | + return $this->session; |
| 229 | + } |
| 230 | + |
| 231 | + /** |
| 232 | + * Get a URL for submission back to the same script |
| 233 | + */ |
| 234 | + function getUrl( $query = array() ) { |
| 235 | + $url = $this->request->getRequestURL(); |
| 236 | + # Remove existing query |
| 237 | + $url = preg_replace( '/\?.*$/', '', $url ); |
| 238 | + if ( $query ) { |
| 239 | + $url .= '?' . wfArrayToCGI( $query ); |
| 240 | + } |
| 241 | + return $url; |
| 242 | + } |
| 243 | + |
| 244 | + /** |
| 245 | + * Get a WebInstallerPage from the main sequence, by ID |
| 246 | + */ |
| 247 | + function getPageById( $id ) { |
| 248 | + $pageName = $this->pageSequence[$id]; |
| 249 | + $pageClass = 'WebInstaller_' . $pageName; |
| 250 | + return new $pageClass( $this ); |
| 251 | + } |
| 252 | + |
| 253 | + /** |
| 254 | + * Get a WebInstallerPage by name |
| 255 | + */ |
| 256 | + function getPageByName( $pageName ) { |
| 257 | + $pageClass = 'WebInstaller_' . $pageName; |
| 258 | + return new $pageClass( $this ); |
| 259 | + } |
| 260 | + |
| 261 | + /** |
| 262 | + * Get a session variable |
| 263 | + */ |
| 264 | + function getSession( $name, $default = null ) { |
| 265 | + if ( !isset( $this->session[$name] ) ) { |
| 266 | + return $default; |
| 267 | + } else { |
| 268 | + return $this->session[$name]; |
| 269 | + } |
| 270 | + } |
| 271 | + |
| 272 | + /** |
| 273 | + * Set a session variable |
| 274 | + */ |
| 275 | + function setSession( $name, $value ) { |
| 276 | + $this->session[$name] = $value; |
| 277 | + } |
| 278 | + |
| 279 | + /** |
| 280 | + * Called by execute() before page output starts, to show a page list |
| 281 | + */ |
| 282 | + function startPageWrapper( $currentPageName ) { |
| 283 | + $s = "<div class=\"config-page-wrapper\">\n" . |
| 284 | + "<div class=\"config-page-list\"><ul>\n"; |
| 285 | + $lastHappy = -1; |
| 286 | + foreach ( $this->pageSequence as $id => $pageName ) { |
| 287 | + $happy = !empty( $this->happyPages[$id] ); |
| 288 | + $s .= $this->getPageListItem( $pageName, |
| 289 | + $happy || $lastHappy == $id - 1, $currentPageName ); |
| 290 | + if ( $happy ) { |
| 291 | + $lastHappy = $id; |
| 292 | + } |
| 293 | + } |
| 294 | + $s .= "</ul><br/><ul>\n"; |
| 295 | + foreach ( $this->otherPages as $pageName ) { |
| 296 | + $s .= $this->getPageListItem( $pageName, true, $currentPageName ); |
| 297 | + } |
| 298 | + $s .= "</ul></div>\n". // end list pane |
| 299 | + "<div class=\"config-page\">\n" . |
| 300 | + Xml::element( 'h2', array(), |
| 301 | + wfMsg( 'config-page-' . strtolower( $currentPageName ) ) ); |
| 302 | + |
| 303 | + $this->output->addHTMLNoFlush( $s ); |
| 304 | + } |
| 305 | + |
| 306 | + /** |
| 307 | + * Get a list item for the page list |
| 308 | + */ |
| 309 | + function getPageListItem( $pageName, $enabled, $currentPageName ) { |
| 310 | + $s = "<li class=\"config-page-list-item\">"; |
| 311 | + $name = wfMsg( 'config-page-' . strtolower( $pageName ) ); |
| 312 | + if ( $enabled ) { |
| 313 | + $query = array( 'page' => $pageName ); |
| 314 | + if ( !in_array( $pageName, $this->pageSequence ) ) { |
| 315 | + $query['lastPage'] = $currentPageName; |
| 316 | + $link = Xml::element( 'a', |
| 317 | + array( |
| 318 | + 'href' => $this->getUrl( $query ) |
| 319 | + ), |
| 320 | + $name |
| 321 | + ); |
| 322 | + } else { |
| 323 | + $link = htmlspecialchars( $name ); |
| 324 | + } |
| 325 | + if ( $pageName == $currentPageName ) { |
| 326 | + $s .= "<span class=\"config-page-current\">$link</span>"; |
| 327 | + } else { |
| 328 | + $s .= $link; |
| 329 | + } |
| 330 | + } else { |
| 331 | + $s .= Xml::element( 'span', |
| 332 | + array( |
| 333 | + 'class' => 'config-page-disabled' |
| 334 | + ), |
| 335 | + $name |
| 336 | + ); |
| 337 | + } |
| 338 | + $s .= "</li>\n"; |
| 339 | + return $s; |
| 340 | + } |
| 341 | + |
| 342 | + /** |
| 343 | + * Output some stuff after a page is finished |
| 344 | + */ |
| 345 | + function endPageWrapper() { |
| 346 | + $this->output->addHTMLNoFlush( |
| 347 | + "</div>\n" . |
| 348 | + "<br clear=\"left\"/>\n" . |
| 349 | + "</div>" ); |
| 350 | + } |
| 351 | + |
| 352 | + /** |
| 353 | + * Get HTML for a warning box with an icon |
| 354 | + */ |
| 355 | + function getWarningBox( $msg ) { |
| 356 | + return $this->getInfoBox( $msg, 'warning-32.png' ); |
| 357 | + } |
| 358 | + |
| 359 | + /** |
| 360 | + * Get HTML for an info box with an icon |
| 361 | + */ |
| 362 | + function getInfoBox( $msg, $icon = 'info-32.png' ) { |
| 363 | + if ( is_array( $msg ) ) { |
| 364 | + $args = $msg; |
| 365 | + $msg = array_shift( $args ); |
| 366 | + $text = wfMsgReal( $msg, $args, false, false, false ); |
| 367 | + } else { |
| 368 | + $text = wfMsgNoTrans( $msg ); |
| 369 | + } |
| 370 | + $s = "<div class=\"config-info\">\n" . |
| 371 | + "<div class=\"config-info-left\">\n" . |
| 372 | + Xml::element( 'img', |
| 373 | + array( |
| 374 | + 'src' => '../skins/common/images/' . $icon |
| 375 | + ) |
| 376 | + ) . "\n" . |
| 377 | + "</div>\n" . |
| 378 | + "<div class=\"config-info-right\">\n" . |
| 379 | + $this->parse( $text ) . |
| 380 | + "</div></div>\n"; |
| 381 | + return $s; |
| 382 | + } |
| 383 | + |
| 384 | + /** |
| 385 | + * Get small text indented help for a preceding form field. |
| 386 | + * Parameters like wfMsg(). |
| 387 | + */ |
| 388 | + function getHelpBox( $msg /*, ... */ ) { |
| 389 | + $args = func_get_args(); |
| 390 | + array_shift( $args ); |
| 391 | + $args = array_map( 'htmlspecialchars', $args ); |
| 392 | + return "<div class=\"config-desc\">\n" . |
| 393 | + $this->parse( wfMsgReal( $msg, $args, false, false, false ) ) . |
| 394 | + "</div>\n"; |
| 395 | + } |
| 396 | + |
| 397 | + /** |
| 398 | + * Output a help box |
| 399 | + */ |
| 400 | + function showHelpBox( $msg /*, ... */ ) { |
| 401 | + $args = func_get_args(); |
| 402 | + $html = call_user_func_array( array( $this, 'getHelpBox' ), $args ); |
| 403 | + $this->output->addHTML( $html ); |
| 404 | + } |
| 405 | + |
| 406 | + /** |
| 407 | + * Show a short informational message |
| 408 | + * Output looks like a list. |
| 409 | + */ |
| 410 | + function showMessage( $msg /*, ... */ ) { |
| 411 | + $args = func_get_args(); |
| 412 | + array_shift( $args ); |
| 413 | + $html = '<div class="config-message">' . |
| 414 | + $this->parse( wfMsgReal( $msg, $args, false, false, false ) ) . |
| 415 | + "</div>\n"; |
| 416 | + $this->output->addHTML( $html ); |
| 417 | + } |
| 418 | + |
| 419 | + /** |
| 420 | + * Get a label element using a message name |
| 421 | + */ |
| 422 | + function getLabel( $msg, $for ) { |
| 423 | + return Xml::element( 'label', |
| 424 | + array( 'for' => $for, 'class' => 'config-label' ), |
| 425 | + wfMsg( $msg ) ) . "\n"; |
| 426 | + } |
| 427 | + |
| 428 | + /** |
| 429 | + * Get a text box |
| 430 | + */ |
| 431 | + function getTextBox( $name, $value = '', $type = 'text' ) { |
| 432 | + return Xml::element( 'input', |
| 433 | + array( |
| 434 | + 'type' => $type, |
| 435 | + 'name' => $name, |
| 436 | + 'id' => $name, |
| 437 | + 'value' => $value, |
| 438 | + 'class' => 'config-input-text', |
| 439 | + ) |
| 440 | + ); |
| 441 | + } |
| 442 | + |
| 443 | + /** |
| 444 | + * Get a checkbox |
| 445 | + */ |
| 446 | + function getCheckBox( $name, $value, $attribs ) { |
| 447 | + return Xml::element( 'input', |
| 448 | + $attribs + array( |
| 449 | + 'type' => 'checkbox', |
| 450 | + 'name' => $name, |
| 451 | + 'id' => $name, |
| 452 | + 'checked' => $value ? '1' : '', |
| 453 | + 'class' => 'config-input-text', |
| 454 | + ) |
| 455 | + ); |
| 456 | + } |
| 457 | + |
| 458 | + /** |
| 459 | + * Output an error box using a Status object |
| 460 | + */ |
| 461 | + function showStatusErrorBox( $status ) { |
| 462 | + $text = $status->getWikiText(); |
| 463 | + $this->parent->output->addWikiText( |
| 464 | + "<div class=\"config-error-top\">\n" . |
| 465 | + $text . |
| 466 | + "</div>" |
| 467 | + ); |
| 468 | + } |
| 469 | + |
| 470 | + function showStatusError( $status ) { |
| 471 | + $text = $status->getWikiText(); |
| 472 | + $this->parent->output->addWikiText( |
| 473 | + "<div class=\"config-message\">\n" . |
| 474 | + $text . |
| 475 | + "</div>" |
| 476 | + ); |
| 477 | + } |
| 478 | +} |
| 479 | + |
| 480 | +class WebInstallerPage { |
| 481 | + function __construct( $parent ) { |
| 482 | + $this->parent = $parent; |
| 483 | + } |
| 484 | + |
| 485 | + function startForm() { |
| 486 | + $this->parent->output->addHTML( |
| 487 | + "<div class=\"config-section\">\n" . |
| 488 | + Xml::openElement( |
| 489 | + 'form', |
| 490 | + array( |
| 491 | + 'method' => 'post', |
| 492 | + 'action' => $this->parent->getUrl( array( 'page' => $this->getName() ) ) |
| 493 | + ) |
| 494 | + ) . "\n" |
| 495 | + ); |
| 496 | + } |
| 497 | + |
| 498 | + function endForm( $continue = 'continue' ) { |
| 499 | + $s = "<div class=\"config-submit\">\n"; |
| 500 | + $id = $this->getId(); |
| 501 | + if ( $id === false ) { |
| 502 | + $s .= Xml::hidden( 'lastPage', $this->parent->request->getVal( 'lastPage' ) ); |
| 503 | + } |
| 504 | + if ( $continue ) { |
| 505 | + // Fake submit button for enter keypress |
| 506 | + $s .= Xml::submitButton( wfMsg( "config-$continue" ), |
| 507 | + array( 'name' => "enter-$continue", 'style' => 'display:none' ) ); |
| 508 | + } |
| 509 | + if ( $id !== 0 ) { |
| 510 | + $s .= Xml::submitButton( wfMsg( 'config-back' ), array( 'name' => 'submit-back' ) ); |
| 511 | + } |
| 512 | + if ( $continue ) { |
| 513 | + $s .= Xml::submitButton( wfMsg( "config-$continue" ), |
| 514 | + array( 'name' => "submit-$continue" ) ); |
| 515 | + } |
| 516 | + $s .= "</div></form></div>\n"; |
| 517 | + $this->parent->output->addHTML( $s ); |
| 518 | + } |
| 519 | + |
| 520 | + function getName() { |
| 521 | + return str_replace( 'WebInstaller_', '', get_class( $this ) ); |
| 522 | + } |
| 523 | + |
| 524 | + function getId() { |
| 525 | + return array_search( $this->getName(), $this->parent->pageSequence ); |
| 526 | + } |
| 527 | + |
| 528 | + function execute() { |
| 529 | + if ( $this->parent->request->wasPosted() ) { |
| 530 | + return 'continue'; |
| 531 | + } else { |
| 532 | + $this->startForm(); |
| 533 | + $this->parent->output->addHTML( 'Mockup' ); |
| 534 | + $this->endForm(); |
| 535 | + } |
| 536 | + } |
| 537 | +} |
| 538 | + |
| 539 | +class WebInstaller_Language extends WebInstallerPage { |
| 540 | + function execute() { |
| 541 | + global $wgLang; |
| 542 | + $r = $this->parent->request; |
| 543 | + $userLang = $r->getVal( 'UserLang' ); |
| 544 | + $contLang = $r->getVal( 'ContLang' ); |
| 545 | + |
| 546 | + if ( $r->wasPosted() ) { |
| 547 | + # Do session test |
| 548 | + if ( $this->parent->getSession( 'test' ) === null ) { |
| 549 | + $requestTime = $r->getVal( 'LanguageRequestTime' ); |
| 550 | + $lifetime = intval( ini_get( 'session.gc_maxlifetime' ) ); |
| 551 | + if ( !$lifetime ) { |
| 552 | + $lifetime = 1440; |
| 553 | + } |
| 554 | + if ( !$requestTime ) { |
| 555 | + // The most likely explanation is that the user was knocked back |
| 556 | + // from another page on POST due to session expiry |
| 557 | + $msg = 'config-session-expired'; |
| 558 | + } elseif ( time() - $requestTime > $lifetime ) { |
| 559 | + $msg = 'config-session-expired'; |
| 560 | + } else { |
| 561 | + $msg = 'config-no-session'; |
| 562 | + } |
| 563 | + $this->parent->showError( $msg, $wgLang->formatTimePeriod( $lifetime ) ); |
| 564 | + } else { |
| 565 | + $languages = Language::getLanguageNames(); |
| 566 | + if ( isset( $languages[$userLang] ) ) { |
| 567 | + $this->parent->setVar( '_UserLang', $userLang ); |
| 568 | + } |
| 569 | + if ( isset( $languages[$contLang] ) ) { |
| 570 | + $this->parent->setVar( 'wgLanguageCode', $contLang ); |
| 571 | + } |
| 572 | + return 'continue'; |
| 573 | + } |
| 574 | + } elseif ( $this->parent->showSessionWarning ) { |
| 575 | + # The user was knocked back from another page to the start |
| 576 | + # This probably indicates a session expiry |
| 577 | + $this->parent->showError( 'config-session-expired' ); |
| 578 | + } |
| 579 | + |
| 580 | + $this->parent->setSession( 'test', true ); |
| 581 | + |
| 582 | + if ( !isset( $languages[$userLang] ) ) { |
| 583 | + $userLang = $this->parent->getVar( '_UserLang', 'en' ); |
| 584 | + } |
| 585 | + if ( !isset( $languages[$contLang] ) ) { |
| 586 | + $contLang = $this->parent->getVar( 'wgLanguageCode', 'en' ); |
| 587 | + } |
| 588 | + $this->startForm(); |
| 589 | + $s = |
| 590 | + Xml::hidden( 'LanguageRequestTime', time() ) . |
| 591 | + $this->getLanguageSelector( 'UserLang', 'config-your-language', $userLang ) . |
| 592 | + $this->parent->getHelpBox( 'config-your-language-help' ) . |
| 593 | + $this->getLanguageSelector( 'ContLang', 'config-wiki-language', $contLang ) . |
| 594 | + $this->parent->getHelpBox( 'config-wiki-language-help' ); |
| 595 | + |
| 596 | + |
| 597 | + $this->parent->output->addHTML( $s ); |
| 598 | + $this->endForm(); |
| 599 | + } |
| 600 | + |
| 601 | + /** |
| 602 | + * Get a <select> for selecting languages |
| 603 | + */ |
| 604 | + function getLanguageSelector( $name, $label, $selectedCode ) { |
| 605 | + $s = "<div class=\"config-input\">\n" . |
| 606 | + $this->parent->getLabel( $label, $name ) . |
| 607 | + Xml::openElement( 'select', array( 'id' => $name, 'name' => $name ) ) . "\n"; |
| 608 | + |
| 609 | + $languages = Language::getLanguageNames(); |
| 610 | + ksort( $languages ); |
| 611 | + foreach ( $languages as $code => $name ) { |
| 612 | + $s .= "\n" . Xml::option( "$code - $name", $code, $code == $selectedCode ); |
| 613 | + } |
| 614 | + $s .= "\n</select>\n</div>\n"; |
| 615 | + return $s; |
| 616 | + } |
| 617 | + |
| 618 | +} |
| 619 | + |
| 620 | +class WebInstaller_Environment extends WebInstallerPage { |
| 621 | + function execute() { |
| 622 | + if ( $this->parent->request->wasPosted() ) { |
| 623 | + if ( $this->parent->getVar( '_Environment' ) ) { |
| 624 | + return 'continue'; |
| 625 | + } |
| 626 | + } |
| 627 | + $status = $this->parent->doEnvironmentChecks(); |
| 628 | + if ( $status ) { |
| 629 | + $this->startForm(); |
| 630 | + $this->endForm(); |
| 631 | + } |
| 632 | + } |
| 633 | +} |
| 634 | + |
| 635 | +class WebInstaller_DBConnect extends WebInstallerPage { |
| 636 | + function execute() { |
| 637 | + $r = $this->parent->request; |
| 638 | + if ( $this->parent->request->wasPosted() ) { |
| 639 | + $status = $this->submit(); |
| 640 | + if ( $status->isGood() ) { |
| 641 | + $this->parent->setVar( '_UpgradeDone', false ); |
| 642 | + return 'continue'; |
| 643 | + } else { |
| 644 | + $error = $status->getWikiText(); |
| 645 | + $this->parent->output->addWikiText( |
| 646 | + "<div class=\"config-error-top\">\n" . |
| 647 | + $error . |
| 648 | + "</div>" |
| 649 | + ); |
| 650 | + } |
| 651 | + } |
| 652 | + |
| 653 | + |
| 654 | + $this->startForm(); |
| 655 | + |
| 656 | + $types = "<label class=\"config-label\">" . |
| 657 | + wfMsg( 'config-db-type' ) . |
| 658 | + "</label>" . |
| 659 | + "<ul class=\"config-settings-block\">\n"; |
| 660 | + $settings = ''; |
| 661 | + $defaultType = $this->parent->getVar( 'wgDBtype' ); |
| 662 | + foreach ( $this->parent->getDBTypes() as $type ) { |
| 663 | + $installer = $this->parent->getDBInstaller( $type ); |
| 664 | + $encType = Xml::encodeJsVar( $type ); |
| 665 | + $types .= |
| 666 | + '<li>' . |
| 667 | + Xml::radioLabel( |
| 668 | + $installer->getReadableName(), |
| 669 | + 'DBType', |
| 670 | + $type, |
| 671 | + 'DBType_' . $type, |
| 672 | + $type == $defaultType, |
| 673 | + array( 'onclick' => "showDBArea($encType);" ) |
| 674 | + ) . |
| 675 | + "</li>\n"; |
| 676 | + |
| 677 | + $settings .= |
| 678 | + Xml::openElement( 'div', array( 'id' => 'DB_wrapper_' . $type ) ) . |
| 679 | + Xml::element( 'h3', array(), wfMsg( 'config-header-' . $type ) ) . |
| 680 | + $installer->getConnectForm() . |
| 681 | + "</div>\n"; |
| 682 | + } |
| 683 | + $types .= "</ul><br clear=\"left\"/>\n"; |
| 684 | + $encType = Xml::encodeJsVar( $defaultType ); |
| 685 | + |
| 686 | + $this->parent->output->addHTML( |
| 687 | + $types . |
| 688 | + $settings . |
| 689 | + "<script>resetDBArea();</script>\n" |
| 690 | + ); |
| 691 | + |
| 692 | + $this->endForm(); |
| 693 | + } |
| 694 | + |
| 695 | + function submit() { |
| 696 | + $r = $this->parent->request; |
| 697 | + $type = $r->getVal( 'DBType' ); |
| 698 | + $this->parent->setVar( 'wgDBtype', $type ); |
| 699 | + $installer = $this->parent->getDBInstaller( $type ); |
| 700 | + if ( !$installer ) { |
| 701 | + return Status::newFatal( 'config-invalid-db-type' ); |
| 702 | + } |
| 703 | + return $installer->submitConnectForm(); |
| 704 | + } |
| 705 | +} |
| 706 | + |
| 707 | +class WebInstaller_Upgrade extends WebInstallerPage { |
| 708 | + function execute() { |
| 709 | + if ( $this->parent->getVar( '_UpgradeDone' ) ) { |
| 710 | + if ( $this->parent->request->wasPosted() ) { |
| 711 | + // Done message acknowledged |
| 712 | + return 'continue'; |
| 713 | + } else { |
| 714 | + // Back button click |
| 715 | + // Show the done message again |
| 716 | + // Make them click back again if they want to do the upgrade again |
| 717 | + $this->showDoneMessage(); |
| 718 | + return 'output'; |
| 719 | + } |
| 720 | + } |
| 721 | + |
| 722 | + // wgDBtype is generally valid here because otherwise the previous page |
| 723 | + // (connect) wouldn't have declared its happiness |
| 724 | + $type = $this->parent->getVar( 'wgDBtype' ); |
| 725 | + $installer = $this->parent->getDBInstaller( $type ); |
| 726 | + |
| 727 | + // There's no guarantee the connection will still succeed though |
| 728 | + $conn = $installer->getConnection(); |
| 729 | + if ( $conn instanceof Status ) { |
| 730 | + $this->startForm(); |
| 731 | + $this->showStatusErrorBox( $conn ); |
| 732 | + $this->endForm(); |
| 733 | + return 'output'; |
| 734 | + } |
| 735 | + |
| 736 | + $ok = $conn->selectDB( $this->parent->getVar( 'wgDBname' ) ); |
| 737 | + if ( !$ok ) { |
| 738 | + // No DB exists yet |
| 739 | + return 'skip'; |
| 740 | + } |
| 741 | + if ( !$conn->tableExists( 'cur' ) && !$conn->tableExists( 'revision' ) ) { |
| 742 | + // Nothing to upgrade |
| 743 | + return 'skip'; |
| 744 | + } |
| 745 | + |
| 746 | + if ( $this->parent->request->wasPosted() ) { |
| 747 | + if ( true || $installer->doUpgrade() ) { |
| 748 | + $this->parent->setVar( '_UpgradeDone', true ); |
| 749 | + $this->showDoneMessage(); |
| 750 | + return 'output'; |
| 751 | + } |
| 752 | + } |
| 753 | + |
| 754 | + $this->startForm(); |
| 755 | + $this->parent->output->addHTML( $this->parent->getInfoBox( |
| 756 | + array( 'config-can-upgrade', $GLOBALS['wgVersion'] ) ) ); |
| 757 | + $this->endForm(); |
| 758 | + } |
| 759 | + |
| 760 | + function showDoneMessage() { |
| 761 | + $this->startForm(); |
| 762 | + $this->parent->output->addHTML( |
| 763 | + $this->parent->getInfoBox( |
| 764 | + array( |
| 765 | + 'config-upgrade-done', |
| 766 | + $GLOBALS['wgServer'] . |
| 767 | + $this->parent->getVar( 'wgScriptPath' ) . '/index' . |
| 768 | + $this->parent->getVar( 'wgScriptExtension' ) |
| 769 | + ), 'tick-32.png' |
| 770 | + ) |
| 771 | + ); |
| 772 | + $this->endForm( 'regenerate' ); |
| 773 | + } |
| 774 | +} |
| 775 | + |
| 776 | +class WebInstaller_DBSettings extends WebInstallerPage { |
| 777 | + function execute() { |
| 778 | + $installer = $this->parent->getDBInstaller( $this->parent->getVar( 'wgDBtype' ) ); |
| 779 | + $form = $installer->getSettingsForm(); |
| 780 | + if ( $form === false ) { |
| 781 | + return 'skip'; |
| 782 | + } |
| 783 | + $this->startForm(); |
| 784 | + $this->parent->output->addHTML( $form ); |
| 785 | + $this->endForm(); |
| 786 | + } |
| 787 | + |
| 788 | +} |
| 789 | + |
| 790 | +class WebInstaller_Identity extends WebInstallerPage { |
| 791 | +} |
| 792 | +class WebInstaller_License extends WebInstallerPage { |
| 793 | +} |
| 794 | +class WebInstaller_Email extends WebInstallerPage { |
| 795 | +} |
| 796 | +class WebInstaller_Install extends WebInstallerPage { |
| 797 | +} |
| 798 | +class WebInstaller_Complete extends WebInstallerPage { |
| 799 | +} |
| 800 | +class WebInstaller_Restart extends WebInstallerPage { |
| 801 | + function execute() { |
| 802 | + $r = $this->parent->request; |
| 803 | + if ( $r->wasPosted() ) { |
| 804 | + $really = $r->getVal( 'submit-restart' ); |
| 805 | + if ( $really ) { |
| 806 | + $this->parent->session = array(); |
| 807 | + $this->parent->happyPages = array(); |
| 808 | + $this->parent->settings = array(); |
| 809 | + } |
| 810 | + return 'continue'; |
| 811 | + } |
| 812 | + |
| 813 | + $this->startForm(); |
| 814 | + $s = $this->parent->getWarningBox( 'config-help-restart' ); |
| 815 | + $this->parent->output->addHTML( $s ); |
| 816 | + $this->endForm( 'restart' ); |
| 817 | + } |
| 818 | +} |
| 819 | + |
Property changes on: branches/new-installer/phase3/includes/installer/WebInstaller.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 820 | + native |
Index: branches/new-installer/phase3/includes/installer/WebInstallerOutput.php |
— | — | @@ -0,0 +1,323 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Output class modelled on OutputPage. |
| 6 | + * |
| 7 | + * I've opted to use a distinct class rather than derive from OutputPage here in |
| 8 | + * the interests of separation of concerns: if we used a subclass, there would be |
| 9 | + * quite a lot of things you could do in OutputPage that would break the installer, |
| 10 | + * that wouldn't be immediately obvious. |
| 11 | + */ |
| 12 | +class WebInstallerOutput { |
| 13 | + var $parent; |
| 14 | + var $contents = ''; |
| 15 | + var $headerDone = false; |
| 16 | + var $redirectTarget; |
| 17 | + var $debug = true; |
| 18 | + |
| 19 | + function __construct( $parent ) { |
| 20 | + $this->parent = $parent; |
| 21 | + } |
| 22 | + |
| 23 | + function addHTML( $html ) { |
| 24 | + $this->contents .= $html; |
| 25 | + $this->flush(); |
| 26 | + } |
| 27 | + |
| 28 | + function addWikiText( $text ) { |
| 29 | + $this->addHTML( $this->parent->parse( $text ) ); |
| 30 | + } |
| 31 | + |
| 32 | + function addHTMLNoFlush( $html ) { |
| 33 | + $this->contents .= $html; |
| 34 | + } |
| 35 | + |
| 36 | + function redirect( $url ) { |
| 37 | + $this->redirectTarget = $url; |
| 38 | + } |
| 39 | + |
| 40 | + function output() { |
| 41 | + $this->flush(); |
| 42 | + $this->outputFooter(); |
| 43 | + } |
| 44 | + |
| 45 | + function flush() { |
| 46 | + if ( !$this->headerDone ) { |
| 47 | + $this->outputHeader(); |
| 48 | + } |
| 49 | + if ( !$this->redirectTarget && strlen( $this->contents ) ) { |
| 50 | + echo $this->contents; |
| 51 | + flush(); |
| 52 | + $this->contents = ''; |
| 53 | + } |
| 54 | + } |
| 55 | + |
| 56 | + function outputHeader() { |
| 57 | + global $wgVersion; |
| 58 | + $this->headerDone = true; |
| 59 | + $dbTypes = $this->parent->getDBTypes(); |
| 60 | + |
| 61 | + $this->parent->request->response()->header("Content-Type: text/html; charset=utf-8"); |
| 62 | + if ( $this->redirectTarget ) { |
| 63 | + $this->parent->request->response()->header( 'Location: '.$this->redirectTarget ); |
| 64 | + return; |
| 65 | + } |
| 66 | + |
| 67 | + |
| 68 | +?> |
| 69 | +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| 70 | +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr"> |
| 71 | +<head> |
| 72 | + <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> |
| 73 | + <title>MediaWiki <?php echo( htmlspecialchars( $wgVersion ) ); ?> Installation</title> |
| 74 | + <style type="text/css"> |
| 75 | + |
| 76 | + @import "../skins/monobook/main.css"; |
| 77 | + |
| 78 | + .env-check { |
| 79 | + font-size: 90%; |
| 80 | + margin: 1em 0 1em 2.5em; |
| 81 | + } |
| 82 | + |
| 83 | + .config-section { |
| 84 | + margin-top: 2em; |
| 85 | + } |
| 86 | + |
| 87 | + .config-label { |
| 88 | + clear: left; |
| 89 | + font-weight: bold; |
| 90 | + width: 10em; |
| 91 | + float: left; |
| 92 | + text-align: right; |
| 93 | + padding-right: 1em; |
| 94 | + padding-top: .2em; |
| 95 | + } |
| 96 | + |
| 97 | + .config-input { |
| 98 | + clear: left; |
| 99 | + zoom: 100%; /* IE hack */ |
| 100 | + } |
| 101 | + |
| 102 | + .config-page-wrapper { |
| 103 | + padding: 0.5em; |
| 104 | + } |
| 105 | + |
| 106 | + .config-page-list { |
| 107 | + float: right; |
| 108 | + width: 12em; |
| 109 | + border: 1px solid #aaa; |
| 110 | + padding: 0.5em; |
| 111 | + margin: 0.5em; |
| 112 | + } |
| 113 | + |
| 114 | + .config-page { |
| 115 | + padding: 0.5em 2em 0.5em 2em; |
| 116 | + /* 15em right margin to leave space for 12em page list */ |
| 117 | + margin: 0.5em 15em 0.5em 0.5em; |
| 118 | + border: 1px solid #aaa; |
| 119 | + } |
| 120 | + |
| 121 | + .config-submit { |
| 122 | + clear: left; |
| 123 | + text-align: center; |
| 124 | + padding: 1em; |
| 125 | + } |
| 126 | + |
| 127 | + .config-submit input { |
| 128 | + margin-left: 0.5em; |
| 129 | + margin-right: 0.5em; |
| 130 | + } |
| 131 | + |
| 132 | + .config-page-disabled { |
| 133 | + color: #aaa; |
| 134 | + } |
| 135 | + |
| 136 | + .config-info-left { |
| 137 | + margin: 0.5em; |
| 138 | + float: left; |
| 139 | + width: 35px; |
| 140 | + } |
| 141 | + |
| 142 | + .config-info-right { |
| 143 | + margin: 0.5em; |
| 144 | + float: left; |
| 145 | + width: 30em; |
| 146 | + } |
| 147 | + |
| 148 | + .config-page-current { |
| 149 | + font-weight: bold; |
| 150 | + } |
| 151 | + |
| 152 | + .config-desc { |
| 153 | + clear: left; |
| 154 | + margin: 0 0 2em 12em; |
| 155 | + padding-top: 1em; |
| 156 | + font-size: 85%; |
| 157 | + } |
| 158 | + |
| 159 | + .config-message { |
| 160 | + display: list-item; |
| 161 | + line-height: 1.5em; |
| 162 | + list-style-image: url(../skins/common/images/bullet.gif); |
| 163 | + list-style-type: square; |
| 164 | + } |
| 165 | + |
| 166 | + .config-input-text { |
| 167 | + width: 20em; |
| 168 | + margin-right: 1em; |
| 169 | + } |
| 170 | + |
| 171 | + .config-input-check { |
| 172 | + margin-left: 10em; |
| 173 | + } |
| 174 | + |
| 175 | + .error { |
| 176 | + color: red; |
| 177 | + background-color: #fff; |
| 178 | + font-weight: bold; |
| 179 | + left: 1em; |
| 180 | + font-size: 100%; |
| 181 | + } |
| 182 | + |
| 183 | + .config-error-top { |
| 184 | + background-color: #FFF0F0; |
| 185 | + border: 2px solid red; |
| 186 | + font-size: 110%; |
| 187 | + font-weight: bold; |
| 188 | + padding: 1em 1.5em; |
| 189 | + margin: 2em 0 1em; |
| 190 | + } |
| 191 | + |
| 192 | + .config-settings-block { |
| 193 | + list-style-type: none; |
| 194 | + list-style-image: none; |
| 195 | + float: left; |
| 196 | + margin: 0; |
| 197 | + padding: 0; |
| 198 | + } |
| 199 | + |
| 200 | + .btn-install { |
| 201 | + font-weight: bold; |
| 202 | + font-size: 110%; |
| 203 | + padding: .2em .3em; |
| 204 | + } |
| 205 | + |
| 206 | + .license { |
| 207 | + clear: both; |
| 208 | + font-size: 85%; |
| 209 | + padding-top: 3em; |
| 210 | + } |
| 211 | + |
| 212 | + .success-message { |
| 213 | + font-weight: bold; |
| 214 | + font-size: 110%; |
| 215 | + color: green; |
| 216 | + } |
| 217 | + .success-box { |
| 218 | + font-size: 130%; |
| 219 | + } |
| 220 | + |
| 221 | + </style> |
| 222 | + <script type="text/javascript"> |
| 223 | + <!-- |
| 224 | +<?php |
| 225 | + echo "var dbTypes = " . Xml::encodeJsVar( $dbTypes ) . "\n"; |
| 226 | +?> |
| 227 | + function hideAllDBs() { |
| 228 | + for ( var i = 0; i < dbTypes.length; i++ ) { |
| 229 | + elt = document.getElementById( 'DB_wrapper_' + dbTypes[i] ); |
| 230 | + if ( elt ) elt.style.display = 'none'; |
| 231 | + } |
| 232 | + } |
| 233 | + function showDBArea(type) { |
| 234 | + hideAllDBs(); |
| 235 | + var div = document.getElementById('DB_wrapper_' + type); |
| 236 | + if (div) div.style.display = 'block'; |
| 237 | + } |
| 238 | + function resetDBArea() { |
| 239 | + for ( var i = 0; i < dbTypes.length; i++ ) { |
| 240 | + input = document.getElementById('DBType_' + dbTypes[i]); |
| 241 | + if ( input && input.checked ) { |
| 242 | + showDBArea( dbTypes[i] ); |
| 243 | + return; |
| 244 | + } |
| 245 | + } |
| 246 | + } |
| 247 | + function disableControlArray( sourceID, targetIDs ) { |
| 248 | + var source = document.getElementById( sourceID ); |
| 249 | + var disabled = source.checked ? '1' : ''; |
| 250 | + if ( !source ) { |
| 251 | + return; |
| 252 | + } |
| 253 | + for ( var i = 0; i < targetIDs.length; i++ ) { |
| 254 | + var elt = document.getElementById( targetIDs[i] ); |
| 255 | + if ( elt ) elt.disabled = disabled; |
| 256 | + } |
| 257 | + } |
| 258 | + // --> |
| 259 | + </script> |
| 260 | +</head> |
| 261 | + |
| 262 | +<body> |
| 263 | +<div id="globalWrapper"> |
| 264 | +<div id="column-content"> |
| 265 | +<div id="content"> |
| 266 | +<div id="bodyContent"> |
| 267 | + |
| 268 | +<h1>MediaWiki <?php print htmlspecialchars( $wgVersion ); ?> Installation</h1> |
| 269 | +<?php |
| 270 | + } |
| 271 | + |
| 272 | + function outputFooter() { |
| 273 | +?> |
| 274 | + <div class="license"> |
| 275 | + <hr/> |
| 276 | + <p>This program is free software; you can redistribute it and/or modify |
| 277 | + it under the terms of the GNU General Public License as published by |
| 278 | + the Free Software Foundation; either version 2 of the License, or |
| 279 | + (at your option) any later version.</p> |
| 280 | + |
| 281 | + <p>This program is distributed in the hope that it will be useful, |
| 282 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 283 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 284 | + GNU General Public License for more details.</p> |
| 285 | + |
| 286 | + <p>You should have received <a href="../COPYING">a copy of the GNU General Public License</a> |
| 287 | + along with this program; if not, write to the Free Software |
| 288 | + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 289 | + or <a href="http://www.gnu.org/copyleft/gpl.html">read it online</a></p> |
| 290 | + </div> |
| 291 | + |
| 292 | +</div></div></div> |
| 293 | + |
| 294 | + |
| 295 | +<div id="column-one"> |
| 296 | + <div class="portlet" id="p-logo"> |
| 297 | + <a style="background-image: url(../skins/common/images/mediawiki.png);" |
| 298 | + href="http://www.mediawiki.org/" |
| 299 | + title="Main Page"></a> |
| 300 | + </div> |
| 301 | + <script type="text/javascript"> if (window.isMSIE55) fixalpha(); </script> |
| 302 | + <div class='portlet'><div class='pBody'> |
| 303 | + <ul> |
| 304 | + <li><strong><a href="http://www.mediawiki.org/">MediaWiki home</a></strong></li> |
| 305 | + <li><a href="../README">Readme</a></li> |
| 306 | + <li><a href="../RELEASE-NOTES">Release notes</a></li> |
| 307 | + <li><a href="../docs/">Documentation</a></li> |
| 308 | + <li><a href="http://www.mediawiki.org/wiki/Help:Contents">User's Guide</a></li> |
| 309 | + <li><a href="http://www.mediawiki.org/wiki/Manual:Contents">Administrator's Guide</a></li> |
| 310 | + <li><a href="http://www.mediawiki.org/wiki/Manual:FAQ">FAQ</a></li> |
| 311 | + </ul> |
| 312 | + <p style="font-size:90%;margin-top:1em">MediaWiki is Copyright © 2001-2008 by Magnus Manske, Brion Vibber, |
| 313 | + Lee Daniel Crocker, Tim Starling, Erik Möller, Gabriel Wicke, Ævar Arnfjörð Bjarmason, Niklas Laxström, |
| 314 | + Domas Mituzas, Rob Church, Yuri Astrakhan, Aryeh Gregor, Aaron Schulz and others.</p> |
| 315 | + </div></div> |
| 316 | +</div> |
| 317 | + |
| 318 | +</div> |
| 319 | + |
| 320 | +</body> |
| 321 | +</html> |
| 322 | +<?php |
| 323 | + } |
| 324 | +} |
Property changes on: branches/new-installer/phase3/includes/installer/WebInstallerOutput.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 325 | + native |
Index: branches/new-installer/phase3/includes/installer/Installer.php |
— | — | @@ -0,0 +1,557 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Base installer class |
| 6 | + * Handles everything that is independent of user interface |
| 7 | + */ |
| 8 | +abstract class Installer { |
| 9 | + var $settings, $output; |
| 10 | + |
| 11 | + /** |
| 12 | + * MediaWiki configuration globals that will eventually be passed through |
| 13 | + * to LocalSettings.php. The names only are given here, the defaults |
| 14 | + * typically come from DefaultSettings.php. |
| 15 | + * @protected |
| 16 | + */ |
| 17 | + var $defaultVarNames = array( |
| 18 | + 'wgSitename', |
| 19 | + 'wgPasswordSender', |
| 20 | + 'wgLanguageCode', |
| 21 | + 'wgRightsIcon', |
| 22 | + 'wgRightsText', |
| 23 | + 'wgRightsUrl', |
| 24 | + 'wgMainCacheType', |
| 25 | + 'wgEnableEmail', |
| 26 | + 'wgEnableUserEmail', |
| 27 | + 'wgEnotifUserTalk', |
| 28 | + 'wgEnotifWatchlist', |
| 29 | + 'wgDBtype', |
| 30 | + 'wgDiff3', |
| 31 | + 'wgImageMagickConvertCommand', |
| 32 | + 'IP', |
| 33 | + 'wgScriptPath', |
| 34 | + 'wgScriptExtension', |
| 35 | + ); |
| 36 | + |
| 37 | + /** |
| 38 | + * Variables that are stored alongside globals, and are used for any |
| 39 | + * configuration of the installation process aside from the MediaWiki |
| 40 | + * configuration. Map of names to defaults. |
| 41 | + * @protected |
| 42 | + */ |
| 43 | + var $internalDefaults = array( |
| 44 | + '_Environment' => false, |
| 45 | + '_CompiledDBs' => array(), |
| 46 | + '_SafeMode' => false, |
| 47 | + '_RaiseMemory' => false, |
| 48 | + '_UpgradeDone' => false, |
| 49 | + '_Caches' => array(), |
| 50 | + ); |
| 51 | + |
| 52 | + /** |
| 53 | + * Known database types. These correspond to the class names <type>_Installer, |
| 54 | + * and are also MediaWiki database types valid for $wgDBtype. |
| 55 | + * |
| 56 | + * To add a new type, create a <type>_Installer class and a Database<type> |
| 57 | + * class, and add a config-type-<type> message to MessagesEn.php. |
| 58 | + * @private |
| 59 | + */ |
| 60 | + var $dbTypes = array( |
| 61 | + 'mysql', |
| 62 | + 'postgres', |
| 63 | + 'sqlite' |
| 64 | + ); |
| 65 | + |
| 66 | + /** |
| 67 | + * Cached DB installer instances, access using getDBInstaller() |
| 68 | + * @private |
| 69 | + */ |
| 70 | + var $dbInstallers = array(); |
| 71 | + |
| 72 | + /** |
| 73 | + * A list of environment check methods called by doEnvironmentChecks(). |
| 74 | + * These may output warnings using showMessage(), and/or abort the |
| 75 | + * installation process by returning false. |
| 76 | + * @protected |
| 77 | + */ |
| 78 | + var $envChecks = array( |
| 79 | + 'envCheckDB', |
| 80 | + 'envCheckRegisterGlobals', |
| 81 | + 'envCheckMagicQuotes', |
| 82 | + 'envCheckMagicSybase', |
| 83 | + 'envCheckMbstring', |
| 84 | + 'envCheckZE1', |
| 85 | + 'envCheckSafeMode', |
| 86 | + 'envCheckXML', |
| 87 | + 'envCheckPCRE', |
| 88 | + 'envCheckMemory', |
| 89 | + 'envCheckCache', |
| 90 | + 'envCheckDiff3', |
| 91 | + 'envCheckGraphics', |
| 92 | + 'envCheckPath', |
| 93 | + 'envCheckExtension', |
| 94 | + ); |
| 95 | + |
| 96 | + /** |
| 97 | + * Known object cache types and the functions used to test for their existence |
| 98 | + * @protected |
| 99 | + */ |
| 100 | + var $objectCaches = array( |
| 101 | + 'turck' => 'mmcache_get', |
| 102 | + 'xcache' => 'xcache_get', |
| 103 | + 'apc' => 'apc_fetch', |
| 104 | + 'eaccel' => 'eaccelerator_get' |
| 105 | + ); |
| 106 | + |
| 107 | + /** |
| 108 | + * Cached Title and ParserOptions used by parse() |
| 109 | + * @private |
| 110 | + */ |
| 111 | + var $parserTitle, $parserOptions; |
| 112 | + |
| 113 | + /** |
| 114 | + * Constructor, always call this from child classes |
| 115 | + */ |
| 116 | + function __construct() { |
| 117 | + $this->settings = $this->internalDefaults; |
| 118 | + foreach ( $this->defaultVarNames as $var ) { |
| 119 | + $this->settings[$var] = $GLOBALS[$var]; |
| 120 | + } |
| 121 | + foreach ( $this->dbTypes as $type ) { |
| 122 | + $installer = $this->getDBInstaller( $type ); |
| 123 | + if ( !$installer->isCompiled() ) { |
| 124 | + continue; |
| 125 | + } |
| 126 | + $defaults = $installer->getGlobalDefaults(); |
| 127 | + foreach ( $installer->getGlobalNames() as $var ) { |
| 128 | + if ( isset( $defaults[$var] ) ) { |
| 129 | + $this->settings[$var] = $defaults[$var]; |
| 130 | + } else { |
| 131 | + $this->settings[$var] = $GLOBALS[$var]; |
| 132 | + } |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + $this->parserTitle = Title::newFromText( 'Installer' ); |
| 137 | + $this->parserOptions = new ParserOptions; |
| 138 | + $this->parserOptions->setEditSection( false ); |
| 139 | + } |
| 140 | + |
| 141 | + /** |
| 142 | + * UI interface for displaying a short message |
| 143 | + * The parameters are like parameters to wfMsg(). |
| 144 | + * The messages will be in wikitext format, which will be converted to an |
| 145 | + * output format such as HTML or text before being sent to the user. |
| 146 | + */ |
| 147 | + abstract function showMessage( $msg /*, ... */ ); |
| 148 | + |
| 149 | + /** |
| 150 | + * Get a list of known DB types |
| 151 | + */ |
| 152 | + function getDBTypes() { |
| 153 | + return $this->dbTypes; |
| 154 | + } |
| 155 | + |
| 156 | + /** |
| 157 | + * Get an instance of InstallerDBType for the specified DB type |
| 158 | + */ |
| 159 | + function getDBInstaller( $type ) { |
| 160 | + if ( !isset( $this->dbInstallers[$type] ) ) { |
| 161 | + $class = ucfirst( $type ). 'Installer'; |
| 162 | + $this->dbInstallers[$type] = new $class( $this ); |
| 163 | + } |
| 164 | + return $this->dbInstallers[$type]; |
| 165 | + } |
| 166 | + |
| 167 | + /** |
| 168 | + * Do initial checks of the PHP environment. Set variables according to |
| 169 | + * the observed environment. |
| 170 | + * |
| 171 | + * It's possible that this may be called under the CLI SAPI, not the SAPI |
| 172 | + * that the wiki will primarily run under. In that case, the subclass should |
| 173 | + * initialise variables such as wgScriptPath, before calling this function. |
| 174 | + * |
| 175 | + * Under the web subclass, it can already be assumed that PHP 5+ is in use |
| 176 | + * and that sessions are working. |
| 177 | + */ |
| 178 | + function doEnvironmentChecks() { |
| 179 | + $this->showMessage( 'config-env-php', phpversion() ); |
| 180 | + |
| 181 | + $good = true; |
| 182 | + foreach ( $this->envChecks as $check ) { |
| 183 | + $status = $this->$check(); |
| 184 | + if ( $status === false ) { |
| 185 | + $good = false; |
| 186 | + } |
| 187 | + } |
| 188 | + $this->setVar( '_Environment', $good ); |
| 189 | + if ( $good ) { |
| 190 | + $this->showMessage( 'config-env-good' ); |
| 191 | + } else { |
| 192 | + $this->showMessage( 'config-env-bad' ); |
| 193 | + } |
| 194 | + return $good; |
| 195 | + } |
| 196 | + |
| 197 | + /** |
| 198 | + * Get an MW configuration variable, or internal installer configuration variable. |
| 199 | + * The defaults come from $GLOBALS (ultimately DefaultSettings.php). |
| 200 | + * Installer variables are typically prefixed by an underscore. |
| 201 | + */ |
| 202 | + function getVar( $name, $default = null ) { |
| 203 | + if ( !isset( $this->settings[$name] ) ) { |
| 204 | + return $default; |
| 205 | + } else { |
| 206 | + return $this->settings[$name]; |
| 207 | + } |
| 208 | + } |
| 209 | + |
| 210 | + /** |
| 211 | + * Set a MW configuration variable, or internal installer configuration variable. |
| 212 | + */ |
| 213 | + function setVar( $name, $value ) { |
| 214 | + $this->settings[$name] = $value; |
| 215 | + } |
| 216 | + |
| 217 | + /** |
| 218 | + * Get a fake password for sending back to the user in HTML. |
| 219 | + * This is a security mechanism to avoid compromise of the password in the |
| 220 | + * event of session ID compromise. |
| 221 | + */ |
| 222 | + function getFakePassword( $realPassword ) { |
| 223 | + return str_repeat( '*', strlen( $realPassword ) ); |
| 224 | + } |
| 225 | + |
| 226 | + /** |
| 227 | + * Set a variable which stores a password, except if the new value is a |
| 228 | + * fake password in which case leave it as it is. |
| 229 | + */ |
| 230 | + function setPassword( $name, $value ) { |
| 231 | + if ( !preg_match( '/^\*+$/', $value ) ) { |
| 232 | + $this->setVar( $name, $value ); |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + /** |
| 237 | + * Returns true if dl() can be used |
| 238 | + */ |
| 239 | + function haveDl() { |
| 240 | + return function_exists( 'dl' ) |
| 241 | + && is_callable( 'dl' ) |
| 242 | + && wfIniGetBool( 'enable_dl' ) |
| 243 | + && !wfIniGetBool( 'safe_mode' ); |
| 244 | + } |
| 245 | + |
| 246 | + /** Environment check for DB types */ |
| 247 | + function envCheckDB() { |
| 248 | + $compiledDBs = array(); |
| 249 | + $haveDl = $this->haveDl(); |
| 250 | + $goodNames = array(); |
| 251 | + $allNames = array(); |
| 252 | + foreach ( $this->dbTypes as $name ) { |
| 253 | + $db = $this->getDBInstaller( $name ); |
| 254 | + $readableName = wfMsg( 'config-type-' . $name ); |
| 255 | + if ( $db->isCompiled() ) { |
| 256 | + $compiledDBs[$name] = true; |
| 257 | + $goodNames[] = $readableName; |
| 258 | + } |
| 259 | + $allNames[] = $readableName; |
| 260 | + } |
| 261 | + $this->setVar( '_CompiledDBs', $compiledDBs ); |
| 262 | + |
| 263 | + global $wgLang; |
| 264 | + if ( !$compiledDBs ) { |
| 265 | + $this->showMessage( 'config-no-db' ); |
| 266 | + $this->showHelpBox( 'config-no-db-help', $wgLang->commaList( $allNames ) ); |
| 267 | + return false; |
| 268 | + } |
| 269 | + $this->showMessage( 'config-have-db', $wgLang->commaList( $goodNames ) ); |
| 270 | + } |
| 271 | + |
| 272 | + /** Environment check for register_globals */ |
| 273 | + function envCheckRegisterGlobals() { |
| 274 | + if( wfIniGetBool( "magic_quotes_runtime" ) ) { |
| 275 | + $this->showMessage( 'config-register-globals' ); |
| 276 | + } |
| 277 | + } |
| 278 | + |
| 279 | + /** Environment check for magic_quotes_runtime */ |
| 280 | + function envCheckMagicQuotes() { |
| 281 | + if( wfIniGetBool( "magic_quotes_runtime" ) ) { |
| 282 | + $this->showMessage( 'config-magic-quotes-runtime' ); |
| 283 | + return false; |
| 284 | + } |
| 285 | + } |
| 286 | + |
| 287 | + /** Environment check for magic_quotes_sybase */ |
| 288 | + function envCheckMagicSybase() { |
| 289 | + if ( wfIniGetBool( 'magic_quotes_sybase' ) ) { |
| 290 | + $this->showMessage( 'config-magic-quotes-sybase' ); |
| 291 | + return false; |
| 292 | + } |
| 293 | + } |
| 294 | + |
| 295 | + /* Environment check for mbstring.func_overload */ |
| 296 | + function envCheckMbstring() { |
| 297 | + if ( wfIniGetBool( 'mbstring.func_overload' ) ) { |
| 298 | + $this->showMessage( 'config-mbstring' ); |
| 299 | + return false; |
| 300 | + } |
| 301 | + } |
| 302 | + |
| 303 | + /** Environment check for zend.ze1_compatibility_mode */ |
| 304 | + function envCheckZE1() { |
| 305 | + if ( wfIniGetBool( 'zend.ze1_compatibility_mode' ) ) { |
| 306 | + $this->showMessage( 'config-ze1' ); |
| 307 | + return false; |
| 308 | + } |
| 309 | + } |
| 310 | + |
| 311 | + /** Environment check for safe_mode */ |
| 312 | + function envCheckSafeMode() { |
| 313 | + if ( wfIniGetBool( 'safe_mode' ) ) { |
| 314 | + $this->setVar( '_SafeMode', true ); |
| 315 | + $this->showMessage( 'config-safe-mode' ); |
| 316 | + } |
| 317 | + } |
| 318 | + |
| 319 | + /** Environment check for the XML module */ |
| 320 | + function envCheckXML() { |
| 321 | + if ( !function_exists( "utf8_encode" ) ) { |
| 322 | + $this->showMessage( 'config-xml-bad' ); |
| 323 | + return false; |
| 324 | + } |
| 325 | + $this->showMessage( 'config-xml-good' ); |
| 326 | + } |
| 327 | + |
| 328 | + /** Environment check for the PCRE module */ |
| 329 | + function envCheckPCRE() { |
| 330 | + if ( !function_exists( 'preg_match' ) ) { |
| 331 | + $this->showMessage( 'config-pcre' ); |
| 332 | + return false; |
| 333 | + } |
| 334 | + } |
| 335 | + |
| 336 | + /** Environment check for available memory */ |
| 337 | + function envCheckMemory() { |
| 338 | + $limit = ini_get( 'memory_limit' ); |
| 339 | + if ( !$limit || $limit == -1 ) { |
| 340 | + $this->showMessage( 'config-memory-none' ); |
| 341 | + return true; |
| 342 | + } |
| 343 | + $n = intval( $limit ); |
| 344 | + if( preg_match( '/^([0-9]+)[Mm]$/', trim( $limit ), $m ) ) { |
| 345 | + $n = intval( $m[1] * (1024*1024) ); |
| 346 | + } |
| 347 | + if( $n < 20*1024*1024 ) { |
| 348 | + if( false === ini_set( "memory_limit", "20M" ) ) { |
| 349 | + $this->showMessage( 'config-memory-bad', $limit ); |
| 350 | + } else { |
| 351 | + $this->showMessage( 'config-memory-raised', $limit ); |
| 352 | + $this->setVar( '_RaiseMemory', true ); |
| 353 | + } |
| 354 | + } else { |
| 355 | + $this->showMessage( 'config-memory-ok', $limit ); |
| 356 | + } |
| 357 | + } |
| 358 | + |
| 359 | + /** Environment check for compiled object cache types */ |
| 360 | + function envCheckCache() { |
| 361 | + $caches = array(); |
| 362 | + foreach ( $this->objectCaches as $name => $function ) { |
| 363 | + if ( function_exists( $function ) ) { |
| 364 | + $caches[$name] = true; |
| 365 | + $this->showMessage( 'config-' . $name ); |
| 366 | + } |
| 367 | + } |
| 368 | + if ( !$caches ) { |
| 369 | + $this->showMessage( 'config-no-cache' ); |
| 370 | + } |
| 371 | + if ( function_exists( 'dba_open' ) ) { |
| 372 | + $caches['dba'] = true; |
| 373 | + } |
| 374 | + $this->setVar( '_Caches', $caches ); |
| 375 | + } |
| 376 | + |
| 377 | + /** Search for GNU diff3 */ |
| 378 | + function envCheckDiff3() { |
| 379 | + $paths = array_merge( |
| 380 | + array( |
| 381 | + "/usr/bin", |
| 382 | + "/usr/local/bin", |
| 383 | + "/opt/csw/bin", |
| 384 | + "/usr/gnu/bin", |
| 385 | + "/usr/sfw/bin" ), |
| 386 | + explode( PATH_SEPARATOR, getenv( "PATH" ) ) ); |
| 387 | + $names = array( "gdiff3", "diff3", "diff3.exe" ); |
| 388 | + |
| 389 | + $versionInfo = array( '$1 --version 2>&1', 'diff3 (GNU diffutils)' ); |
| 390 | + $haveDiff3 = false; |
| 391 | + foreach ( $paths as $path ) { |
| 392 | + $exe = $this->locateExecutable( $path, $names, $versionInfo ); |
| 393 | + if ($exe !== false) { |
| 394 | + $this->setVar( 'wgDiff3', $exe ); |
| 395 | + $haveDiff3 = true; |
| 396 | + break; |
| 397 | + } |
| 398 | + } |
| 399 | + if ( $haveDiff3 ) { |
| 400 | + $this->showMessage( 'config-diff3-good', $exe ); |
| 401 | + } else { |
| 402 | + $this->setVar( 'wgDiff3', false ); |
| 403 | + $this->showMessage( 'config-diff3-bad' ); |
| 404 | + } |
| 405 | + } |
| 406 | + |
| 407 | + /** |
| 408 | + * Search a path for any of the given executable names. Returns the |
| 409 | + * executable name if found. Also checks the version string returned |
| 410 | + * by each executable |
| 411 | + * |
| 412 | + * @param string $path Path to search |
| 413 | + * @param array $names Array of executable names |
| 414 | + * @param string $versionInfo Array with two members: |
| 415 | + * 0 => Command to run for version check, with $1 for the path |
| 416 | + * 1 => String to compare the output with |
| 417 | + * |
| 418 | + * If $versionInfo is not false, only executables with a version |
| 419 | + * matching $versionInfo[1] will be returned. |
| 420 | + */ |
| 421 | + function locateExecutable( $path, $names, $versionInfo = false ) { |
| 422 | + if (!is_array($names)) |
| 423 | + $names = array($names); |
| 424 | + |
| 425 | + foreach ($names as $name) { |
| 426 | + $command = "$path/$name"; |
| 427 | + if ( @file_exists( $command ) ) { |
| 428 | + if ( !$versionInfo ) |
| 429 | + return $command; |
| 430 | + |
| 431 | + $file = str_replace( '$1', $command, $versionInfo[0] ); |
| 432 | + if ( strstr( wfShellExec( $file ), $versionInfo[1]) !== false ) |
| 433 | + return $command; |
| 434 | + } |
| 435 | + } |
| 436 | + return false; |
| 437 | + } |
| 438 | + |
| 439 | + /** Environment check for ImageMagick and GD */ |
| 440 | + function envCheckGraphics() { |
| 441 | + $imcheck = array( "/usr/bin", "/opt/csw/bin", "/usr/local/bin", "/sw/bin", "/opt/local/bin" ); |
| 442 | + foreach( $imcheck as $dir ) { |
| 443 | + $im = "$dir/convert"; |
| 444 | + if( @file_exists( $im ) ) { |
| 445 | + $this->showMessage( 'config-imagemagick', $im ); |
| 446 | + $this->setVar( 'wgImageMagickConvertCommand', $im ); |
| 447 | + return true; |
| 448 | + } |
| 449 | + } |
| 450 | + if ( function_exists( 'imagejpeg' ) ) { |
| 451 | + $this->showMessage( 'config-gd' ); |
| 452 | + return true; |
| 453 | + } |
| 454 | + $this->showMessage( 'no-scaling' ); |
| 455 | + } |
| 456 | + |
| 457 | + /** Environment check for setting $IP and $wgScriptPath */ |
| 458 | + function envCheckPath() { |
| 459 | + $IP = dirname( dirname( dirname( __FILE__ ) ) ); |
| 460 | + $this->setVar( 'IP', $IP ); |
| 461 | + $this->showMessage( 'config-dir', $IP ); |
| 462 | + |
| 463 | + // PHP_SELF isn't available sometimes, such as when PHP is CGI but |
| 464 | + // cgi.fix_pathinfo is disabled. In that case, fall back to SCRIPT_NAME |
| 465 | + // to get the path to the current script... hopefully it's reliable. SIGH |
| 466 | + if ( !empty( $_SERVER['PHP_SELF'] ) ) { |
| 467 | + $path = $_SERVER['PHP_SELF']; |
| 468 | + } elseif ( !empty( $_SERVER['SCRIPT_NAME'] ) ) { |
| 469 | + $path = $_SERVER['SCRIPT_NAME']; |
| 470 | + } elseif ( $this->getVar( 'wgScriptPath' ) ) { |
| 471 | + // Some kind soul has set it for us already (e.g. debconf) |
| 472 | + return true; |
| 473 | + } else { |
| 474 | + $this->showMessage( 'config-no-uri' ); |
| 475 | + return false; |
| 476 | + } |
| 477 | + $uri = preg_replace( '{^(.*)/config.*$}', '$1', $path ); |
| 478 | + $this->setVar( 'wgScriptPath', $uri ); |
| 479 | + $this->showMessage( 'config-uri', $uri ); |
| 480 | + } |
| 481 | + |
| 482 | + abstract function showStatusError( $status ); |
| 483 | + |
| 484 | + /** Environment check for setting the preferred PHP file extension */ |
| 485 | + function envCheckExtension() { |
| 486 | + // FIXME: detect this properly |
| 487 | + if ( defined( 'MW_INSTALL_PHP5_EXT' ) ) { |
| 488 | + $ext = 'php5'; |
| 489 | + } else { |
| 490 | + $ext = 'php'; |
| 491 | + } |
| 492 | + $this->setVar( 'wgScriptExtension', ".$ext" ); |
| 493 | + $this->showMessage( 'config-extension', $ext ); |
| 494 | + } |
| 495 | + |
| 496 | + /** |
| 497 | + * Convert wikitext $text to HTML. |
| 498 | + * |
| 499 | + * This is potentially error prone since many parser features require a complete |
| 500 | + * installed MW database. The solution is to just not use those features when you |
| 501 | + * write your messages. This appears to work well enough. Basic formatting and |
| 502 | + * external links work just fine. |
| 503 | + * |
| 504 | + * But in case a translator decides to throw in a #ifexist or internal link or |
| 505 | + * whatever, this function is guarded to catch attempted DB access and to present |
| 506 | + * some fallback text. |
| 507 | + * |
| 508 | + * @param string $text |
| 509 | + * @return string |
| 510 | + */ |
| 511 | + function parse( $text ) { |
| 512 | + global $wgParser; |
| 513 | + try { |
| 514 | + $out = $wgParser->parse( $text, $this->parserTitle, $this->parserOptions, false ); |
| 515 | + $html = $out->getText(); |
| 516 | + } catch ( InstallerDBAccessError $e ) { |
| 517 | + $html = '<!--DB access attempted during parse--> ' . htmlspecialchars( $text ); |
| 518 | + if ( $this->debug ) { |
| 519 | + $html .= "<!--\n" . $e->getTraceAsString() . "\n-->"; |
| 520 | + } |
| 521 | + } |
| 522 | + return $html; |
| 523 | + } |
| 524 | +} |
| 525 | + |
| 526 | +/** |
| 527 | + * Exception class for attempted DB access |
| 528 | + */ |
| 529 | +class InstallerDBAccessError extends MWException { |
| 530 | + function __construct() { |
| 531 | + parent::__construct( "The installer attempted to access the DB via wfGetDB(). This is not allowed." ); |
| 532 | + } |
| 533 | +} |
| 534 | + |
| 535 | +/** |
| 536 | + * LBFactory class that throws an error on any attempt to use it. |
| 537 | + * This will typically be done via wfGetDB(). |
| 538 | + * Installer entry points should ensure that they set up $wgLBFactoryConf to |
| 539 | + * array( 'class' => 'LBFactory_InstallerFake' ) |
| 540 | + */ |
| 541 | +class LBFactory_InstallerFake extends LBFactory { |
| 542 | + function __construct( $conf ) {} |
| 543 | + |
| 544 | + function newMainLB( $wiki = false) { |
| 545 | + throw new InstallerDBAccessError; |
| 546 | + } |
| 547 | + function getMainLB( $wiki = false ) { |
| 548 | + throw new InstallerDBAccessError; |
| 549 | + } |
| 550 | + function newExternalLB( $cluster, $wiki = false ) { |
| 551 | + throw new InstallerDBAccessError; |
| 552 | + } |
| 553 | + function &getExternalLB( $cluster, $wiki = false ) { |
| 554 | + throw new InstallerDBAccessError; |
| 555 | + } |
| 556 | + function forEachLB( $callback, $params = array() ) {} |
| 557 | +} |
| 558 | + |
Property changes on: branches/new-installer/phase3/includes/installer/Installer.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 559 | + native |
Index: branches/new-installer/phase3/includes/installer/SqliteInstaller.php |
— | — | @@ -0,0 +1,71 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class SqliteInstaller extends InstallerDBType { |
| 5 | + var $globalNames = array( |
| 6 | + 'wgDBname', |
| 7 | + 'wgSQLiteDataDir' |
| 8 | + ); |
| 9 | + |
| 10 | + function getName() { |
| 11 | + return 'sqlite'; |
| 12 | + } |
| 13 | + |
| 14 | + function isCompiled() { |
| 15 | + return $this->checkExtension( 'pdo_sqlite' ); |
| 16 | + } |
| 17 | + |
| 18 | + function getGlobalNames() { |
| 19 | + return $this->globalNames; |
| 20 | + } |
| 21 | + |
| 22 | + function getGlobalDefaults() { |
| 23 | + if ( isset( $_SERVER['DOCUMENT_ROOT'] ) ) { |
| 24 | + return array( 'wgSQLiteDataDir' => dirname( $_SERVER['DOCUMENT_ROOT'] ) . '/data' ); |
| 25 | + } else { |
| 26 | + return array(); |
| 27 | + } |
| 28 | + } |
| 29 | + |
| 30 | + function getConnectForm() { |
| 31 | + return |
| 32 | + $this->getLabelledTextBox( 'wgSQLiteDataDir', 'config-sqlite-dir' ) . |
| 33 | + $this->parent->getHelpBox( 'config-sqlite-dir-help' ) . |
| 34 | + $this->getLabelledTextBox( 'wgDBname', 'config-db-name' ) . |
| 35 | + $this->parent->getHelpBox( 'config-sqlite-name-help' ); |
| 36 | + } |
| 37 | + |
| 38 | + function submitConnectForm() { |
| 39 | + global $wgSQLiteDataDirMode, $wgSQLiteDataDir; |
| 40 | + $newValues = $this->setVarsFromRequest(); |
| 41 | + $dir = $newValues['wgSQLiteDataDir']; |
| 42 | + if ( !is_dir( $dir ) ) { |
| 43 | + if ( !is_writable( dirname( $dir ) ) ) { |
| 44 | + return Status::newFatal( 'config-sqlite-parent-unwritable', $dir, dirname( $dir ) ); |
| 45 | + } |
| 46 | + wfSuppressWarnings(); |
| 47 | + $ok = wfMkdirParents( $dir, $wgSQLiteDataDirMode ); |
| 48 | + wfRestoreWarnings(); |
| 49 | + if ( !$ok ) { |
| 50 | + return Status::newFatal( 'config-sqlite-mkdir-error', $dir ); |
| 51 | + } |
| 52 | + # Put a .htaccess file in in case the user didn't take our advice |
| 53 | + file_put_contents( "$dir/.htaccess", "Deny from all\n" ); |
| 54 | + } |
| 55 | + if ( !is_writable( $dir ) ) { |
| 56 | + return Status::newFatal( 'config-sqlite-unwritable', $dir ); |
| 57 | + } |
| 58 | + return Status::newGood(); |
| 59 | + /* -- during install: |
| 60 | + $status = Status::newGood(); |
| 61 | + try { |
| 62 | + # FIXME: need more sensible constructor parameters, e.g. single associative array |
| 63 | + # Setting globals kind of sucks |
| 64 | + $wgSQLiteDataDir = $dir; |
| 65 | + $this->conn = new DatabaseSqlite( false, false, false, $newValues['wgDBname'] ); |
| 66 | + } catch ( DBConnectionError $e ) { |
| 67 | + $status->fatal( 'config-sqlite-connection-error', $e->getMessage() ); |
| 68 | + } |
| 69 | + return $status; |
| 70 | + */ |
| 71 | + } |
| 72 | +} |
Property changes on: branches/new-installer/phase3/includes/installer/SqliteInstaller.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 73 | + native |
Index: branches/new-installer/phase3/includes/installer/MysqlInstaller.php |
— | — | @@ -0,0 +1,197 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class MysqlInstaller extends InstallerDBType { |
| 5 | + var $globalNames = array( |
| 6 | + 'wgDBserver', |
| 7 | + 'wgDBname', |
| 8 | + 'wgDBuser', |
| 9 | + 'wgDBpassword', |
| 10 | + 'wgDBprefix', |
| 11 | + 'wgDBTableOptions', |
| 12 | + 'wgDBmysql5', |
| 13 | + ); |
| 14 | + |
| 15 | + var $internalDefaults = array( |
| 16 | + '_MysqlInstallUser' => 'root', |
| 17 | + '_MysqlInstallPassword' => '', |
| 18 | + '_MysqlSameAccount' => true, |
| 19 | + ); |
| 20 | + |
| 21 | + var $minimumVersion = '4.0.14'; |
| 22 | + |
| 23 | + var $conn; |
| 24 | + |
| 25 | + function getName() { |
| 26 | + return 'mysql'; |
| 27 | + } |
| 28 | + |
| 29 | + function isCompiled() { |
| 30 | + return $this->checkExtension( 'mysql' ); |
| 31 | + } |
| 32 | + |
| 33 | + function getGlobalNames() { |
| 34 | + return $this->globalNames; |
| 35 | + } |
| 36 | + |
| 37 | + function getGlobalDefaults() { |
| 38 | + return array(); |
| 39 | + } |
| 40 | + |
| 41 | + function getInternalDefaults() { |
| 42 | + return $this->internalDefaults; |
| 43 | + } |
| 44 | + |
| 45 | + function getConnectForm() { |
| 46 | + return |
| 47 | + $this->getLabelledTextBox( 'wgDBserver', 'config-db-host' ) . |
| 48 | + $this->parent->getHelpBox( 'config-db-host-help' ) . |
| 49 | + Xml::openElement( 'fieldset' ) . |
| 50 | + Xml::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) . |
| 51 | + $this->getLabelledTextBox( 'wgDBname', 'config-db-name' ) . |
| 52 | + $this->parent->getHelpBox( 'config-db-name-help' ) . |
| 53 | + $this->getLabelledTextBox( 'wgDBprefix', 'config-db-prefix' ) . |
| 54 | + $this->parent->getHelpBox( 'config-db-prefix-help' ) . |
| 55 | + Xml::closeElement( 'fieldset' ) . |
| 56 | + Xml::openElement( 'fieldset' ) . |
| 57 | + Xml::element( 'legend', array(), wfMsg( 'config-db-install-account' ) ) . |
| 58 | + $this->getLabelledTextBox( '_MysqlInstallUser', 'config-db-username' ) . |
| 59 | + $this->getLabelledPasswordBox( '_MysqlInstallPassword', 'config-db-password' ) . |
| 60 | + $this->parent->getHelpBox( 'config-db-install-help' ) . |
| 61 | + Xml::closeElement( 'fieldset' ); |
| 62 | + } |
| 63 | + |
| 64 | + function submitConnectForm() { |
| 65 | + // Get variables from the request |
| 66 | + $newValues = $this->setVarsFromRequest(); |
| 67 | + |
| 68 | + // Validate them |
| 69 | + $status = Status::newGood(); |
| 70 | + if ( !strlen( $newValues['wgDBname'] ) ) { |
| 71 | + $status->fatal( 'config-missing-db-name' ); |
| 72 | + } elseif ( !preg_match( '/^[a-zA-Z0-9_]+$/', $newValues['wgDBname'] ) ) { |
| 73 | + $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] ); |
| 74 | + } |
| 75 | + if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBprefix'] ) ) { |
| 76 | + $status->fatal( 'config-invalid-db-prefix', $newValues['wgDBprefix'] ); |
| 77 | + } |
| 78 | + if ( !$status->isOK() ) { |
| 79 | + return $status; |
| 80 | + } |
| 81 | + |
| 82 | + // Try to connect |
| 83 | + $status = $this->attemptConnection(); |
| 84 | + if ( !$status->isOK() ) { |
| 85 | + return $status; |
| 86 | + } |
| 87 | + |
| 88 | + // Check version |
| 89 | + $version = $this->conn->getServerVersion(); |
| 90 | + if ( version_compare( $version, $this->minimumVersion ) < 0 ) { |
| 91 | + return Status::newFatal( 'config-mysql-old', $this->minimumVersion, $version ); |
| 92 | + } |
| 93 | + |
| 94 | + return $status; |
| 95 | + } |
| 96 | + |
| 97 | + function attemptConnection() { |
| 98 | + $status = Status::newGood(); |
| 99 | + try { |
| 100 | + $this->conn = new Database( |
| 101 | + $this->getVar( 'wgDBserver' ), |
| 102 | + $this->getVar( '_MysqlInstallUser' ), |
| 103 | + $this->getVar( '_MysqlInstallPassword' ), |
| 104 | + false, |
| 105 | + false, |
| 106 | + 0, |
| 107 | + $this->getVar( 'wgDBprefix' ) |
| 108 | + ); |
| 109 | + } catch ( DBConnectionError $e ) { |
| 110 | + $status->fatal( 'config-connection-error', $e->getMessage() ); |
| 111 | + } |
| 112 | + return $status; |
| 113 | + } |
| 114 | + |
| 115 | + function getConnection() { |
| 116 | + $status = $this->attemptConnection(); |
| 117 | + if ( $status->isOK() ) { |
| 118 | + return $this->conn; |
| 119 | + } else { |
| 120 | + return $status; |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + function doUpgrade() { |
| 125 | + $conn = $this->getConnection(); |
| 126 | + if ( $conn instanceof Status ) { |
| 127 | + $this->parent->showStatusError( $conn ); |
| 128 | + return; |
| 129 | + } |
| 130 | + |
| 131 | + # Determine existing default character set |
| 132 | + if ( $conn->tableExists( "revision" ) ) { |
| 133 | + $revision = $conn->escapeLike( $this->getVar( 'wgDBprefix' ) . 'revision' ); |
| 134 | + $res = $conn->query( "SHOW TABLE STATUS LIKE '$revision'" ); |
| 135 | + $row = $conn->fetchObject( $res ); |
| 136 | + if ( !$row ) { |
| 137 | + $this->parent->showMessage( 'config-show-table-status' ); |
| 138 | + $existingSchema = false; |
| 139 | + $existingEngine = false; |
| 140 | + } else { |
| 141 | + if ( preg_match( '/^latin1/', $row->Collation ) ) { |
| 142 | + $existingSchema = 'mysql4'; |
| 143 | + } elseif ( preg_match( '/^utf8/', $row->Collation ) ) { |
| 144 | + $existingSchema = 'mysql5'; |
| 145 | + } elseif ( preg_match( '/^binary/', $row->Collation ) ) { |
| 146 | + $existingSchema = 'mysql5-binary'; |
| 147 | + } else { |
| 148 | + $existingSchema = false; |
| 149 | + $this->parent->showMessage( 'config-unknown-collation' ); |
| 150 | + } |
| 151 | + if ( isset( $row->Engine ) ) { |
| 152 | + $existingEngine = $row->Engine; |
| 153 | + } else { |
| 154 | + $existingEngine = $row->Type; |
| 155 | + } |
| 156 | + } |
| 157 | + } |
| 158 | + |
| 159 | + // TODO... |
| 160 | + return; |
| 161 | + |
| 162 | + # Create user if required |
| 163 | + if ( $conf->Root ) { |
| 164 | + $conn = $dbc->newFromParams( $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, 1 ); |
| 165 | + if ( $conn->isOpen() ) { |
| 166 | + print "<li>DB user account ok</li>\n"; |
| 167 | + $conn->close(); |
| 168 | + } else { |
| 169 | + print "<li>Granting user permissions..."; |
| 170 | + if( $mysqlOldClient && $mysqlNewAuth ) { |
| 171 | + print " <b class='error'>If the next step fails, see <a href='http://dev.mysql.com/doc/mysql/en/old-client.html'>http://dev.mysql.com/doc/mysql/en/old-client.html</a> for help.</b>"; |
| 172 | + } |
| 173 | + print "</li>\n"; |
| 174 | + dbsource( "../maintenance/users.sql", $conn ); |
| 175 | + } |
| 176 | + } |
| 177 | + } |
| 178 | + |
| 179 | + function getSettingsForm() { |
| 180 | + $installUser = $this->getVar( '_MysqlInstallUser' ); |
| 181 | + $installPass = $this->parent->getFakePassword( $this->getVar( '_MysqlInstallPassword' ) ); |
| 182 | + $js = 'disableControlArray( "mysql__MysqlSameAccount", ' . |
| 183 | + '["mysql_wgDBuser", "mysql_wgDBpassword"] )'; |
| 184 | + |
| 185 | + return |
| 186 | + Xml::openElement( 'fieldset' ) . |
| 187 | + Xml::element( 'legend', array(), wfMsg( 'config-db-web-account' ) ) . |
| 188 | + $this->getLabelledCheckBox( |
| 189 | + '_MysqlSameAccount', 'config-db-web-account-same', array( 'onclick' => $js ) |
| 190 | + ) . |
| 191 | + "<br/>\n" . |
| 192 | + $this->getLabelledTextBox( 'wgDBuser', 'config-db-username' ) . |
| 193 | + $this->getLabelledPasswordBox( 'wgDBpassword', 'config-db-password' ) . |
| 194 | + $this->parent->getHelpBox( 'config-db-web-help' ) . |
| 195 | + Xml::closeElement( 'fieldset' ) . |
| 196 | + "<script type=\"text/javascript\">$js</script>"; |
| 197 | + } |
| 198 | +} |
Property changes on: branches/new-installer/phase3/includes/installer/MysqlInstaller.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 199 | + native |
Index: branches/new-installer/phase3/includes/installer/PostgresInstaller.php |
— | — | @@ -0,0 +1,110 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class PostgresInstaller extends InstallerDBType { |
| 5 | + |
| 6 | + var $globalNames = array( |
| 7 | + 'wgDBserver', |
| 8 | + 'wgDBport', |
| 9 | + 'wgDBname', |
| 10 | + 'wgDBuser', |
| 11 | + 'wgDBpassword', |
| 12 | + 'wgDBmwschema', |
| 13 | + 'wgDBts2schema', |
| 14 | + ); |
| 15 | + |
| 16 | + var $internalDefaults = array( |
| 17 | + '_PostgresInstallUser' => 'postgres', |
| 18 | + '_PostgresInstallPassword' => '', |
| 19 | + ); |
| 20 | + |
| 21 | + var $minimumVersion = '8.1'; |
| 22 | + |
| 23 | + var $conn; |
| 24 | + |
| 25 | + function getName() { |
| 26 | + return 'postgres'; |
| 27 | + } |
| 28 | + |
| 29 | + function isCompiled() { |
| 30 | + return $this->checkExtension( 'pgsql' ); |
| 31 | + } |
| 32 | + |
| 33 | + function getGlobalNames() { |
| 34 | + return $this->globalNames; |
| 35 | + } |
| 36 | + |
| 37 | + function getInternalDefaults() { |
| 38 | + return $this->internalDefaults; |
| 39 | + } |
| 40 | + |
| 41 | + function getConnectForm() { |
| 42 | + return |
| 43 | + $this->getLabelledTextBox( 'wgDBserver', 'config-db-host' ) . |
| 44 | + $this->parent->getHelpBox( 'config-db-host-help' ) . |
| 45 | + $this->getLabelledTextBox( 'wgDBport', 'config-db-port' ) . |
| 46 | + Xml::openElement( 'fieldset' ) . |
| 47 | + Xml::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) . |
| 48 | + $this->getLabelledTextBox( 'wgDBname', 'config-db-name' ) . |
| 49 | + $this->parent->getHelpBox( 'config-db-name-help' ) . |
| 50 | + $this->getLabelledTextBox( 'wgDBmwschema', 'config-db-schema' ) . |
| 51 | + $this->getLabelledTextBox( 'wgDBts2schema', 'config-db-ts2-schema' ) . |
| 52 | + $this->parent->getHelpBox( 'config-db-schema-help' ) . |
| 53 | + Xml::closeElement( 'fieldset' ) . |
| 54 | + Xml::openElement( 'fieldset' ) . |
| 55 | + Xml::element( 'legend', array(), wfMsg( 'config-db-install-account' ) ) . |
| 56 | + $this->getLabelledTextBox( '_PostgresInstallUser', 'config-db-username' ) . |
| 57 | + $this->getLabelledPasswordBox( '_PostgresInstallPassword', 'config-db-password' ) . |
| 58 | + $this->parent->getHelpBox( 'config-db-install-help' ) . |
| 59 | + Xml::closeElement( 'fieldset' ); |
| 60 | + } |
| 61 | + |
| 62 | + function submitConnectForm() { |
| 63 | + // Get variables from the request |
| 64 | + $newValues = $this->setVarsFromRequest(); |
| 65 | + |
| 66 | + // Validate them |
| 67 | + $status = Status::newGood(); |
| 68 | + if ( !strlen( $newValues['wgDBname'] ) ) { |
| 69 | + $status->fatal( 'config-missing-db-name' ); |
| 70 | + } elseif ( !preg_match( '/^[a-zA-Z0-9_]+$/', $newValues['wgDBname'] ) ) { |
| 71 | + $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] ); |
| 72 | + } |
| 73 | + if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBmwschema'] ) ) { |
| 74 | + $status->fatal( 'config-invalid-schema', $newValues['wgDBmwschema'] ); |
| 75 | + } |
| 76 | + if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBts2schema'] ) ) { |
| 77 | + $status->fatal( 'config-invalid-ts2schema', $newValues['wgDBts2schema'] ); |
| 78 | + } |
| 79 | + |
| 80 | + // Try to connect |
| 81 | + if ( $status->isOK() ) { |
| 82 | + $status->merge( $this->attemptConnection() ); |
| 83 | + } |
| 84 | + if ( !$status->isOK() ) { |
| 85 | + return $status; |
| 86 | + } |
| 87 | + |
| 88 | + // Check version |
| 89 | + $version = $this->conn->getServerVersion(); |
| 90 | + if ( version_compare( $version, $this->minimumVersion ) < 0 ) { |
| 91 | + return Status::newFatal( 'config-postgres-old', $this->minimumVersion, $version ); |
| 92 | + } |
| 93 | + return $status; |
| 94 | + } |
| 95 | + |
| 96 | + function attemptConnection() { |
| 97 | + $status = Status::newGood(); |
| 98 | + |
| 99 | + try { |
| 100 | + $this->conn = new DatabasePostgres( |
| 101 | + $this->getVar( 'wgDBserver' ), |
| 102 | + $this->getVar( '_PostgresInstallUser' ), |
| 103 | + $this->getVar( '_PostgresInstallPassword' ), |
| 104 | + 'postgres' ); |
| 105 | + } catch ( DBConnectionError $e ) { |
| 106 | + $status->fatal( 'config-connection-error', $e->getMessage() ); |
| 107 | + } |
| 108 | + return $status; |
| 109 | + } |
| 110 | + |
| 111 | +} |
Property changes on: branches/new-installer/phase3/includes/installer/PostgresInstaller.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 112 | + native |
Index: branches/new-installer/phase3/includes/installer/InstallerDBType.php |
— | — | @@ -0,0 +1,163 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Base class for DBMS-specific installation helper classes |
| 6 | + */ |
| 7 | +abstract class InstallerDBType { |
| 8 | + /** The Installer object */ |
| 9 | + var $parent; |
| 10 | + |
| 11 | + /** |
| 12 | + * Construct and initialise parent. |
| 13 | + * This is typically only called from Installer::getDBInstaller() |
| 14 | + */ |
| 15 | + function __construct( $parent ) { |
| 16 | + $this->parent = $parent; |
| 17 | + } |
| 18 | + |
| 19 | + /** |
| 20 | + * Convenience function |
| 21 | + * Check if a named extension is present |
| 22 | + */ |
| 23 | + function checkExtension( $name ) { |
| 24 | + wfSuppressWarnings(); |
| 25 | + $compiled = extension_loaded( $name ) |
| 26 | + || ( $this->parent->haveDl() && dl( $name . '.' . PHP_SHLIB_SUFFIX ) ); |
| 27 | + wfRestoreWarnings(); |
| 28 | + return $compiled; |
| 29 | + } |
| 30 | + |
| 31 | + /** |
| 32 | + * Return the internal name, e.g. 'mysql', or 'sqlite' |
| 33 | + */ |
| 34 | + abstract function getName(); |
| 35 | + |
| 36 | + /** |
| 37 | + * Get the internationalised name for this DBMS |
| 38 | + */ |
| 39 | + function getReadableName() { |
| 40 | + return wfMsg( 'config-type-' . $this->getName() ); |
| 41 | + } |
| 42 | + |
| 43 | + /** |
| 44 | + * @return true if the client library is compiled in |
| 45 | + */ |
| 46 | + abstract function isCompiled(); |
| 47 | + |
| 48 | + /** |
| 49 | + * Get an array of MW configuration globals that will be configured by this class. |
| 50 | + */ |
| 51 | + abstract function getGlobalNames(); |
| 52 | + |
| 53 | + /** |
| 54 | + * Get a name=>value map of MW configuration globals that overrides |
| 55 | + * DefaultSettings.php |
| 56 | + */ |
| 57 | + function getGlobalDefaults() { |
| 58 | + return array(); |
| 59 | + } |
| 60 | + |
| 61 | + /** |
| 62 | + * Get a name=>value map of internal variables used during installation |
| 63 | + */ |
| 64 | + function getInternalDefaults() { |
| 65 | + return array(); |
| 66 | + } |
| 67 | + |
| 68 | + /** |
| 69 | + * Get HTML for a web form that configures this database |
| 70 | + * If this is called, $this->parent can be assumed to be a WebInstaller |
| 71 | + */ |
| 72 | + abstract function getConnectForm(); |
| 73 | + |
| 74 | + /** |
| 75 | + * Set variables based on the request array, assuming it was submitted |
| 76 | + * via the form returned by getConnectForm() |
| 77 | + * If this is called, $this->parent can be assumed to be a WebInstaller |
| 78 | + */ |
| 79 | + abstract function submitConnectForm(); |
| 80 | + |
| 81 | + /** |
| 82 | + * Get a variable, taking local defaults into account |
| 83 | + */ |
| 84 | + function getVar( $var, $default = null ) { |
| 85 | + $defaults = $this->getGlobalDefaults(); |
| 86 | + $internal = $this->getInternalDefaults(); |
| 87 | + if ( isset( $defaults[$var] ) ) { |
| 88 | + $default = $defaults[$var]; |
| 89 | + } elseif ( isset( $internal[$var] ) ) { |
| 90 | + $default = $internal[$var]; |
| 91 | + } |
| 92 | + return $this->parent->getVar( $var, $default ); |
| 93 | + } |
| 94 | + |
| 95 | + /** |
| 96 | + * Convenience function for a labelled text box to configure a variable |
| 97 | + */ |
| 98 | + function getLabelledTextBox( $var, $label ) { |
| 99 | + $name = $this->getName() . '_' . $var; |
| 100 | + $value = $this->getVar( $var ); |
| 101 | + return |
| 102 | + "<div class=\"config-input\">\n" . |
| 103 | + $this->parent->getLabel( $label, $name ) . |
| 104 | + $this->parent->getTextBox( $name, $value ) . |
| 105 | + "</div>\n"; |
| 106 | + } |
| 107 | + |
| 108 | + /** |
| 109 | + * Convenience function for a labelled password box. |
| 110 | + * Implements password hiding |
| 111 | + */ |
| 112 | + function getLabelledPasswordBox( $var, $label ) { |
| 113 | + $name = $this->getName() . '_' . $var; |
| 114 | + $realPassword = $this->getVar( $var ); |
| 115 | + if ( strlen( $var ) ) { |
| 116 | + $fakeValue = $this->parent->getFakePassword( $realPassword ); |
| 117 | + } else { |
| 118 | + $fakeValue = ''; |
| 119 | + } |
| 120 | + return |
| 121 | + "<div class=\"config-input\">\n" . |
| 122 | + $this->parent->getLabel( $label, $name ) . |
| 123 | + $this->parent->getTextBox( $name, $fakeValue, 'password' ) . |
| 124 | + "</div>\n"; |
| 125 | + } |
| 126 | + |
| 127 | + /** |
| 128 | + * Convenience function for a labelled checkbox |
| 129 | + */ |
| 130 | + function getLabelledCheckBox( $var, $label, $attribs = array() ) { |
| 131 | + $name = $this->getName() . '_' . $var; |
| 132 | + $value = $this->getVar( $var ); |
| 133 | + return |
| 134 | + "<div class=\"config-input-check\">\n" . |
| 135 | + "<label>\n" . |
| 136 | + $this->parent->getCheckBox( $name, $value, $attribs ) . "\n" . |
| 137 | + wfMsgHtml( $label ) . "\n" . |
| 138 | + "</label>\n" . |
| 139 | + "</div>\n"; |
| 140 | + } |
| 141 | + |
| 142 | + /** |
| 143 | + * Convenience function to set variables based on form data |
| 144 | + * Has some heuristics that may need to be overridden in child classes. |
| 145 | + */ |
| 146 | + function setVarsFromRequest() { |
| 147 | + $newValues = array(); |
| 148 | + $varNames = array_merge( $this->getGlobalNames(), |
| 149 | + array_keys( $this->getInternalDefaults() ) ); |
| 150 | + foreach ( $varNames as $name ) { |
| 151 | + $value = $this->parent->request->getVal( $this->getName() . '_' . $name ); |
| 152 | + $newValues[$name] = $value; |
| 153 | + if ( $value !== null ) { |
| 154 | + if ( stripos( $name, 'password' ) !== false ) { |
| 155 | + $this->parent->setPassword( $name, $value ); |
| 156 | + } else { |
| 157 | + $this->parent->setVar( $name, $value ); |
| 158 | + } |
| 159 | + } |
| 160 | + } |
| 161 | + return $newValues; |
| 162 | + } |
| 163 | +} |
| 164 | + |
Property changes on: branches/new-installer/phase3/includes/installer/InstallerDBType.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 165 | + native |
Index: branches/new-installer/phase3/includes/AutoLoader.php |
— | — | @@ -382,6 +382,16 @@ |
383 | 383 | 'RepoGroup' => 'includes/filerepo/RepoGroup.php', |
384 | 384 | 'UnregisteredLocalFile' => 'includes/filerepo/UnregisteredLocalFile.php', |
385 | 385 | |
| 386 | + # includes/installer |
| 387 | + 'Installer' => 'includes/installer/Installer.php', |
| 388 | + 'InstallerDBType' => 'includes/installer/InstallerDBType.php', |
| 389 | + 'LBFactory_InstallerFake' => 'includes/installer/Installer.php', |
| 390 | + 'WebInstaller' => 'includes/installer/WebInstaller.php', |
| 391 | + 'WebInstallerOutput' => 'includes/installer/WebInstallerOutput.php', |
| 392 | + 'MysqlInstaller' => 'includes/installer/MysqlInstaller.php', |
| 393 | + 'PostgresInstaller' => 'includes/installer/PostgresInstaller.php', |
| 394 | + 'SqliteInstaller' => 'includes/installer/SqliteInstaller.php', |
| 395 | + |
386 | 396 | # includes/media |
387 | 397 | 'BitmapHandler' => 'includes/media/Bitmap.php', |
388 | 398 | 'BitmapHandler_ClientOnly' => 'includes/media/Bitmap_ClientOnly.php', |
Index: branches/new-installer/phase3/config/new-index.php |
— | — | @@ -0,0 +1,35 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +define( 'MW_NO_DB', 1 ); |
| 5 | +define( 'MW_CONFIG_CALLBACK', 'wfInstallerConfig' ); |
| 6 | + |
| 7 | +function wfInstallerConfig() { |
| 8 | + $GLOBALS['wgUseDatabaseMessages'] = false; |
| 9 | + $GLOBALS['wgLBFactoryConf'] = array( 'class' => 'LBFactory_InstallerFake' ); |
| 10 | + $GLOBALS['wgShowExceptionDetails'] = true; |
| 11 | +} |
| 12 | + |
| 13 | +chdir( ".." ); |
| 14 | +require( './includes/WebStart.php' ); |
| 15 | + |
| 16 | +$installer = new WebInstaller( $wgRequest ); |
| 17 | + |
| 18 | +if ( !$installer->startSession() ) { |
| 19 | + $installer->finish(); |
| 20 | + exit; |
| 21 | +} |
| 22 | + |
| 23 | +$session = isset( $_SESSION['installData'] ) ? $_SESSION['installData'] : array(); |
| 24 | + |
| 25 | +if ( isset( $session['settings']['_UserLang'] ) ) { |
| 26 | + $langCode = $session['settings']['_UserLang']; |
| 27 | +} elseif ( !is_null( $wgRequest->getVal( 'UserLang' ) ) ) { |
| 28 | + $langCode = $wgRequest->getVal( 'UserLang' ); |
| 29 | +} else { |
| 30 | + $langCode = 'en'; |
| 31 | +} |
| 32 | +$wgLang = Language::factory( $langCode ); |
| 33 | + |
| 34 | +$session = $installer->execute( $session ); |
| 35 | +$_SESSION['installData'] = $session; |
| 36 | + |
Property changes on: branches/new-installer/phase3/config/new-index.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 37 | + native |
Index: branches/new-installer/phase3/languages/messages/MessagesEn.php |
— | — | @@ -3682,6 +3682,169 @@ |
3683 | 3683 | 'unknown_extension_tag' => 'Unknown extension tag "$1"', |
3684 | 3684 | 'duplicate-defaultsort' => 'Warning: Default sort key "$2" overrides earlier default sort key "$1".', |
3685 | 3685 | |
| 3686 | +# Installer |
| 3687 | +'config-session-error' => 'Error starting session: $1', |
| 3688 | +'config-session-expired' => 'Your session data seems to have expired. |
| 3689 | +Sessions are configured for a lifetime of $1, you can increase this by setting session.gc_maxlifetime in php.ini. |
| 3690 | +Please restart the installation process.', |
| 3691 | +'config-no-session' => 'Your session data was lost! |
| 3692 | +Please check your php.ini and make sure session.save_path is set to an appropriate directory.', |
| 3693 | +'config-your-language' => 'Your language:', |
| 3694 | +'config-your-language-help' => 'Select a language to use during the installation process', |
| 3695 | +'config-wiki-language' => 'Wiki language:', |
| 3696 | +'config-wiki-language-help' => 'Select the language that the wiki will predominantly be written in', |
| 3697 | +'config-back' => '< Back', |
| 3698 | +'config-continue' => 'Continue >', |
| 3699 | +'config-page-language' => 'Language', |
| 3700 | +'config-page-environment' => 'Environment', |
| 3701 | +'config-page-dbconnect' => 'Connect to DB', |
| 3702 | +'config-page-upgrade' => 'Upgrade existing', |
| 3703 | +'config-page-dbsettings' => 'DB settings', |
| 3704 | +'config-page-identity' => 'Identity', |
| 3705 | +'config-page-license' => 'License', |
| 3706 | +'config-page-email' => 'Email', |
| 3707 | +'config-page-install' => 'Install', |
| 3708 | +'config-page-complete' => 'Complete!', |
| 3709 | +'config-page-restart' => 'Restart installation', |
| 3710 | +'config-help-restart' => 'Do you want to clear all saved data that you have entered, and restart the installation process?', |
| 3711 | +'config-restart' => 'Yes, restart it', |
| 3712 | + |
| 3713 | +'config-env-good' => '<span class="success-message">Environment checked. You can install MediaWiki.</span>', |
| 3714 | +'config-env-bad' => 'Cannot install MediaWiki.', |
| 3715 | +'config-env-php' => 'PHP $1 installed', |
| 3716 | +'config-no-db' => 'Could not find a suitable database driver!', |
| 3717 | +'config-no-db-help' => 'You need to install a database driver for PHP. |
| 3718 | +The following database types are supported: $1. |
| 3719 | +If you are on shared hosting, ask your hosting provider to install a suitable database driver. |
| 3720 | +If you compiled PHP yourself, reconfigure it with a database client enabled, for example using the ./configure --with-mysql. |
| 3721 | +If you installed PHP from a Debian or Ubuntu package, then you also need install the php5-mysql module.', |
| 3722 | +'config-have-db' => 'Found database drivers for: $1', |
| 3723 | +'config-register-globals' => '<strong class="error">Warning:</strong> |
| 3724 | +<strong>PHP\'s <tt>[http://php.net/register_globals register_globals]</tt> option is enabled. Disable it if you can.</strong> |
| 3725 | +MediaWiki will work, but your server is more exposed to PHP-based security vulnerabilities.', |
| 3726 | +'config-magic-quotes-runtime' => '<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] is active!</strong> |
| 3727 | +This option corrupts data input unpredictably; you cannot install or use MediaWiki unless this option is disabled.', |
| 3728 | +'config-magic-quotes-sybase' => '<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] is active!</strong> |
| 3729 | +This option corrupts data input unpredictably; you cannot install or use MediaWiki unless this option is disabled.', |
| 3730 | +'config-mbstring' => '<strong>Fatal: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] is active!</strong> |
| 3731 | +This option causes errors and may corrupt data unpredictably; you cannot install or use MediaWiki unless this option is disabled.', |
| 3732 | +'config-ze1' => '<strong>Fatal: [http://www.php.net/manual/en/ini.core.php zend.ze1_compatibility_mode] is active!</strong> |
| 3733 | +This option causes horrible bugs with MediaWiki; you cannot install or use MediaWiki unless this option is disabled.', |
| 3734 | +'config-safe-mode' => '<b class="error">Warning:</b> |
| 3735 | +<strong>PHP\'s [http://www.php.net/features.safe-mode safe mode] is active.</strong> |
| 3736 | +You may have problems caused by this, particularly if using image uploads.', |
| 3737 | +'config-xml-good' => 'Have XML / Latin1-UTF-8 conversion support.', |
| 3738 | +'config-xml-bad' => 'PHP\'s XML module is missing; |
| 3739 | +the wiki requires functions in this module and won\'t work in this configuration. |
| 3740 | +If you\'re running Mandrake, install the php-xml package.', |
| 3741 | +'config-pcre' => 'The PCRE support module appears to be missing. |
| 3742 | +MediaWiki requires the Perl-compatible regular expression functions.', |
| 3743 | +'config-memory-none' => 'PHP is configured with no <tt>memory_limit</tt>', |
| 3744 | +'config-memory-ok' => 'PHP\'s <tt>memory_limit</tt> is $1, ok.', |
| 3745 | +'config-memory-raised' => 'PHP\'s <tt>memory_limit</tt> is $1, raised to $2.', |
| 3746 | +'config-memory-bad' => '<strong>Warning:</strong> PHP\'s <tt>memory_limit</tt> is $1. |
| 3747 | +This is probably too low, the installation may fail!', |
| 3748 | +'config-turck' => '[http://turck-mmcache.sourceforge.net/ Turck MMCache] installed</li>', |
| 3749 | +'config-xcache' => '[http://trac.lighttpd.net/xcache/ XCache] installed', |
| 3750 | +'config-apc' => '[http://www.php.net/apc APC] installed', |
| 3751 | +'config-eaccel' => '[http://eaccelerator.sourceforge.net/ eAccelerator] installed', |
| 3752 | +'config-no-cache' => '<strong>Warning:</strong> |
| 3753 | +Couldn\'t find [http://turck-mmcache.sourceforge.net Turck MMCache], |
| 3754 | +[http://eaccelerator.sourceforge.net eAccelerator], |
| 3755 | +[http://www.php.net/apc APC] or [http://trac.lighttpd.net/xcache/ XCache]; |
| 3756 | +cannot use these for object caching.', |
| 3757 | +'config-diff3-good' => 'Found GNU diff3: <tt>$1</tt>.', |
| 3758 | +'config-diff3-bad' => 'GNU diff3 not found.', |
| 3759 | +'config-imagemagick' => 'Found ImageMagick: <tt>$1</tt>; image thumbnailing will be enabled if you enable uploads.', |
| 3760 | +'config-gd' => 'Found GD graphics library built-in, image thumbnailing will be enabled if you enable uploads.', |
| 3761 | +'config-no-scaling' => 'Couldn\'t find GD library or ImageMagick; image thumbnailing disabled.', |
| 3762 | +'config-dir' => 'Installation directory: <tt>$1</tt>', |
| 3763 | +'config-uri' => 'Script URI path: <tt>$1</tt>', |
| 3764 | +'config-no-uri' => '<strong>Error:</strong> Could not determine the current URI. Installation aborted.', |
| 3765 | +'config-extension' => 'Installing MediaWiki with <tt>$1</tt> file extensions', |
| 3766 | + |
| 3767 | +'config-db-type' => 'DB type:', |
| 3768 | +'config-db-host' => 'DB host:', |
| 3769 | +'config-db-host-help' => 'If your database server isn\'t on your web server, enter the name or IP address here. |
| 3770 | +If you are using a shared web host, your hosting provider should give you the correct host name in their documentation.', |
| 3771 | +'config-db-wiki-settings' => 'Identify this wiki', |
| 3772 | +'config-db-name' => 'DB name:', |
| 3773 | +'config-db-name-help' => 'Choose a name that identifies your wiki. It should not contain spaces or hyphens. |
| 3774 | +If you are using a shared host, your hosting provider will either give you a specific database name to use, or let you create databases via a control panel.', |
| 3775 | +'config-db-install-account' => 'User account for installation', |
| 3776 | +'config-db-username' => 'DB username:', |
| 3777 | +'config-db-password' => 'DB password:', |
| 3778 | +'config-db-install-help' => 'Select the username and password that will be used to connect to the database during the installation process.', |
| 3779 | +'config-db-account-lock' => 'Use the same username and password during normal operation', |
| 3780 | +'config-db-wiki-account' => 'User account for normal operation', |
| 3781 | +'config-db-wiki-help' => 'Select the username and password that will be used to connect to the database during normal wiki operation. |
| 3782 | +If the account does not exist, and the installation account has sufficient privileges, this user account will be created with the minimum privileges required to operate the wiki.', |
| 3783 | +'config-db-prefix' => 'DB table prefix:', |
| 3784 | +'config-db-prefix-help' => 'If you need to share one database between multiple wikis, or between MediaWiki and another web application, you may choose to add a prefix to all the table names to avoid conflicts. |
| 3785 | +Do not use spaces or hyphens. |
| 3786 | + |
| 3787 | +This may normally be left blank.', |
| 3788 | +'config-db-charset' => 'DB character set', |
| 3789 | +'config-charset-mysql5-binary' => 'MySQL 4.1/5.0 binary', |
| 3790 | +'config-charset-mysql5' => 'MySQL 4.1/5.0 UTF-8', |
| 3791 | +'config-charset-mysql4' => 'MySQL 4.0 backwards-compatible UTF-8', |
| 3792 | +'config-charset-help' => '<b>WARNING:</b> If you use <b>backwards-compatible UTF-8</b> on MySQL 4.1+, and subsequently back up the database with <tt>mysqldump</tt>, it may destroy all non-ASCII characters, irreversibly corrupting your backups!. |
| 3793 | +<br/><br/> |
| 3794 | +In <b>binary mode</b>, MediaWiki stores UTF-8 text to the database in binary fields. This is more efficient than MySQL\'s UTF-8 mode, and allows you to use the full range of Unicode characters. In <b>UTF-8 mode</b>, MySQL will know what character set your data is in, and can present and convert it appropriately, but it won\'t let you store characters above the [http://en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Basic Multilingual Plane]. |
| 3795 | +', |
| 3796 | +'config-mysql-old' => 'MySQL $1 or later is required, you have $2.', |
| 3797 | +'config-db-port' => 'DB port:', |
| 3798 | +'config-db-schema' => 'Schema for MediaWiki', |
| 3799 | +'config-db-ts2-schema' => 'Schema for tsearch2', |
| 3800 | +'config-db-schema-help' => 'The above schemas are generally correct, only change them if you are sure you need to.', |
| 3801 | +'config-sqlite-dir' => 'SQLite data directory:', |
| 3802 | +'config-sqlite-dir-help' => 'SQLite stores table data into files in the filesystem. |
| 3803 | +This directory must be writable by the webserver. |
| 3804 | +It should <strong>not</strong> accessible via the web.', |
| 3805 | +'config-type-mysql' => 'MySQL', |
| 3806 | +'config-type-postgres' => 'PostgreSQL', |
| 3807 | +'config-type-sqlite' => 'SQLite', |
| 3808 | +'config-header-mysql' => 'MySQL settings', |
| 3809 | +'config-header-postgres' => 'PostgreSQL settings', |
| 3810 | +'config-header-sqlite' => 'SQLite settings', |
| 3811 | +'config-invalid-db-type' => 'Invalid DB type', |
| 3812 | +'config-missing-db-name' => 'You must enter a value for "DB name"', |
| 3813 | +'config-invalid-db-name' => 'Invalid DB name "$1". It may only contain numbers, letters and underscores.', |
| 3814 | +'config-invalid-db-prefix' => 'Invalid DB prefix "$1". It may only contain numbers, letters and underscores.', |
| 3815 | +'config-connection-error' => '$1. |
| 3816 | + |
| 3817 | +Check the host, username and password below and try again.', |
| 3818 | +'config-invalid-schema' => 'Invalid schema for MediaWiki "$1". Please use only letters, numbers and underscores.', |
| 3819 | +'config-invalid-ts2schema' => 'Invalid schema for tsearch2 "$1". Please use only letters, numbers and underscores.', |
| 3820 | +'config-postgres-old' => 'Postgres $1 or later is required, you have $2.', |
| 3821 | +'config-sqlite-name-help' => 'Choose a name that identifies your wiki. Do not use spaces or hyphens. This will be used for the SQLite data file name.', |
| 3822 | +'config-sqlite-parent-unwritable' => 'Cannot create the data directory "$1", because the parent directory "$2" is not writable by the webserver. Please create this directory yourself, make it writable, and try again.', |
| 3823 | +'config-sqlite-mkdir-error' => 'Error creating the data directory "$1". Please check the location and try again.', |
| 3824 | +'config-sqlite-unwritable' => 'Unable to write to the directory specified: $1. Please change its permissions so that the webserver can write to it, and try again.', |
| 3825 | +'config-sqlite-connection-error' => '$1. |
| 3826 | + |
| 3827 | +Check the data directory and DB name below and try again.', |
| 3828 | +'config-can-upgrade' => 'There are MediaWiki tables in this database. |
| 3829 | +To upgrade them to MediaWiki $1, click <strong>Continue</strong>.', |
| 3830 | +'config-upgrade-done' => 'Upgrade complete. |
| 3831 | + |
| 3832 | +You can now [$1 start using your wiki]. |
| 3833 | + |
| 3834 | +If you want to regenerate your LocalSettings.php file, click the button below. |
| 3835 | +This is <strong>not recommended</strong> unless you are having problems with your wiki. |
| 3836 | +', |
| 3837 | +'config-regenerate' => 'Regenerate LocalSettings.php >', |
| 3838 | +'config-show-table-status' => 'SHOW TABLE STATUS query failed!', |
| 3839 | +'config-unknown-collation' => '<strong>Warning:</strong> Unrecognised existing collation', |
| 3840 | + |
| 3841 | +'config-db-web-account' => 'DB account for web access', |
| 3842 | +'config-db-web-help' => 'Select the username and password that the web server will use to connect to the database server, during ordinary operation of the wiki. |
| 3843 | + |
| 3844 | +If the account specified does not exist, the installer will attempt to create it. |
| 3845 | +', |
| 3846 | +'config-db-web-account-same' => 'Use the same account as for installation', |
| 3847 | + |
| 3848 | + |
3686 | 3849 | # Special:Version |
3687 | 3850 | 'version' => 'Version', # Not used as normal message but as header for the special page itself |
3688 | 3851 | 'version-extensions' => 'Installed extensions', |