]> source.dussan.org Git - nextcloud-server.git/commitdiff
use pdo for postgres setup
authorRobin Appelman <icewind@owncloud.com>
Tue, 12 Jul 2016 11:50:54 +0000 (13:50 +0200)
committerRobin Appelman <icewind@owncloud.com>
Tue, 12 Jul 2016 12:38:24 +0000 (14:38 +0200)
lib/private/Setup/AbstractDatabase.php
lib/private/Setup/PostgreSQL.php

index 62e9b2e823ff46ecef3fb0c6ca220d81001de80f..8dee96b1ba5b0d8d7dcb61574a90839b6bcd3376 100644 (file)
@@ -101,10 +101,10 @@ abstract class AbstractDatabase {
        }
 
        /**
+        * @param array $configOverwrite
         * @return \OC\DB\Connection
-        * @throws \OC\DatabaseSetupException
         */
-       protected function connect() {
+       protected function connect(array $configOverwrite = []) {
                $systemConfig = $this->config->getSystemConfig();
                $cf = new ConnectionFactory();
                $connectionParams = $cf->createConnectionParams($systemConfig);
@@ -115,6 +115,7 @@ abstract class AbstractDatabase {
                if (!$connectionParams['password']) {
                        $connectionParams['password'] = $this->dbPassword;
                }
+               $connectionParams = array_merge($connectionParams, $configOverwrite);
                return $cf->getConnection($systemConfig->getValue('dbtype', 'sqlite'), $connectionParams);
        }
 
index 464d1e02e21a411f6ecb0b26493028411edd97b2..30ca88f53aad3a1cbcfb86cefd697a0a181f6ac8 100644 (file)
  */
 namespace OC\Setup;
 
+use OC\DatabaseException;
+use OC\DB\QueryBuilder\Literal;
+use OCP\IDBConnection;
+
 class PostgreSQL extends AbstractDatabase {
        public $dbprettyname = 'PostgreSQL';
 
        public function setupDatabase($username) {
-               $e_host = addslashes($this->dbHost);
-               $e_user = addslashes($this->dbUser);
-               $e_password = addslashes($this->dbPassword);
-
-               // adding port support through installer
-               if(!empty($this->dbPort)) {
-                       // casting to int to avoid malicious input
-                       $port = (int)$this->dbPort;
-               } else if(strpos($e_host, ':')) {
-                       list($e_host, $port)=explode(':', $e_host, 2);
-               } else {
-                       $port=false;
+               $connection = $this->connect([
+                       'dbname' => 'postgres'
+               ]);
+               //check for roles creation rights in postgresql
+               $builder = $connection->getQueryBuilder();
+               $builder->automaticTablePrefix(false);
+               $query = $builder
+                       ->select('rolname')
+                       ->from('pg_roles')
+                       ->where($builder->expr()->eq('rolcreaterole', new Literal('TRUE')))
+                       ->andWhere($builder->expr()->eq('rolname', $builder->createNamedParameter($this->dbUser)));
+
+               try {
+                       $result = $query->execute();
+                       $canCreateRoles = $result->rowCount() > 0;
+               } catch (DatabaseException $e) {
+                       $canCreateRoles = false;
                }
 
-               //check if the database user has admin rights
-               $connection_string = "host='$e_host' dbname=postgres user='$e_user' port='$port' password='$e_password'";
-               $connection = @pg_connect($connection_string);
-               if(!$connection) {
-                       // Try if we can connect to the DB with the specified name
-                       $e_dbname = addslashes($this->dbName);
-                       $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'";
-                       $connection = @pg_connect($connection_string);
-
-                       if(!$connection)
-                               throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL connection failed'),
-                                               $this->trans->t('Please check your connection details.'));
-               }
-               $e_user = pg_escape_string($this->dbUser);
-               //check for roles creation rights in postgresql
-               $query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$e_user'";
-               $result = pg_query($connection, $query);
-               if($result and pg_num_rows($result) > 0) {
+               if($canCreateRoles) {
                        //use the admin login data for the new database user
 
                        //add prefix to the postgresql user name to prevent collisions
@@ -72,7 +64,7 @@ class PostgreSQL extends AbstractDatabase {
                        $this->createDBUser($connection);
                }
 
-               $systemConfig = \OC::$server->getSystemConfig();
+               $systemConfig = $this->config->getSystemConfig();
                $systemConfig->setValues([
                        'dbuser'                => $this->dbUser,
                        'dbpassword'    => $this->dbPassword,
@@ -80,98 +72,85 @@ class PostgreSQL extends AbstractDatabase {
 
                //create the database
                $this->createDatabase($connection);
+               $query = $connection->prepare("select count(*) FROM pg_class WHERE relname=? limit 1");
+               $query->execute([$this->tablePrefix . "users"]);
+               $tablesSetup = $query->fetchColumn() > 0;
 
                // the connection to dbname=postgres is not needed anymore
-               pg_close($connection);
+               $connection->close();
 
                // connect to the ownCloud database (dbname=$this->dbname) and check if it needs to be filled
                $this->dbUser = $systemConfig->getValue('dbuser');
                $this->dbPassword = $systemConfig->getValue('dbpassword');
-
-               $e_host = addslashes($this->dbHost);
-               $e_dbname = addslashes($this->dbName);
-               $e_user = addslashes($this->dbUser);
-               $e_password = addslashes($this->dbPassword);
-
-               // Fix database with port connection
-               if(strpos($e_host, ':')) {
-                       list($e_host, $port)=explode(':', $e_host, 2);
-               } else {
-                       $port=false;
-               }
-
-               $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'";
-               $connection = @pg_connect($connection_string);
-               if(!$connection) {
+               $connection = $this->connect();
+               try {
+                       $connection->connect();
+               } catch (\Exception $e) {
+                       $this->logger->logException($e);
                        throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'),
-                                       $this->trans->t('You need to enter either an existing account or the administrator.'));
+                               $this->trans->t('You need to enter either an existing account or the administrator.'));
                }
-               $query = "select count(*) FROM pg_class WHERE relname='".$this->tablePrefix."users' limit 1";
-               $result = pg_query($connection, $query);
-               if($result) {
-                       $row = pg_fetch_row($result);
-               }
-               if(!$result or $row[0]==0) {
+
+
+               if(!$tablesSetup) {
                        \OC_DB::createDbFromStructure($this->dbDefinitionFile);
                }
        }
 
-       private function createDatabase($connection) {
-               //we can't use OC_BD functions here because we need to connect as the administrative user.
-               $e_name = pg_escape_string($this->dbName);
-               $e_user = pg_escape_string($this->dbUser);
-               $query = "select datname from pg_database where datname = '$e_name'";
-               $result = pg_query($connection, $query);
-               if(!$result) {
-                       $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
-                       $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
-                       \OCP\Util::writeLog('setup.pg', $entry, \OCP\Util::WARN);
-               }
-               if(! pg_fetch_row($result)) {
+       private function createDatabase(IDBConnection $connection) {
+               if(!$this->databaseExists($connection)) {
                        //The database does not exists... let's create it
-                       $query = "CREATE DATABASE \"$e_name\" OWNER \"$e_user\"";
-                       $result = pg_query($connection, $query);
-                       if(!$result) {
-                               $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
-                               $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
-                               \OCP\Util::writeLog('setup.pg', $entry, \OCP\Util::WARN);
+                       $query = $connection->prepare("CREATE DATABASE " . addslashes($this->dbName) . " OWNER " . addslashes($this->dbUser));
+                       try {
+                               $query->execute();
+                       } catch (DatabaseException $e) {
+                               $this->logger->error('Error while trying to create database');
+                               $this->logger->logException($e);
                        }
-                       else {
-                               $query = "REVOKE ALL PRIVILEGES ON DATABASE \"$e_name\" FROM PUBLIC";
-                               pg_query($connection, $query);
+               } else {
+                       $query = $connection->prepare("REVOKE ALL PRIVILEGES ON DATABASE " . addslashes($this->dbName) . " FROM PUBLIC");
+                       try {
+                               $query->execute();
+                       } catch (DatabaseException $e) {
+                               $this->logger->error('Error while trying to restrict database permissions');
+                               $this->logger->logException($e);
                        }
                }
        }
 
-       private function createDBUser($connection) {
-               $e_name = pg_escape_string($this->dbUser);
-               $e_password = pg_escape_string($this->dbPassword);
-               $query = "select * from pg_roles where rolname='$e_name';";
-               $result = pg_query($connection, $query);
-               if(!$result) {
-                       $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
-                       $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
-                       \OCP\Util::writeLog('setup.pg', $entry, \OCP\Util::WARN);
-               }
+       private function userExists(IDBConnection $connection) {
+               $builder = $connection->getQueryBuilder();
+               $builder->automaticTablePrefix(false);
+               $query = $builder->select('*')
+                       ->from('pg_roles')
+                       ->where($builder->expr()->eq('rolname', $builder->createNamedParameter($this->dbUser)));
+               $result = $query->execute();
+               return $result->rowCount() > 0;
+       }
 
-               if(! pg_fetch_row($result)) {
-                       //user does not exists let's create it :)
-                       $query = "CREATE USER \"$e_name\" CREATEDB PASSWORD '$e_password';";
-                       $result = pg_query($connection, $query);
-                       if(!$result) {
-                               $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
-                               $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
-                               \OCP\Util::writeLog('setup.pg', $entry, \OCP\Util::WARN);
-                       }
-               }
-               else { // change password of the existing role
-                       $query = "ALTER ROLE \"$e_name\" WITH PASSWORD '$e_password';";
-                       $result = pg_query($connection, $query);
-                       if(!$result) {
-                               $entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
-                               $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
-                               \OCP\Util::writeLog('setup.pg', $entry, \OCP\Util::WARN);
+       private function databaseExists(IDBConnection $connection) {
+               $builder = $connection->getQueryBuilder();
+               $builder->automaticTablePrefix(false);
+               $query = $builder->select('datname')
+                       ->from('pg_database')
+                       ->where($builder->expr()->eq('datname', $builder->createNamedParameter($this->dbName)));
+               $result = $query->execute();
+               return $result->rowCount() > 0;
+       }
+
+       private function createDBUser(IDBConnection $connection) {
+               try {
+                       if ($this->userExists($connection, $this->dbUser)) {
+                               // change the password
+                               $query = $connection->prepare("ALTER ROLE " . addslashes($this->dbUser) . " CREATEDB WITH PASSWORD " . addslashes($this->dbPassword));
+                       } else {
+                               // create the user
+                               $query = $connection->prepare("CREATE USER " . addslashes($this->dbUser) . " CREATEDB PASSWORD " . addslashes($this->dbPassword));
                        }
+                       $query->execute();
+               } catch (DatabaseException $e) {
+                       $this->logger->error('Error while trying to create database user');
+                       $this->logger->logException($e);
                }
        }
 }