Merge "StringUtils: Add a utility for checking if a string is a valid regex"
[lhc/web/wiklou.git] / includes / installer / Installer.php
index f6a5c41..b830b70 100644 (file)
@@ -105,8 +105,6 @@ abstract class Installer {
        protected static $dbTypes = [
                'mysql',
                'postgres',
-               'oracle',
-               'mssql',
                'sqlite',
        ];
 
@@ -733,6 +731,7 @@ abstract class Installer {
                if ( !$status->isOK() ) {
                        return $status;
                }
+               // @phan-suppress-next-line PhanUndeclaredMethod
                $status->value->insert(
                        'site_stats',
                        [
@@ -756,11 +755,12 @@ abstract class Installer {
         */
        protected function envCheckDB() {
                global $wgLang;
+               /** @var string|null $dbType The user-specified database type */
+               $dbType = $this->getVar( 'wgDBtype' );
 
                $allNames = [];
 
-               // Messages: config-type-mysql, config-type-postgres, config-type-oracle,
-               // config-type-sqlite
+               // Messages: config-type-mysql, config-type-postgres, config-type-sqlite
                foreach ( self::getDBTypes() as $name ) {
                        $allNames[] = wfMessage( "config-type-$name" )->text();
                }
@@ -768,25 +768,27 @@ abstract class Installer {
                $databases = $this->getCompiledDBs();
 
                $databases = array_flip( $databases );
+               $ok = true;
                foreach ( array_keys( $databases ) as $db ) {
                        $installer = $this->getDBInstaller( $db );
                        $status = $installer->checkPrerequisites();
                        if ( !$status->isGood() ) {
+                               if ( !$this instanceof WebInstaller && $db === $dbType ) {
+                                       // Strictly check the key database type instead of just outputting message
+                                       // Note: No perform this check run from the web installer, since this method always called by
+                                       // the welcome page under web installation, so $dbType will always be 'mysql'
+                                       $ok = false;
+                               }
                                $this->showStatusMessage( $status );
-                       }
-                       if ( !$status->isOK() ) {
                                unset( $databases[$db] );
                        }
                }
                $databases = array_flip( $databases );
                if ( !$databases ) {
                        $this->showError( 'config-no-db', $wgLang->commaList( $allNames ), count( $allNames ) );
-
-                       // @todo FIXME: This only works for the web installer!
                        return false;
                }
-
-               return true;
+               return $ok;
        }
 
        /**
@@ -1087,14 +1089,16 @@ abstract class Installer {
 
        /**
         * Checks if suhosin.get.max_value_length is set, and if so generate
-        * a warning because it decreases ResourceLoader performance.
+        * a warning because it is incompatible with ResourceLoader.
         * @return bool
         */
        protected function envCheckSuhosinMaxValueLength() {
-               $maxValueLength = ini_get( 'suhosin.get.max_value_length' );
-               if ( $maxValueLength > 0 && $maxValueLength < 1024 ) {
-                       // Only warn if the value is below the sane 1024
-                       $this->showMessage( 'config-suhosin-max-value-length', $maxValueLength );
+               $currentValue = ini_get( 'suhosin.get.max_value_length' );
+               $minRequired = 2000;
+               $recommended = 5000;
+               if ( $currentValue > 0 && $currentValue < $minRequired ) {
+                       $this->showError( 'config-suhosin-max-value-length', $currentValue, $minRequired, $recommended );
+                       return false;
                }
 
                return true;
@@ -1269,7 +1273,8 @@ abstract class Installer {
         *
         * @param string $directory Directory to search in, relative to $IP, must be either "extensions"
         *     or "skins"
-        * @return array [ $extName => [ 'screenshots' => [ '...' ] ]
+        * @return Status An object containing an error list. If there were no errors, an associative
+        *     array of information about the extension can be found in $status->value.
         */
        public function findExtensions( $directory = 'extensions' ) {
                switch ( $directory ) {
@@ -1288,33 +1293,43 @@ abstract class Installer {
         *
         * @param string $type Either "extension" or "skin"
         * @param string $directory Directory to search in, relative to $IP
-        * @return array [ $extName => [ 'screenshots' => [ '...' ] ]
+        * @return Status An object containing an error list. If there were no errors, an associative
+        *     array of information about the extension can be found in $status->value.
         */
        protected function findExtensionsByType( $type = 'extension', $directory = 'extensions' ) {
                if ( $this->getVar( 'IP' ) === null ) {
-                       return [];
+                       return Status::newGood( [] );
                }
 
                $extDir = $this->getVar( 'IP' ) . '/' . $directory;
                if ( !is_readable( $extDir ) || !is_dir( $extDir ) ) {
-                       return [];
+                       return Status::newGood( [] );
                }
 
                $dh = opendir( $extDir );
                $exts = [];
+               $status = new Status;
                while ( ( $file = readdir( $dh ) ) !== false ) {
-                       if ( !is_dir( "$extDir/$file" ) ) {
+                       // skip non-dirs and hidden directories
+                       if ( !is_dir( "$extDir/$file" ) || $file[0] === '.' ) {
                                continue;
                        }
-                       $status = $this->getExtensionInfo( $type, $directory, $file );
-                       if ( $status->isOK() ) {
-                               $exts[$file] = $status->value;
+                       $extStatus = $this->getExtensionInfo( $type, $directory, $file );
+                       if ( $extStatus->isOK() ) {
+                               $exts[$file] = $extStatus->value;
+                       } elseif ( $extStatus->hasMessage( 'config-extension-not-found' ) ) {
+                               // (T225512) The directory is not actually an extension. Downgrade to warning.
+                               $status->warning( 'config-extension-not-found', $file );
+                       } else {
+                               $status->merge( $extStatus );
                        }
                }
                closedir( $dh );
                uksort( $exts, 'strnatcasecmp' );
 
-               return $exts;
+               $status->value = $exts;
+
+               return $status;
        }
 
        /**
@@ -1415,11 +1430,16 @@ abstract class Installer {
                        } elseif ( $e->missingExtensions || $e->missingSkins ) {
                                // There's an extension missing in the dependency tree,
                                // so add those to the dependency list and try again
-                               return $this->readExtension(
+                               $status = $this->readExtension(
                                        $fullJsonFile,
                                        array_merge( $extDeps, $e->missingExtensions ),
                                        array_merge( $skinDeps, $e->missingSkins )
                                );
+                               if ( !$status->isOK() && !$status->hasMessage( 'config-extension-dependency' ) ) {
+                                       $status = Status::newFatal( 'config-extension-dependency',
+                                               basename( dirname( $fullJsonFile ) ), $status->getMessage() );
+                               }
+                               return $status;
                        }
                        // Some other kind of dependency error?
                        return Status::newFatal( 'config-extension-dependency',
@@ -1586,7 +1606,7 @@ abstract class Installer {
         * @param callable $startCB A callback array for the beginning of each step
         * @param callable $endCB A callback array for the end of each step
         *
-        * @return array Array of Status objects
+        * @return Status[] Array of Status objects
         */
        public function performInstallation( $startCB, $endCB ) {
                $installResults = [];
@@ -1606,11 +1626,11 @@ abstract class Installer {
 
                        // If we've hit some sort of fatal, we need to bail.
                        // Callback already had a chance to do output above.
-                       if ( !$status->isOk() ) {
+                       if ( !$status->isOK() ) {
                                break;
                        }
                }
-               if ( $status->isOk() ) {
+               if ( $status->isOK() ) {
                        $this->showMessage(
                                'config-install-db-success'
                        );