From 0e2b957dacb86c510c59721f63879f1c9d93d5d4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 17 Sep 2011 02:30:58 +0200 Subject: [PATCH 1/5] add pdo backend to oc_db --- lib/db.php | 350 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 215 insertions(+), 135 deletions(-) diff --git a/lib/db.php b/lib/db.php index 414525ae207..3c0ab8544af 100644 --- a/lib/db.php +++ b/lib/db.php @@ -25,7 +25,13 @@ * MDB2 with some adaptions. */ class OC_DB { - static private $DBConnection=false; + const BACKEND_PDO=0; + const BACKEND_MDB2=1; + + static private $connection; //the prefered conenction to use, either PDO or MDB2 + static private $backend=null; + static private $MDB2=false; + static private $PDO=false; static private $schema=false; static private $affected=0; static private $result=false; @@ -36,18 +42,77 @@ class OC_DB { * * Connects to the database as specified in config.php */ - static public function connect(){ + public static function connect(){ + if(class_exists('PDO')){//check if we can use PDO, else use MDB2 + self::connectPDO(); + self::$connection=self::$PDO; + self::$backend=self::BACKEND_PDO; + }else{ + self::connectMDB2(); + die('bar'); + self::$connection=self::$MDB2; + self::$backend=self::BACKEND_MDB2; + } + } + + /** + * connect to the database using pdo + */ + private static function connectPDO(){ // The global data we need - $CONFIG_DBNAME = OC_Config::getValue( "dbname", "owncloud" );; - $CONFIG_DBHOST = OC_Config::getValue( "dbhost", "" );; - $CONFIG_DBUSER = OC_Config::getValue( "dbuser", "" );; - $CONFIG_DBPASSWORD = OC_Config::getValue( "dbpassword", "" );; - $CONFIG_DBTYPE = OC_Config::getValue( "dbtype", "sqlite" );; - global $SERVERROOT; + $name = OC_Config::getValue( "dbname", "owncloud" ); + $host = OC_Config::getValue( "dbhost", "" ); + $user = OC_Config::getValue( "dbuser", "" ); + $pass = OC_Config::getValue( "dbpassword", "" ); + $type = OC_Config::getValue( "dbtype", "sqlite" ); + $SERVERROOT=OC::$SERVERROOT; + $datadir=OC_Config::getValue( "datadirectory", "$SERVERROOT/data" ); + + // do nothing if the connection already has been established + if(!self::$PDO){ + // Add the dsn according to the database type + switch($type){ + case 'sqlite': + $dsn='sqlite2:'.$datadir.'/'.$name.'.db'; + break; + case 'sqlite3': + $dsn='sqlite:'.$datadir.'/'.$name.'.db'; + break; + case 'mysql': + $dsn='mysql:dbname='.$name.';host='.$host; + break; + case 'pgsql': + $dsn='pgsql:dbname='.$name.';host='.$host; + break; + } + try{ + self::$PDO=new PDO($dsn,$user,$pass); + }catch(PDOException $e){ + echo( 'can not connect to database, using '.$type.'. ('.$e->getMessage().')'); + die(); + } + // We always, really always want associative arrays + self::$PDO->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC); + self::$PDO->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); + } + return true; + } + + /** + * connect to the database using mdb2 + */ + static private function connectMDB2(){ + // The global data we need + $name = OC_Config::getValue( "dbname", "owncloud" ); + $host = OC_Config::getValue( "dbhost", "" ); + $user = OC_Config::getValue( "dbuser", "" ); + $pass = OC_Config::getValue( "dbpassword", "" ); + $type = OC_Config::getValue( "dbtype", "sqlite" ); + $SERVERROOT=OC::$SERVERROOT; $datadir=OC_Config::getValue( "datadirectory", "$SERVERROOT/data" ); // do nothing if the connection already has been established - if(!self::$DBConnection){ + if(!self::$MDB2){ // Require MDB2.php (not required in the head of the file so we only load it when needed) require_once('MDB2.php'); @@ -60,83 +125,55 @@ class OC_DB { 'quote_identifier' => true ); // Add the dsn according to the database type - if( $CONFIG_DBTYPE == 'sqlite' or $CONFIG_DBTYPE == 'sqlite3' ){ - // sqlite - $dsn = array( - 'phptype' => $CONFIG_DBTYPE, - 'database' => "$datadir/$CONFIG_DBNAME.db", - 'mode' => '0644' ); - } - elseif( $CONFIG_DBTYPE == 'mysql' ){ - // MySQL - $dsn = array( - 'phptype' => 'mysql', - 'username' => $CONFIG_DBUSER, - 'password' => $CONFIG_DBPASSWORD, - 'hostspec' => $CONFIG_DBHOST, - 'database' => $CONFIG_DBNAME ); - } - elseif( $CONFIG_DBTYPE == 'pgsql' ){ - // PostgreSQL - $dsn = array( - 'phptype' => 'pgsql', - 'username' => $CONFIG_DBUSER, - 'password' => $CONFIG_DBPASSWORD, - 'hostspec' => $CONFIG_DBHOST, - 'database' => $CONFIG_DBNAME ); + switch($type){ + case 'sqlite': + case 'sqlite3': + $dsn = array( + 'phptype' => $type, + 'database' => "$datadir/$name.db", + 'mode' => '0644' + ); + break; + case 'mysql': + $dsn = array( + 'phptype' => 'mysql', + 'username' => $user, + 'password' => $pass, + 'hostspec' => $host, + 'database' => $name + ); + break; + case 'pgsql': + $dsn = array( + 'phptype' => 'pgsql', + 'username' => $user, + 'password' => $pass, + 'hostspec' => $host, + 'database' => $name + ); + break; } - + // Try to establish connection - self::$DBConnection = MDB2::factory( $dsn, $options ); - + self::$MDB2 = MDB2::factory( $dsn, $options ); + // Die if we could not connect - if( PEAR::isError( self::$DBConnection )){ - echo( 'can not connect to database, using '.$CONFIG_DBTYPE.'. ('.self::$DBConnection->getUserInfo().')'); - $error = self::$DBConnection->getMessage(); + if( PEAR::isError( self::$MDB2 )){ + echo( 'can not connect to database, using '.$type.'. ('.self::$MDB2->getUserInfo().')'); + $error = self::$MDB2->getMessage(); error_log( $error); - error_log( self::$DBConnection->getUserInfo()); + error_log( self::$MDB2->getUserInfo()); die( $error ); } - + // We always, really always want associative arrays - self::$DBConnection->setFetchMode(MDB2_FETCHMODE_ASSOC); - - //we need to function module for query pre-procesing - self::$DBConnection->loadModule('Function'); + self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC); } - + // we are done. great! return true; } - /** - * @brief SQL query - * @param $query Query string - * @returns result as MDB2_Result - * - * SQL query via MDB2 query() - */ - static public function query( $query ){ - // Optimize the query - $query = self::processQuery( $query ); - - self::connect(); - //fix differences between sql versions - - // return the result - $result = self::$DBConnection->exec( $query ); - - // Die if we have an error (error means: bad query, not 0 results!) - if( PEAR::isError($result)) { - $entry = 'DB Error: "'.$result->getMessage().'"
'; - $entry .= 'Offending command was: '.$query.'
'; - error_log( $entry ); - die( $entry ); - } - - return $result; - } - /** * @brief Prepare a SQL query * @param $query Query string @@ -150,16 +187,27 @@ class OC_DB { self::connect(); // return the result - $result = self::$DBConnection->prepare( $query ); - - // Die if we have an error (error means: bad query, not 0 results!) - if( PEAR::isError($result)) { - $entry = 'DB Error: "'.$result->getMessage().'"
'; - $entry .= 'Offending command was: '.$query.'
'; - error_log( $entry ); - die( $entry ); + if(self::$backend==self::BACKEND_MDB2){ + $result = self::$connection->prepare( $query ); + + // Die if we have an error (error means: bad query, not 0 results!) + if( PEAR::isError($result)) { + $entry = 'DB Error: "'.$result->getMessage().'"
'; + $entry .= 'Offending command was: '.$query.'
'; + error_log( $entry ); + die( $entry ); + } + }else{ + try{ + $result=self::$connection->prepare($query); + }catch(PDOException $e){ + $entry = 'DB Error: "'.$e->getMessage().'"
'; + $entry .= 'Offending command was: '.$query.'
'; + error_log( $entry ); + die( $entry ); + } + $result=new PDOStatementWrapper($result); } - return $result; } @@ -174,7 +222,7 @@ class OC_DB { */ public static function insertid(){ self::connect(); - return self::$DBConnection->lastInsertID(); + return self::$connection->lastInsertId(); } /** @@ -185,26 +233,18 @@ class OC_DB { */ public static function disconnect(){ // Cut connection if required - if(self::$DBConnection){ - self::$DBConnection->disconnect(); - self::$DBConnection=false; + if(self::$connection){ + if(self::$backend==self::BACKEND_MDB2){ + self::$connection->disconnect(); + } + self::$connection=false; + self::$mdb2=false; + self::$pdo=false; } return true; } - /** - * @brief Escapes bad characters - * @param $string string with dangerous characters - * @returns escaped string - * - * MDB2 escape() - */ - public static function escape( $string ){ - self::connect(); - return self::$DBConnection->escape( $string ); - } - /** * @brief saves database scheme to xml file * @param $file name of file @@ -283,13 +323,13 @@ class OC_DB { * Connects to a MDB2 database scheme */ private static function connectScheme(){ - // We need a database connection - self::connect(); + // We need a mdb2 database connection + self::connectMDB2(); // Connect if this did not happen before if(!self::$schema){ require_once('MDB2/Schema.php'); - self::$schema=MDB2_Schema::factory(self::$DBConnection); + self::$schema=MDB2_Schema::factory(self::$MDB2); } return true; @@ -306,24 +346,25 @@ class OC_DB { private static function processQuery( $query ){ self::connect(); // We need Database type and table prefix - $CONFIG_DBTYPE = OC_Config::getValue( "dbtype", "sqlite" ); - $CONFIG_DBTABLEPREFIX = OC_Config::getValue( "dbtableprefix", "oc_" ); - - // differences is getting the current timestamp - $query = str_replace( 'NOW()', self::$DBConnection->now(), $query ); - $query = str_replace( 'now()', self::$DBConnection->now(), $query ); + $type = OC_Config::getValue( "dbtype", "sqlite" ); + $prefix = OC_Config::getValue( "dbtableprefix", "oc_" ); - // differences in escaping of table names (` for mysql) - // Problem: what if there is a ` in the value we want to insert? - if( $CONFIG_DBTYPE == 'sqlite' ){ + // differences in escaping of table names ('`' for mysql) and getting the current timestamp + if( $type == 'sqlite' ){ $query = str_replace( '`', '\'', $query ); - } - elseif( $CONFIG_DBTYPE == 'pgsql' ){ + $query = str_replace( 'NOW()', 'datetime(\'now\')', $query ); + $query = str_replace( 'now()', 'datetime(\'now\')', $query ); + }elseif( $type == 'mysql' ){ + $query = str_replace( 'NOW()', 'CURRENT_TIMESTAMP', $query ); + $query = str_replace( 'now()', 'CURRENT_TIMESTAMP', $query ); + }elseif( $type == 'pgsql' ){ $query = str_replace( '`', '"', $query ); + $query = str_replace( 'NOW()', 'CURRENT_TIMESTAMP', $query ); + $query = str_replace( 'now()', 'CURRENT_TIMESTAMP', $query ); } // replace table name prefix - $query = str_replace( '*PREFIX*', $CONFIG_DBTABLEPREFIX, $query ); + $query = str_replace( '*PREFIX*', $prefix, $query ); return $query; } @@ -333,9 +374,9 @@ class OC_DB { * @param string $tableNamme the table to drop */ public static function dropTable($tableName){ - self::connect(); - self::$DBConnection->loadModule('Manager'); - self::$DBConnection->dropTable($tableName); + self::connectMDB2(); + self::$MDB2->loadModule('Manager'); + self::$MDB2->dropTable($tableName); } /** @@ -367,37 +408,76 @@ class OC_DB { } /** - * Start a transaction or set a savepoint. - * @param string $savePoint (optional) name of the savepoint to set + * Start a transaction */ - public static function beginTransaction($savePoint=''){ + public static function beginTransaction(){ self::connect(); - if (!self::$DBConnection->supports('transactions')) { + if (self::$backend=self::BACKEND_MDB2 && !self::$connection->supports('transactions')) { return false; } - if($savePoint && !self::$DBConnection->supports('savepoints')){ - return false; - } - if($savePoint){ - self::$DBConnection->beginTransaction($savePoint); - }else{ - self::$DBConnection->beginTransaction(); - } + self::$connection->beginTransaction(); } /** - * Commit the database changes done during a transaction that is in progress or release a savepoint. - * @param string $savePoint (optional) name of the savepoint to commit + * Commit the database changes done during a transaction that is in progress */ public static function commit($savePoint=''){ self::connect(); - if(!self::$DBConnection->inTransaction()){ + if(!self::$connection->inTransaction()){ return false; } - if($savePoint){ - self::$DBConnection->commit($savePoint); + self::$connection->commit(); + } +} + +/** + * small wrapper around PDOStatement to make it behave ,more like an MDB2 Statement + */ +class PDOStatementWrapper{ + private $statement=null; + private $lastArguments=array(); + + public function __construct($statement){ + $this->statement=$statement; + } + + /** + * make exucute return the result instead of a bool + */ + public function execute($input=array()){ + $this->lastArguments=$input; + if(count($input)>0){ + $this->statement->execute($input); + }else{ + $this->statement->execute(); + } + return $this; + } + + /** + * provide numRows + */ + public function numRows(){ + $regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/i'; + if (preg_match($regex, $this->statement->queryString, $output) > 0) { + $query = OC_DB::prepare("SELECT COUNT(*) FROM {$output[1]}", PDO::FETCH_NUM); + return $query->execute($this->lastArguments)->fetchColumn(); }else{ - self::$DBConnection->commit(); + return $this->statement->rowCount(); } } + + /** + * provide an alias for fetch + */ + public function fetchRow(){ + return $this->statement->fetch(); + } + + /** + * pass all other function directly to the PDOStatement + */ + public function __call($name,$arguments){ + return call_user_func_array(array($this->statement,$name),$arguments); + } } From 5e3ecbbf96ff0268220a85aaef3c99c84e13ab44 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 17 Sep 2011 02:36:04 +0200 Subject: [PATCH 2/5] dont use numRows when it's not needed since it can be expensive --- lib/appconfig.php | 10 ++++------ lib/group/database.php | 2 +- lib/preferences.php | 11 +++++------ lib/user/database.php | 4 ++-- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/lib/appconfig.php b/lib/appconfig.php index c64a15b8938..392782b2586 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -93,14 +93,12 @@ class OC_Appconfig{ // At least some magic in here :-) $query = OC_DB::prepare( 'SELECT configvalue FROM *PREFIX*appconfig WHERE appid = ? AND configkey = ?' ); $result = $query->execute( array( $app, $key )); - - if( !$result->numRows()){ + $row = $result->fetchRow(); + if($row){ + return $row["configvalue"]; + }else{ return $default; } - - $row = $result->fetchRow(); - - return $row["configvalue"]; } /** diff --git a/lib/group/database.php b/lib/group/database.php index 8a9fc53d39f..7bf9c8bb5ce 100644 --- a/lib/group/database.php +++ b/lib/group/database.php @@ -56,7 +56,7 @@ class OC_Group_Database extends OC_Group_Backend { $query = OC_DB::prepare( "SELECT gid FROM `*PREFIX*groups` WHERE gid = ?" ); $result = $query->execute( array( $gid )); - if( $result->numRows() > 0 ){ + if( !$result->fetchRow() ){ // Can not add an existing group return false; } diff --git a/lib/preferences.php b/lib/preferences.php index d53cdd538e0..5af007f0223 100644 --- a/lib/preferences.php +++ b/lib/preferences.php @@ -116,14 +116,13 @@ class OC_Preferences{ // Try to fetch the value, return default if not exists. $query = OC_DB::prepare( 'SELECT configvalue FROM *PREFIX*preferences WHERE userid = ? AND appid = ? AND configkey = ?' ); $result = $query->execute( array( $user, $app, $key )); - - if( !$result->numRows()){ + + $row = $result->fetchRow(); + if($row){ + return $row["configvalue"]; + }else{ return $default; } - - $row = $result->fetchRow(); - - return $row["configvalue"]; } /** diff --git a/lib/user/database.php b/lib/user/database.php index f29aaf00f05..452709c1fb9 100644 --- a/lib/user/database.php +++ b/lib/user/database.php @@ -106,8 +106,8 @@ class OC_User_Database extends OC_User_Backend { $query = OC_DB::prepare( "SELECT uid FROM *PREFIX*users WHERE uid LIKE ? AND password = ?" ); $result = $query->execute( array( $uid, sha1( $password ))); - if( $result->numRows() > 0 ){ - $row=$result->fetchRow(); + $row=$result->fetchRow(); + if($row){ return $row['uid']; }else{ return false; From 39fa5d1c7fe6b0e3c90396eb16a875b74d803894 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 18 Sep 2011 14:05:38 +0200 Subject: [PATCH 3/5] always use mdb2 for installation --- lib/db.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/db.php b/lib/db.php index 3c0ab8544af..20adff30787 100644 --- a/lib/db.php +++ b/lib/db.php @@ -43,13 +43,12 @@ class OC_DB { * Connects to the database as specified in config.php */ public static function connect(){ - if(class_exists('PDO')){//check if we can use PDO, else use MDB2 + if(class_exists('PDO') && OC_Config::getValue('installed', false)){//check if we can use PDO, else use MDB2 (instalation always needs to be done my mdb2) self::connectPDO(); self::$connection=self::$PDO; self::$backend=self::BACKEND_PDO; }else{ self::connectMDB2(); - die('bar'); self::$connection=self::$MDB2; self::$backend=self::BACKEND_MDB2; } From 949494ccfd89d7ff4af26d8da83475e2ee382f73 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 8 Oct 2011 21:18:47 +0200 Subject: [PATCH 4/5] mimetype icon improvements --- .../filetypes/{script.png => code-script.png} | Bin core/img/filetypes/{php.png => text-x-php.png} | Bin files/ajax/mimeicon.php | 8 ++++++++ files/js/filelist.js | 12 ++++++++---- files/js/files.js | 15 +++++++++------ lib/helper.php | 6 ++++++ 6 files changed, 31 insertions(+), 10 deletions(-) rename core/img/filetypes/{script.png => code-script.png} (100%) rename core/img/filetypes/{php.png => text-x-php.png} (100%) create mode 100644 files/ajax/mimeicon.php diff --git a/core/img/filetypes/script.png b/core/img/filetypes/code-script.png similarity index 100% rename from core/img/filetypes/script.png rename to core/img/filetypes/code-script.png diff --git a/core/img/filetypes/php.png b/core/img/filetypes/text-x-php.png similarity index 100% rename from core/img/filetypes/php.png rename to core/img/filetypes/text-x-php.png diff --git a/files/ajax/mimeicon.php b/files/ajax/mimeicon.php new file mode 100644 index 00000000000..8724016b3a1 --- /dev/null +++ b/files/ajax/mimeicon.php @@ -0,0 +1,8 @@ + diff --git a/files/js/filelist.js b/files/js/filelist.js index 84762bb561d..e6da922700d 100644 --- a/files/js/filelist.js +++ b/files/js/filelist.js @@ -101,10 +101,14 @@ FileList={ $('.file_upload_filename').removeClass('highlight'); }, loadingDone:function(name){ - $('tr[data-file="'+name+'"]').data('loading',false); - var mime=$('tr[data-file="'+name+'"]').data('mime'); - $('tr[data-file="'+name+'"] td.filename').attr('style','background-image:url('+getMimeIcon(mime)+')'); - $('tr[data-file="'+name+'"] td.filename').draggable(dragOptions); + var tr=$('tr[data-file="'+name+'"]'); + tr.data('loading',false); + var mime=tr.data('mime'); + tr.attr('data-mime',mime); + getMimeIcon(mime,function(path){ + tr.find('td.filename').attr('style','background-image:url('+path+')'); + }); + tr.find('td.filename').draggable(dragOptions); }, isLoading:function(name){ return $('tr[data-file="'+name+'"]').data('loading'); diff --git a/files/js/files.js b/files/js/files.js index 9342642b4ff..079646070d4 100644 --- a/files/js/files.js +++ b/files/js/files.js @@ -473,11 +473,14 @@ function relative_modified_date(timestamp) { else { return diffyears+' '+t('files','years ago'); } } -function getMimeIcon(mime){ - mime=mime.substr(0,mime.indexOf('/')); - var knownMimes=['image','audio']; - if(knownMimes.indexOf(mime)==-1){ - mime='file'; +function getMimeIcon(mime, ready){ + if(getMimeIcon.cache[mime]){ + ready(getMimeIcon.cache[mime]); + }else{ + $.get( OC.filePath('files','ajax','mimeicon.php')+'?mime='+mime, function(path){ + getMimeIcon.cache[mime]=path; + ready(getMimeIcon.cache[mime]); + }); } - return OC.imagePath('core','filetypes/'+mime); } +getMimeIcon.cache={}; diff --git a/lib/helper.php b/lib/helper.php index c2a81ba3306..5b3e394cafd 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -96,6 +96,12 @@ class OC_Helper { * Returns the path to the image of this file type. */ public static function mimetypeIcon( $mimetype ){ + $alias=array('application/xml'=>'code/xml'); +// echo $mimetype; + if(isset($alias[$mimetype])){ + $mimetype=$alias[$mimetype]; +// echo $mimetype; + } // Replace slash with a minus $mimetype = str_replace( "/", "-", $mimetype ); From ffb9a0475e046d2cf88bbc5801905358fe4ce1e0 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 13 Oct 2011 16:31:01 +0200 Subject: [PATCH 5/5] webdav workaround for apache+php-cgi --- .htaccess | 4 ++++ lib/base.php | 8 ++++++++ lib/setup.php | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/.htaccess b/.htaccess index 8763a8bcde5..dd49442e371 100644 --- a/.htaccess +++ b/.htaccess @@ -5,4 +5,8 @@ php_value post_max_size 512M php_value memory_limit 128M SetEnv htaccessWorking true + +RewriteEngine on +RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization},last] + Options -Indexes diff --git a/lib/base.php b/lib/base.php index 0156febe231..57a3ae8669b 100644 --- a/lib/base.php +++ b/lib/base.php @@ -81,6 +81,14 @@ class OC{ date_default_timezone_set('Europe/Berlin'); ini_set('arg_separator.output','&'); + //set http auth headers for apache+php-cgi work around + if (preg_match('/Basic\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'], $matches)) + { + list($name, $password) = explode(':', base64_decode($matches[1])); + $_SERVER['PHP_AUTH_USER'] = strip_tags($name); + $_SERVER['PHP_AUTH_PW'] = strip_tags($password); + } + // calculate the documentroot OC::$DOCUMENTROOT=realpath($_SERVER['DOCUMENT_ROOT']); OC::$SERVERROOT=str_replace("\\",'/',substr(__FILE__,0,-13)); diff --git a/lib/setup.php b/lib/setup.php index 355d979dc65..252eaaeea18 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -273,6 +273,10 @@ class OC_Setup { $content.= "php_value post_max_size 512M\n"; $content.= "SetEnv htaccessWorking true\n"; $content.= "\n"; + $content.= "\n"; + $content.= "RewriteEngine on\n"; + $content.= "RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization},last]\n"; + $content.= "\n"; $content.= "Options -Indexes\n"; @file_put_contents(OC::$SERVERROOT.'/.htaccess', $content); //supress errors in case we don't have permissions for it