MediaWiki  REL1_22
SqliteInstaller.php
Go to the documentation of this file.
00001 <?php
00030 class SqliteInstaller extends DatabaseInstaller {
00031     const MINIMUM_VERSION = '3.3.7';
00032 
00036     public $db;
00037 
00038     protected $globalNames = array(
00039         'wgDBname',
00040         'wgSQLiteDataDir',
00041     );
00042 
00043     public function getName() {
00044         return 'sqlite';
00045     }
00046 
00047     public function isCompiled() {
00048         return self::checkExtension( 'pdo_sqlite' );
00049     }
00050 
00055     public function checkPrerequisites() {
00056         $result = Status::newGood();
00057         // Bail out if SQLite is too old
00058         $db = new DatabaseSqliteStandalone( ':memory:' );
00059         if ( version_compare( $db->getServerVersion(), self::MINIMUM_VERSION, '<' ) ) {
00060             $result->fatal( 'config-outdated-sqlite', $db->getServerVersion(), self::MINIMUM_VERSION );
00061         }
00062         // Check for FTS3 full-text search module
00063         if ( DatabaseSqlite::getFulltextSearchModule() != 'FTS3' ) {
00064             $result->warning( 'config-no-fts3' );
00065         }
00066 
00067         return $result;
00068     }
00069 
00070     public function getGlobalDefaults() {
00071         if ( isset( $_SERVER['DOCUMENT_ROOT'] ) ) {
00072             $path = str_replace(
00073                 array( '/', '\\' ),
00074                 DIRECTORY_SEPARATOR,
00075                 dirname( $_SERVER['DOCUMENT_ROOT'] ) . '/data'
00076             );
00077 
00078             return array( 'wgSQLiteDataDir' => $path );
00079         } else {
00080             return array();
00081         }
00082     }
00083 
00084     public function getConnectForm() {
00085         return $this->getTextBox(
00086             'wgSQLiteDataDir',
00087             'config-sqlite-dir', array(),
00088             $this->parent->getHelpBox( 'config-sqlite-dir-help' )
00089         ) .
00090         $this->getTextBox(
00091             'wgDBname',
00092             'config-db-name',
00093             array(),
00094             $this->parent->getHelpBox( 'config-sqlite-name-help' )
00095         );
00096     }
00097 
00105     private static function realpath( $path ) {
00106         $result = realpath( $path );
00107         if ( !$result ) {
00108             return $path;
00109         }
00110 
00111         return $result;
00112     }
00113 
00117     public function submitConnectForm() {
00118         $this->setVarsFromRequest( array( 'wgSQLiteDataDir', 'wgDBname' ) );
00119 
00120         # Try realpath() if the directory already exists
00121         $dir = self::realpath( $this->getVar( 'wgSQLiteDataDir' ) );
00122         $result = self::dataDirOKmaybeCreate( $dir, true /* create? */ );
00123         if ( $result->isOK() ) {
00124             # Try expanding again in case we've just created it
00125             $dir = self::realpath( $dir );
00126             $this->setVar( 'wgSQLiteDataDir', $dir );
00127         }
00128         # Table prefix is not used on SQLite, keep it empty
00129         $this->setVar( 'wgDBprefix', '' );
00130 
00131         return $result;
00132     }
00133 
00139     private static function dataDirOKmaybeCreate( $dir, $create = false ) {
00140         if ( !is_dir( $dir ) ) {
00141             if ( !is_writable( dirname( $dir ) ) ) {
00142                 $webserverGroup = Installer::maybeGetWebserverPrimaryGroup();
00143                 if ( $webserverGroup !== null ) {
00144                     return Status::newFatal(
00145                         'config-sqlite-parent-unwritable-group',
00146                         $dir, dirname( $dir ), basename( $dir ),
00147                         $webserverGroup
00148                     );
00149                 } else {
00150                     return Status::newFatal(
00151                         'config-sqlite-parent-unwritable-nogroup',
00152                         $dir, dirname( $dir ), basename( $dir )
00153                     );
00154                 }
00155             }
00156 
00157             # Called early on in the installer, later we just want to sanity check
00158             # if it's still writable
00159             if ( $create ) {
00160                 wfSuppressWarnings();
00161                 $ok = wfMkdirParents( $dir, 0700, __METHOD__ );
00162                 wfRestoreWarnings();
00163                 if ( !$ok ) {
00164                     return Status::newFatal( 'config-sqlite-mkdir-error', $dir );
00165                 }
00166                 # Put a .htaccess file in in case the user didn't take our advice
00167                 file_put_contents( "$dir/.htaccess", "Deny from all\n" );
00168             }
00169         }
00170         if ( !is_writable( $dir ) ) {
00171             return Status::newFatal( 'config-sqlite-dir-unwritable', $dir );
00172         }
00173 
00174         # We haven't blown up yet, fall through
00175         return Status::newGood();
00176     }
00177 
00181     public function openConnection() {
00182         global $wgSQLiteDataDir;
00183 
00184         $status = Status::newGood();
00185         $dir = $this->getVar( 'wgSQLiteDataDir' );
00186         $dbName = $this->getVar( 'wgDBname' );
00187         try {
00188             # @todo FIXME: Need more sensible constructor parameters, e.g. single associative array
00189             # Setting globals kind of sucks
00190             $wgSQLiteDataDir = $dir;
00191             $db = new DatabaseSqlite( false, false, false, $dbName );
00192             $status->value = $db;
00193         } catch ( DBConnectionError $e ) {
00194             $status->fatal( 'config-sqlite-connection-error', $e->getMessage() );
00195         }
00196 
00197         return $status;
00198     }
00199 
00203     public function needsUpgrade() {
00204         $dir = $this->getVar( 'wgSQLiteDataDir' );
00205         $dbName = $this->getVar( 'wgDBname' );
00206         // Don't create the data file yet
00207         if ( !file_exists( DatabaseSqlite::generateFileName( $dir, $dbName ) ) ) {
00208             return false;
00209         }
00210 
00211         // If the data file exists, look inside it
00212         return parent::needsUpgrade();
00213     }
00214 
00218     public function setupDatabase() {
00219         $dir = $this->getVar( 'wgSQLiteDataDir' );
00220 
00221         # Sanity check. We checked this before but maybe someone deleted the
00222         # data dir between then and now
00223         $dir_status = self::dataDirOKmaybeCreate( $dir, false /* create? */ );
00224         if ( !$dir_status->isOK() ) {
00225             return $dir_status;
00226         }
00227 
00228         $db = $this->getVar( 'wgDBname' );
00229         $file = DatabaseSqlite::generateFileName( $dir, $db );
00230         if ( file_exists( $file ) ) {
00231             if ( !is_writable( $file ) ) {
00232                 return Status::newFatal( 'config-sqlite-readonly', $file );
00233             }
00234         } else {
00235             if ( file_put_contents( $file, '' ) === false ) {
00236                 return Status::newFatal( 'config-sqlite-cant-create-db', $file );
00237             }
00238         }
00239         // nuke the unused settings for clarity
00240         $this->setVar( 'wgDBserver', '' );
00241         $this->setVar( 'wgDBuser', '' );
00242         $this->setVar( 'wgDBpassword', '' );
00243         $this->setupSchemaVars();
00244 
00245         return $this->getConnection();
00246     }
00247 
00251     public function createTables() {
00252         $status = parent::createTables();
00253 
00254         return $this->setupSearchIndex( $status );
00255     }
00256 
00261     public function setupSearchIndex( &$status ) {
00262         global $IP;
00263 
00264         $module = DatabaseSqlite::getFulltextSearchModule();
00265         $fts3tTable = $this->db->checkForEnabledSearch();
00266         if ( $fts3tTable && !$module ) {
00267             $status->warning( 'config-sqlite-fts3-downgrade' );
00268             $this->db->sourceFile( "$IP/maintenance/sqlite/archives/searchindex-no-fts.sql" );
00269         } elseif ( !$fts3tTable && $module == 'FTS3' ) {
00270             $this->db->sourceFile( "$IP/maintenance/sqlite/archives/searchindex-fts3.sql" );
00271         }
00272 
00273         return $status;
00274     }
00275 
00279     public function getLocalSettings() {
00280         $dir = LocalSettingsGenerator::escapePhpString( $this->getVar( 'wgSQLiteDataDir' ) );
00281 
00282         return "# SQLite-specific settings
00283 \$wgSQLiteDataDir = \"{$dir}\";";
00284     }
00285 }