Make supported DBs configurable within config.phptags/v8.0.0alpha1
@@ -807,6 +807,23 @@ $CONFIG = array( | |||
), | |||
), | |||
/** | |||
* Database types that are supported for installation | |||
* Available: | |||
* - sqlite (SQLite3) | |||
* - mysql (MySQL) | |||
* - pgsql (PostgreSQL) | |||
* - oci (Oracle) | |||
* - mssql (Microsoft SQL Server) | |||
*/ | |||
'supportedDatabases' => array( | |||
'sqlite', | |||
'mysql', | |||
'pgsql', | |||
'oci', | |||
'mssql' | |||
), | |||
/** | |||
* Custom CSP policy, changing this will overwrite the standard policy | |||
*/ |
@@ -1,6 +1,7 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl> | |||
* Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
@@ -8,7 +9,19 @@ | |||
namespace OC\Core\Setup; | |||
use OCP\IConfig; | |||
class Controller { | |||
/** @var \OCP\IConfig */ | |||
protected $config; | |||
/** | |||
* @param IConfig $config | |||
*/ | |||
function __construct(IConfig $config) { | |||
$this->config = $config; | |||
} | |||
public function run($post) { | |||
// Check for autosetup: | |||
$post = $this->loadAutoConfig($post); | |||
@@ -87,28 +100,10 @@ class Controller { | |||
* in case of errors/warnings | |||
*/ | |||
public function getSystemInfo() { | |||
$hasSQLite = class_exists('SQLite3'); | |||
$hasMySQL = is_callable('mysql_connect'); | |||
$hasPostgreSQL = is_callable('pg_connect'); | |||
$hasOracle = is_callable('oci_connect'); | |||
$hasMSSQL = is_callable('sqlsrv_connect'); | |||
$databases = array(); | |||
if ($hasSQLite) { | |||
$databases['sqlite'] = 'SQLite'; | |||
} | |||
if ($hasMySQL) { | |||
$databases['mysql'] = 'MySQL/MariaDB'; | |||
} | |||
if ($hasPostgreSQL) { | |||
$databases['pgsql'] = 'PostgreSQL'; | |||
} | |||
if ($hasOracle) { | |||
$databases['oci'] = 'Oracle'; | |||
} | |||
if ($hasMSSQL) { | |||
$databases['mssql'] = 'MS SQL'; | |||
} | |||
$datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data'); | |||
$setup = new \OC_Setup($this->config); | |||
$databases = $setup->getSupportedDatabases(); | |||
$dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data'); | |||
$vulnerableToNullByte = false; | |||
if(@file_exists(__FILE__."\0Nullbyte")) { // Check if the used PHP version is vulnerable to the NULL Byte attack (CVE-2006-7243) | |||
$vulnerableToNullByte = true; | |||
@@ -119,25 +114,25 @@ class Controller { | |||
// Create data directory to test whether the .htaccess works | |||
// Notice that this is not necessarily the same data directory as the one | |||
// that will effectively be used. | |||
@mkdir($datadir); | |||
if (is_dir($datadir) && is_writable($datadir)) { | |||
@mkdir($dataDir); | |||
$htAccessWorking = true; | |||
if (is_dir($dataDir) && is_writable($dataDir)) { | |||
// Protect data directory here, so we can test if the protection is working | |||
\OC_Setup::protectDataDirectory(); | |||
try { | |||
$htaccessWorking = \OC_Util::isHtaccessWorking(); | |||
$htAccessWorking = \OC_Util::isHtaccessWorking(); | |||
} catch (\OC\HintException $e) { | |||
$errors[] = array( | |||
'error' => $e->getMessage(), | |||
'hint' => $e->getHint() | |||
); | |||
$htaccessWorking = false; | |||
$htAccessWorking = false; | |||
} | |||
} | |||
if (\OC_Util::runningOnMac()) { | |||
$l10n = \OC::$server->getL10N('core'); | |||
$themeName = \OC_Util::getTheme(); | |||
$theme = new \OC_Defaults(); | |||
$errors[] = array( | |||
'error' => $l10n->t( | |||
@@ -150,14 +145,14 @@ class Controller { | |||
} | |||
return array( | |||
'hasSQLite' => $hasSQLite, | |||
'hasMySQL' => $hasMySQL, | |||
'hasPostgreSQL' => $hasPostgreSQL, | |||
'hasOracle' => $hasOracle, | |||
'hasMSSQL' => $hasMSSQL, | |||
'hasSQLite' => isset($databases['sqlite']), | |||
'hasMySQL' => isset($databases['mysql']), | |||
'hasPostgreSQL' => isset($databases['postgre']), | |||
'hasOracle' => isset($databases['oci']), | |||
'hasMSSQL' => isset($databases['mssql']), | |||
'databases' => $databases, | |||
'directory' => $datadir, | |||
'htaccessWorking' => $htaccessWorking, | |||
'directory' => $dataDir, | |||
'htaccessWorking' => $htAccessWorking, | |||
'vulnerableToNullByte' => $vulnerableToNullByte, | |||
'errors' => $errors, | |||
); |
@@ -717,7 +717,7 @@ class OC { | |||
// Check if ownCloud is installed or in maintenance (update) mode | |||
if (!OC_Config::getValue('installed', false)) { | |||
$controller = new OC\Core\Setup\Controller(); | |||
$controller = new OC\Core\Setup\Controller(\OC::$server->getConfig()); | |||
$controller->run($_POST); | |||
exit(); | |||
} |
@@ -1,9 +1,27 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
use OCP\IConfig; | |||
class DatabaseSetupException extends \OC\HintException { | |||
} | |||
class OC_Setup { | |||
/** @var IConfig */ | |||
protected $config; | |||
/** | |||
* @param IConfig $config | |||
*/ | |||
function __construct(IConfig $config) { | |||
$this->config = $config; | |||
} | |||
static $dbSetupClasses = array( | |||
'mysql' => '\OC\Setup\MySQL', | |||
'pgsql' => '\OC\Setup\PostgreSQL', | |||
@@ -13,15 +31,99 @@ class OC_Setup { | |||
'sqlite3' => '\OC\Setup\Sqlite', | |||
); | |||
/** | |||
* @return OC_L10N | |||
*/ | |||
public static function getTrans(){ | |||
return \OC::$server->getL10N('lib'); | |||
} | |||
/** | |||
* Wrapper around the "class_exists" PHP function to be able to mock it | |||
* @param string $name | |||
* @return bool | |||
*/ | |||
public function class_exists($name) { | |||
return class_exists($name); | |||
} | |||
/** | |||
* Wrapper around the "is_callable" PHP function to be able to mock it | |||
* @param string $name | |||
* @return bool | |||
*/ | |||
public function is_callable($name) { | |||
return is_callable($name); | |||
} | |||
/** | |||
* Get the available and supported databases of this instance | |||
* | |||
* @throws Exception | |||
* @return array | |||
*/ | |||
public function getSupportedDatabases() { | |||
$availableDatabases = array( | |||
'sqlite' => array( | |||
'type' => 'class', | |||
'call' => 'SQLite3', | |||
'name' => 'SQLite' | |||
), | |||
'mysql' => array( | |||
'type' => 'function', | |||
'call' => 'mysql_connect', | |||
'name' => 'MySQL/MariaDB' | |||
), | |||
'pgsql' => array( | |||
'type' => 'function', | |||
'call' => 'oci_connect', | |||
'name' => 'PostgreSQL' | |||
), | |||
'oci' => array( | |||
'type' => 'function', | |||
'call' => 'oci_connect', | |||
'name' => 'Oracle' | |||
), | |||
'mssql' => array( | |||
'type' => 'function', | |||
'call' => 'sqlsrv_connect', | |||
'name' => 'MS SQL' | |||
) | |||
); | |||
$configuredDatabases = $this->config->getSystemValue('supportedDatabases', | |||
array('sqlite', 'mysql', 'pgsql', 'oci', 'mssql')); | |||
if(!is_array($configuredDatabases)) { | |||
throw new Exception('Supported databases are not properly configured.'); | |||
} | |||
$supportedDatabases = array(); | |||
foreach($configuredDatabases as $database) { | |||
if(array_key_exists($database, $availableDatabases)) { | |||
$working = false; | |||
if($availableDatabases[$database]['type'] === 'class') { | |||
$working = $this->class_exists($availableDatabases[$database]['call']); | |||
} elseif ($availableDatabases[$database]['type'] === 'function') { | |||
$working = $this->is_callable($availableDatabases[$database]['call']); | |||
} | |||
if($working) { | |||
$supportedDatabases[$database] = $availableDatabases[$database]['name']; | |||
} | |||
} | |||
} | |||
return $supportedDatabases; | |||
} | |||
/** | |||
* @param $options | |||
* @return array | |||
*/ | |||
public static function install($options) { | |||
$l = self::getTrans(); | |||
$error = array(); | |||
$dbtype = $options['dbtype']; | |||
$dbType = $options['dbtype']; | |||
if(empty($options['adminlogin'])) { | |||
$error[] = $l->t('Set an admin username.'); | |||
@@ -33,25 +135,25 @@ class OC_Setup { | |||
$options['directory'] = OC::$SERVERROOT."/data"; | |||
} | |||
if (!isset(self::$dbSetupClasses[$dbtype])) { | |||
$dbtype = 'sqlite'; | |||
if (!isset(self::$dbSetupClasses[$dbType])) { | |||
$dbType = 'sqlite'; | |||
} | |||
$username = htmlspecialchars_decode($options['adminlogin']); | |||
$password = htmlspecialchars_decode($options['adminpass']); | |||
$datadir = htmlspecialchars_decode($options['directory']); | |||
$dataDir = htmlspecialchars_decode($options['directory']); | |||
$class = self::$dbSetupClasses[$dbtype]; | |||
$class = self::$dbSetupClasses[$dbType]; | |||
/** @var \OC\Setup\AbstractDatabase $dbSetup */ | |||
$dbSetup = new $class(self::getTrans(), 'db_structure.xml'); | |||
$error = array_merge($error, $dbSetup->validate($options)); | |||
// validate the data directory | |||
if ( | |||
(!is_dir($datadir) and !mkdir($datadir)) or | |||
!is_writable($datadir) | |||
(!is_dir($dataDir) and !mkdir($dataDir)) or | |||
!is_writable($dataDir) | |||
) { | |||
$error[] = $l->t("Can't create or write into the data directory %s", array($datadir)); | |||
$error[] = $l->t("Can't create or write into the data directory %s", array($dataDir)); | |||
} | |||
if(count($error) != 0) { | |||
@@ -59,7 +161,7 @@ class OC_Setup { | |||
} | |||
//no errors, good | |||
if( isset($options['trusted_domains']) | |||
if(isset($options['trusted_domains']) | |||
&& is_array($options['trusted_domains'])) { | |||
$trustedDomains = $options['trusted_domains']; | |||
} else { | |||
@@ -67,12 +169,12 @@ class OC_Setup { | |||
} | |||
if (OC_Util::runningOnWindows()) { | |||
$datadir = rtrim(realpath($datadir), '\\'); | |||
$dataDir = rtrim(realpath($dataDir), '\\'); | |||
} | |||
//use sqlite3 when available, otherise sqlite2 will be used. | |||
if($dbtype=='sqlite' and class_exists('SQLite3')) { | |||
$dbtype='sqlite3'; | |||
//use sqlite3 when available, otherwise sqlite2 will be used. | |||
if($dbType=='sqlite' and class_exists('SQLite3')) { | |||
$dbType='sqlite3'; | |||
} | |||
//generate a random salt that is used to salt the local user passwords | |||
@@ -85,9 +187,9 @@ class OC_Setup { | |||
//write the config file | |||
\OC::$server->getConfig()->setSystemValue('trusted_domains', $trustedDomains); | |||
\OC::$server->getConfig()->setSystemValue('datadirectory', $datadir); | |||
\OC::$server->getConfig()->setSystemValue('datadirectory', $dataDir); | |||
\OC::$server->getConfig()->setSystemValue('overwrite.cli.url', \OC_Request::serverProtocol() . '://' . \OC_Request::serverHost() . OC::$WEBROOT); | |||
\OC::$server->getConfig()->setSystemValue('dbtype', $dbtype); | |||
\OC::$server->getConfig()->setSystemValue('dbtype', $dbType); | |||
\OC::$server->getConfig()->setSystemValue('version', implode('.', OC_Util::getVersion())); | |||
try { | |||
@@ -110,8 +212,7 @@ class OC_Setup { | |||
//create the user and group | |||
try { | |||
OC_User::createUser($username, $password); | |||
} | |||
catch(Exception $exception) { | |||
} catch(Exception $exception) { | |||
$error[] = $exception->getMessage(); | |||
} | |||
@@ -436,12 +436,9 @@ class OC_Util { | |||
} | |||
$webServerRestart = false; | |||
//check for database drivers | |||
if (!(is_callable('sqlite_open') or class_exists('SQLite3')) | |||
and !is_callable('mysql_connect') | |||
and !is_callable('pg_connect') | |||
and !is_callable('oci_connect') | |||
) { | |||
$setup = new OC_Setup($config); | |||
$availableDatabases = $setup->getSupportedDatabases(); | |||
if (empty($availableDatabases)) { | |||
$errors[] = array( | |||
'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'), | |||
'hint' => '' //TODO: sane hint |
@@ -0,0 +1,103 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
use OCP\IConfig; | |||
class Test_OC_Setup extends PHPUnit_Framework_TestCase { | |||
/** @var IConfig */ | |||
protected $config; | |||
/** @var \OC_Setup */ | |||
protected $setupClass; | |||
public function setUp() { | |||
$this->config = $this->getMock('\OCP\IConfig'); | |||
$this->setupClass = $this->getMock('\OC_Setup', array('class_exists', 'is_callable'), array($this->config)); | |||
} | |||
public function testGetSupportedDatabasesWithOneWorking() { | |||
$this->config | |||
->expects($this->once()) | |||
->method('getSystemValue') | |||
->will($this->returnValue( | |||
array('sqlite', 'mysql', 'oci') | |||
)); | |||
$this->setupClass | |||
->expects($this->once()) | |||
->method('class_exists') | |||
->will($this->returnValue(true)); | |||
$this->setupClass | |||
->expects($this->exactly(2)) | |||
->method('is_callable') | |||
->will($this->returnValue(false)); | |||
$result = $this->setupClass->getSupportedDatabases(); | |||
$expectedResult = array( | |||
'sqlite' => 'SQLite' | |||
); | |||
$this->assertSame($expectedResult, $result); | |||
} | |||
public function testGetSupportedDatabasesWithNoWorking() { | |||
$this->config | |||
->expects($this->once()) | |||
->method('getSystemValue') | |||
->will($this->returnValue( | |||
array('sqlite', 'mysql', 'oci', 'pgsql') | |||
)); | |||
$this->setupClass | |||
->expects($this->once()) | |||
->method('class_exists') | |||
->will($this->returnValue(false)); | |||
$this->setupClass | |||
->expects($this->exactly(3)) | |||
->method('is_callable') | |||
->will($this->returnValue(false)); | |||
$result = $this->setupClass->getSupportedDatabases(); | |||
$this->assertSame(array(), $result); | |||
} | |||
public function testGetSupportedDatabasesWitAllWorking() { | |||
$this->config | |||
->expects($this->once()) | |||
->method('getSystemValue') | |||
->will($this->returnValue( | |||
array('sqlite', 'mysql', 'pgsql', 'oci', 'mssql') | |||
)); | |||
$this->setupClass | |||
->expects($this->once()) | |||
->method('class_exists') | |||
->will($this->returnValue(true)); | |||
$this->setupClass | |||
->expects($this->exactly(4)) | |||
->method('is_callable') | |||
->will($this->returnValue(true)); | |||
$result = $this->setupClass->getSupportedDatabases(); | |||
$expectedResult = array( | |||
'sqlite' => 'SQLite', | |||
'mysql' => 'MySQL/MariaDB', | |||
'pgsql' => 'PostgreSQL', | |||
'oci' => 'Oracle', | |||
'mssql' => 'MS SQL' | |||
); | |||
$this->assertSame($expectedResult, $result); | |||
} | |||
/** | |||
* @expectedException \Exception | |||
* @expectedExceptionMessage Supported databases are not properly configured. | |||
*/ | |||
public function testGetSupportedDatabaseException() { | |||
$this->config | |||
->expects($this->once()) | |||
->method('getSystemValue') | |||
->will($this->returnValue('NotAnArray')); | |||
$this->setupClass->getSupportedDatabases(); | |||
} | |||
} |