diff options
author | Simon Birnbach <simon@simon-birnbach.de> | 2012-04-15 15:59:57 +0200 |
---|---|---|
committer | Simon Birnbach <simon@simon-birnbach.de> | 2012-04-15 15:59:57 +0200 |
commit | a384fcb99fc3a12d7dac937398bf827c79e86098 (patch) | |
tree | 55a631751578cd1f642e5fa0f88fd2290509b126 /lib | |
parent | 4e89a0faf652f2f100cca47cca54a3b35e720aad (diff) | |
parent | 38cb716a572a8af136f6260089bc486413c6ca9f (diff) | |
download | nextcloud-server-a384fcb99fc3a12d7dac937398bf827c79e86098.tar.gz nextcloud-server-a384fcb99fc3a12d7dac937398bf827c79e86098.zip |
Merge git://gitorious.org/owncloud/owncloud
Conflicts:
files/css/files.css
files/js/files.js
Diffstat (limited to 'lib')
43 files changed, 2627 insertions, 1131 deletions
diff --git a/lib/app.php b/lib/app.php index f841180ebad..bd432109b23 100644..100755 --- a/lib/app.php +++ b/lib/app.php @@ -34,16 +34,21 @@ class OC_App{ static private $settingsForms = array(); static private $adminForms = array(); static private $personalForms = array(); + static private $appInfo = array(); + static private $appTypes = array(); /** * @brief loads all apps + * @param array $types * @returns true/false * * This function walks through the owncloud directory and loads all apps * it can find. A directory contains an app if the file /appinfo/app.php * exists. + * + * if $types is set, only apps of those types will be loaded */ - public static function loadApps(){ + public static function loadApps($types=null){ // Did we allready load everything? if( self::$init ){ return true; @@ -51,13 +56,15 @@ class OC_App{ // Our very own core apps are hardcoded foreach( array('files', 'settings') as $app ){ - require( $app.'/appinfo/app.php' ); + if(is_null($types)){ + require( $app.'/appinfo/app.php' ); + } } // The rest comes here - $apps = OC_Appconfig::getApps(); + $apps = self::getEnabledApps(); foreach( $apps as $app ){ - if( self::isEnabled( $app )){ + if(is_null($types) or self::isType($app,$types)){ if(is_file(OC::$APPSROOT.'/apps/'.$app.'/appinfo/app.php')){ require( $app.'/appinfo/app.php' ); } @@ -71,6 +78,63 @@ class OC_App{ } /** + * check if an app is of a sepcific type + * @param string $app + * @param string/array $types + */ + public static function isType($app,$types){ + if(is_string($types)){ + $types=array($types); + } + $appTypes=self::getAppTypes($app); + foreach($types as $type){ + if(array_search($type,$appTypes)!==false){ + return true; + } + } + return false; + } + + /** + * get the types of an app + * @param string $app + * @return array + */ + private static function getAppTypes($app){ + //load the cache + if(count(self::$appTypes)==0){ + self::$appTypes=OC_Appconfig::getValues(false,'types'); + } + + //get it from info.xml if we haven't cached it + if(!isset(self::$appTypes[$app])){ + $appData=self::getAppInfo($app); + if(isset($appData['types'])){ + self::$appTypes[$app]=$appData['types']; + }else{ + self::$appTypes[$app]=array(); + } + + OC_Appconfig::setValue($app,'types',implode(',',self::$appTypes[$app])); + } + + return explode(',',self::$appTypes[$app]); + } + + /** + * get all enabled apps + */ + public static function getEnabledApps(){ + $apps=array(); + $query = OC_DB::prepare( 'SELECT appid FROM *PREFIX*appconfig WHERE configkey = \'enabled\' AND configvalue=\'yes\'' ); + $result=$query->execute(); + while($row=$result->fetchRow()){ + $apps[]=$row['appid']; + } + return $apps; + } + + /** * @brief checks whether or not an app is enabled * @param $app app * @returns true/false @@ -98,13 +162,18 @@ class OC_App{ if(!is_numeric($app)){ OC_Installer::installShippedApp($app); }else{ - $download=OC_OCSClient::getApplicationDownload($app,1); - if(isset($download['downloadlink']) and $download['downloadlink']<>'') { + $download=OC_OCSClient::getApplicationDownload($app,1); + if(isset($download['downloadlink']) and $download['downloadlink']!='') { $app=OC_Installer::installApp(array('source'=>'http','href'=>$download['downloadlink'])); } } } - OC_Appconfig::setValue( $app, 'enabled', 'yes' ); + if($app!==false){ + OC_Appconfig::setValue( $app, 'enabled', 'yes' ); + return true; + }else{ + return false; + } } /** @@ -208,12 +277,15 @@ class OC_App{ * entries are sorted by the key 'order' ascending. */ public static function getSettingsNavigation(){ - $l=new OC_L10N('core'); + $l=OC_L10N::get('core'); + $settings = array(); // by default, settings only contain the help menu - $settings = array( - array( "id" => "help", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "help.php" ), "name" => $l->t("Help"), "icon" => OC_Helper::imagePath( "settings", "help.svg" )) - ); + if(OC_Config::getValue('knowledgebaseenabled', true)==true){ + $settings = array( + array( "id" => "help", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "help.php" ), "name" => $l->t("Help"), "icon" => OC_Helper::imagePath( "settings", "help.svg" )) + ); + } // if the user is logged-in if (OC_User::isLoggedIn()) { @@ -258,28 +330,54 @@ class OC_App{ return $list; } + + /** + * get the last version of the app, either from appinfo/version or from appinfo/info.xml + */ + public static function getAppVersion($appid){ + $file=OC::$APPSROOT.'/apps/'.$appid.'/appinfo/version'; + $version=@file_get_contents($file); + if($version){ + return $version; + }else{ + $appData=self::getAppInfo($appid); + return $appData['version']; + } + } /** * @brief Read app metadata from the info.xml file * @param string $appid id of the app or the path of the info.xml file + * @param boolean path (optional) * @returns array */ - public static function getAppInfo($appid){ - if(is_file($appid)){ + public static function getAppInfo($appid,$path=false){ + if($path){ $file=$appid; }else{ - $file=OC::$APPSROOT.'/apps/'.$appid.'/appinfo/info.xml'; - if(!is_file($file)){ - return array(); + if(isset(self::$appInfo[$appid])){ + return self::$appInfo[$appid]; } + $file=OC::$APPSROOT.'/apps/'.$appid.'/appinfo/info.xml'; } $data=array(); - $content=file_get_contents($file); + $content=@file_get_contents($file); + if(!$content){ + return; + } $xml = new SimpleXMLElement($content); $data['info']=array(); foreach($xml->children() as $child){ - $data[$child->getName()]=(string)$child; + if($child->getName()=='types'){ + $data['types']=array(); + foreach($child->children() as $type){ + $data['types'][]=$type->getName(); + } + }else{ + $data[$child->getName()]=(string)$child; + } } + self::$appInfo[$appid]=$data; return $data; } @@ -325,6 +423,7 @@ class OC_App{ $source=self::$settingsForms; break; case 'admin': + $forms[] = include 'files/admin.php'; //hardcode own apps $source=self::$adminForms; break; case 'personal': @@ -371,26 +470,37 @@ class OC_App{ } return $apps; } - + /** * check if any apps need updating and update those */ public static function updateApps(){ // The rest comes here - $apps = OC_Appconfig::getApps(); - foreach( $apps as $app ){ - $installedVersion=OC_Appconfig::getValue($app,'installed_version'); - $appInfo=OC_App::getAppInfo($app); - if (isset($appInfo['version'])) { - $currentVersion=$appInfo['version']; + $versions = self::getAppVersions(); + foreach( $versions as $app=>$installedVersion ){ + $currentVersion=OC_App::getAppVersion($app); + if ($currentVersion) { if (version_compare($currentVersion, $installedVersion, '>')) { OC_App::updateApp($app); - OC_Appconfig::setValue($app,'installed_version',$appInfo['version']); + OC_Appconfig::setValue($app,'installed_version',OC_App::getAppVersion($app)); } } } } - + + /** + * get the installed version of all papps + */ + public static function getAppVersions(){ + $versions=array(); + $query = OC_DB::prepare( 'SELECT appid, configvalue FROM *PREFIX*appconfig WHERE configkey = \'installed_version\'' ); + $result = $query->execute(); + while($row = $result->fetchRow()){ + $versions[$row['appid']]=$row['configvalue']; + } + return $versions; + } + /** * update the database for the app and call the update script * @param string appid diff --git a/lib/appconfig.php b/lib/appconfig.php index 2b5cef59adc..5aaaadd9c4a 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -163,4 +163,38 @@ class OC_Appconfig{ return true; } + + /** + * get multiply values, either the app or key can be used as wildcard by setting it to false + * @param app + * @param key + * @return array + */ + public static function getValues($app,$key){ + if($app!==false and $key!==false){ + return false; + } + $where='WHERE'; + $fields='configvalue'; + $params=array(); + if($app!==false){ + $where.=' appid = ?'; + $fields.=', configkey'; + $params[]=$app; + $key='configkey'; + }else{ + $fields.=', appid'; + $where.=' configkey = ?'; + $params[]=$key; + $key='appid'; + } + $queryString='SELECT '.$fields.' FROM *PREFIX*appconfig '.$where; + $query=OC_DB::prepare($queryString); + $result=$query->execute($params); + $values=array(); + while($row=$result->fetchRow()){ + $values[$row[$key]]=$row['configvalue']; + } + return $values; + } } diff --git a/lib/base.php b/lib/base.php index 9995544f14e..f3dacdc0f76 100644 --- a/lib/base.php +++ b/lib/base.php @@ -114,42 +114,7 @@ class OC{ return($mode); } - public static function init(){ - // register autoloader - spl_autoload_register(array('OC','autoload')); - - // set some stuff - //ob_start(); - error_reporting(E_ALL | E_STRICT); - if (defined('DEBUG') && DEBUG){ - ini_set('display_errors', 1); - } - - date_default_timezone_set('Europe/Berlin'); - ini_set('arg_separator.output','&'); - - //set http auth headers for apache+php-cgi work around - if (isset($_SERVER['HTTP_AUTHORIZATION']) && 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); - } - - //set http auth headers for apache+php-cgi work around if variable gets renamed by apache - if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['REDIRECT_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); - } - - // register the stream wrappers - require_once('streamwrappers.php'); - stream_wrapper_register("fakedir", "OC_FakeDirStream"); - stream_wrapper_register('static', 'OC_StaticStreamWrapper'); - stream_wrapper_register('close', 'OC_CloseStreamWrapper'); - + public static function initPaths(){ // calculate the documentroot OC::$DOCUMENTROOT=realpath($_SERVER['DOCUMENT_ROOT']); OC::$SERVERROOT=str_replace("\\",'/',substr(__FILE__,0,-13)); @@ -174,6 +139,12 @@ class OC{ OC::$WEBROOT='/'.OC::$WEBROOT; } + // ensure we can find OC_Config + set_include_path( + OC::$SERVERROOT.'/lib'.PATH_SEPARATOR. + get_include_path() + ); + // search the 3rdparty folder if(OC_Config::getValue('3rdpartyroot', '')<>'' and OC_Config::getValue('3rdpartyurl', '')<>''){ OC::$THIRDPARTYROOT=OC_Config::getValue('3rdpartyroot', ''); @@ -211,14 +182,18 @@ class OC{ get_include_path().PATH_SEPARATOR. OC::$SERVERROOT ); + } + public static function checkInstalled() { // Redirect to installer if not installed if (!OC_Config::getValue('installed', false) && OC::$SUBURI != '/index.php') { $url = 'http://'.$_SERVER['SERVER_NAME'].OC::$WEBROOT.'/index.php'; header("Location: $url"); exit(); } + } + public static function checkSSL() { // redirect to https site if configured if( OC_Config::getValue( "forcessl", false )){ ini_set("session.cookie_secure", "on"); @@ -228,7 +203,9 @@ class OC{ exit(); } } + } + public static function checkUpgrade() { if(OC_Config::getValue('installed', false)){ $installedVersion=OC_Config::getValue('version','0.0.0'); $currentVersion=implode('.',OC_Util::getVersion()); @@ -250,10 +227,9 @@ class OC{ OC_App::updateApps(); } + } - ini_set('session.cookie_httponly','1;'); - session_start(); - + public static function initTemplateEngine() { // if the formfactor is not yet autodetected do the autodetection now. For possible forfactors check the detectFormfactor documentation if(!isset($_SESSION['formfactor'])){ $_SESSION['formfactor']=OC::detectFormfactor(); @@ -263,7 +239,6 @@ class OC{ $_SESSION['formfactor']=$_GET['formfactor']; } - // Add the stuff we need always OC_Util::addScript( "jquery-1.6.4.min" ); OC_Util::addScript( "jquery-ui-1.8.16.custom.min" ); @@ -280,6 +255,76 @@ class OC{ OC_Util::addStyle( "multiselect" ); OC_Util::addStyle( "jquery-ui-1.8.16.custom" ); OC_Util::addStyle( "jquery-tipsy" ); + } + + public static function initSession() { + ini_set('session.cookie_httponly','1;'); + session_start(); + } + + public static function init(){ + // register autoloader + spl_autoload_register(array('OC','autoload')); + setlocale(LC_ALL, 'en_US.UTF-8'); + + // set some stuff + //ob_start(); + error_reporting(E_ALL | E_STRICT); + if (defined('DEBUG') && DEBUG){ + ini_set('display_errors', 1); + } + + date_default_timezone_set('Europe/Berlin'); + ini_set('arg_separator.output','&'); + + //try to configure php to enable big file uploads. + //this doesn´t work always depending on the webserver and php configuration. + //Let´s try to overwrite some defaults anyways + + //try to set the maximum execution time to 60min + @set_time_limit(3600); + @ini_set('max_execution_time',3600); + @ini_set('max_input_time',3600); + + //try to set the maximum filesize to 10G + @ini_set('upload_max_filesize','10G'); + @ini_set('post_max_size','10G'); + @ini_set('file_uploads','50'); + + //try to set the session lifetime to 60min + @ini_set('gc_maxlifetime','3600'); + + + //set http auth headers for apache+php-cgi work around + if (isset($_SERVER['HTTP_AUTHORIZATION']) && 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); + } + + //set http auth headers for apache+php-cgi work around if variable gets renamed by apache + if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['REDIRECT_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); + } + + self::initPaths(); + + // register the stream wrappers + require_once('streamwrappers.php'); + stream_wrapper_register("fakedir", "OC_FakeDirStream"); + stream_wrapper_register('static', 'OC_StaticStreamWrapper'); + stream_wrapper_register('close', 'OC_CloseStreamWrapper'); + + self::checkInstalled(); + self::checkSSL(); + + self::initSession(); + self::initTemplateEngine(); + self::checkUpgrade(); $errors=OC_Util::checkServer(); if(count($errors)>0) { @@ -301,7 +346,7 @@ class OC{ OC_User::useBackend( OC_Config::getValue( "userbackend", "database" )); - OC_Group::setBackend( OC_Config::getValue( "groupbackend", "database" )); + OC_Group::useBackend(new OC_Group_Database()); // Set up file system unless forbidden global $RUNTIME_NOSETUPFS; @@ -312,9 +357,17 @@ class OC{ // Load Apps // This includes plugins for users and filesystems as well global $RUNTIME_NOAPPS; + global $RUNTIME_APPTYPES; if(!$RUNTIME_NOAPPS ){ - OC_App::loadApps(); + if($RUNTIME_APPTYPES){ + OC_App::loadApps($RUNTIME_APPTYPES); + }else{ + OC_App::loadApps(); + } } + + // Check for blacklisted files + OC_Hook::connect('OC_Filesystem','write','OC_Filesystem','isBlacklisted'); //make sure temporary files are cleaned up register_shutdown_function(array('OC_Helper','cleanTmp')); diff --git a/lib/connect.php b/lib/connect.php deleted file mode 100644 index 22e48750a62..00000000000 --- a/lib/connect.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php - -/** -* ownCloud -* -* @author Frank Karlitschek -* @copyright 2010 Frank Karlitschek karlitschek@kde.org -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU AFFERO GENERAL PUBLIC LICENSE for more details. -* -* You should have received a copy of the GNU Affero General Public -* License along with this library. If not, see <http://www.gnu.org/licenses/>. -* -*/ - -/** - * Class for connecting multiply ownCloud installations - * - */ -class OC_Connect{ - static private $clouds=array(); - - static function connect($path,$user,$password){ - $cloud=new OC_REMOTE_CLOUD($path,$user,$password); - if($cloud->connected){ - self::$clouds[$path]=$cloud; - return $cloud; - }else{ - return false; - } - } -} diff --git a/lib/db.php b/lib/db.php index 9fab51edfcd..2f74cc6dd95 100644 --- a/lib/db.php +++ b/lib/db.php @@ -36,8 +36,26 @@ class OC_DB { static private $affected=0; static private $result=false; static private $inTransaction=false; + static private $prefix=null; + static private $type=null; /** + * check which backend we should use + * @return BACKEND_MDB2 or BACKEND_PDO + */ + private static function getDBBackend(){ + $backend=self::BACKEND_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) + $type = OC_Config::getValue( "dbtype", "sqlite" ); + if($type=='sqlite3') $type='sqlite'; + $drivers=PDO::getAvailableDrivers(); + if(array_search($type,$drivers)!==false){ + $backend=self::BACKEND_PDO; + } + } + } + + /** * @brief connects to the database * @returns true if connection can be established or nothing (die()) * @@ -48,15 +66,7 @@ class OC_DB { return; } if(is_null($backend)){ - $backend=self::BACKEND_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) - $type = OC_Config::getValue( "dbtype", "sqlite" ); - if($type=='sqlite3') $type='sqlite'; - $drivers=PDO::getAvailableDrivers(); - if(array_search($type,$drivers)!==false){ - $backend=self::BACKEND_PDO; - } - } + $backend=self::getDBBackend(); } if($backend==self::BACKEND_PDO){ self::connectPDO(); @@ -86,6 +96,7 @@ class OC_DB { $user = OC_Config::getValue( "dbuser", "" ); $pass = OC_Config::getValue( "dbpassword", "" ); $type = OC_Config::getValue( "dbtype", "sqlite" ); + $opts = array(); $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' ); // do nothing if the connection already has been established @@ -100,13 +111,14 @@ class OC_DB { break; case 'mysql': $dsn='mysql:dbname='.$name.';host='.$host; + $opts[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES 'UTF8'"; break; case 'pgsql': $dsn='pgsql:dbname='.$name.';host='.$host; break; } try{ - self::$PDO=new PDO($dsn,$user,$pass); + self::$PDO=new PDO($dsn,$user,$pass,$opts); }catch(PDOException $e){ echo( '<b>can not connect to database, using '.$type.'. ('.$e->getMessage().')</center>'); die(); @@ -318,9 +330,6 @@ class OC_DB { // Make changes and save them to an in-memory file $file2 = 'static://db_scheme'; - if($file2 == ''){ - die('could not create tempfile in get_temp_dir() - aborting'); - } $content = str_replace( '*dbname*', $CONFIG_DBNAME, $content ); $content = str_replace( '*dbprefix*', $CONFIG_DBTABLEPREFIX, $content ); if( $CONFIG_DBTYPE == 'pgsql' ){ //mysql support it too but sqlite doesn't @@ -424,8 +433,14 @@ class OC_DB { private static function processQuery( $query ){ self::connect(); // We need Database type and table prefix - $type = OC_Config::getValue( "dbtype", "sqlite" ); - $prefix = OC_Config::getValue( "dbtableprefix", "oc_" ); + if(is_null(self::$type)){ + self::$type=OC_Config::getValue( "dbtype", "sqlite" ); + } + $type = self::$type; + if(is_null(self::$prefix)){ + self::$prefix=OC_Config::getValue( "dbtableprefix", "oc_" ); + } + $prefix = self::$prefix; // differences in escaping of table names ('`' for mysql) and getting the current timestamp if( $type == 'sqlite' || $type == 'sqlite3' ){ @@ -486,6 +501,30 @@ class OC_DB { } /** + * @brief replaces the owncloud tables with a new set + * @param $file string path to the MDB2 xml db export file + */ + public static function replaceDB( $file ){ + + $apps = OC_App::getAllApps(); + self::beginTransaction(); + // Delete the old tables + self::removeDBStructure( OC::$SERVERROOT . '/db_structure.xml' ); + + foreach($apps as $app){ + $path = OC::$SERVERROOT.'/apps/'.$app.'/appinfo/database.xml'; + if(file_exists($path)){ + self::removeDBStructure( $path ); + } + } + + // Create new tables + self::createDBFromStructure( $file ); + self::commit(); + + } + + /** * Start a transaction */ public static function beginTransaction(){ @@ -589,3 +628,4 @@ class PDOStatementWrapper{ return $this->statement->fetchColumn($colnum); } } + diff --git a/lib/eventsource.php b/lib/eventsource.php index 523f72403c3..cf10660b94c 100644 --- a/lib/eventsource.php +++ b/lib/eventsource.php @@ -32,6 +32,7 @@ class OC_EventSource{ private $fallBackId=0; public function __construct(){ + @ob_end_clean(); header('Cache-Control: no-cache'); $this->fallback=isset($_GET['fallback']) and $_GET['fallback']=='true'; if($this->fallback){ @@ -58,7 +59,7 @@ class OC_EventSource{ $type=null; } if($this->fallback){ - $response='<script type="text/javascript">window.parent.OC.EventSource.fallBackCallBack('.$this->fallBackId.',"'.$type.'","'.json_encode($data).'")</script>'.PHP_EOL; + $response='<script type="text/javascript">window.parent.OC.EventSource.fallBackCallBack('.$this->fallBackId.',"'.$type.'",'.json_encode($data).')</script>'.PHP_EOL; echo $response; }else{ if($type){ diff --git a/lib/filecache.php b/lib/filecache.php index 280a9929db0..24984c2ccff 100644 --- a/lib/filecache.php +++ b/lib/filecache.php @@ -59,8 +59,8 @@ class OC_FileCache{ $root=''; } $path=$root.$path; - $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path=?'); - $result=$query->execute(array($path))->fetchRow(); + $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?'); + $result=$query->execute(array(md5($path)))->fetchRow(); if(is_array($result)){ return $result; }else{ @@ -111,8 +111,8 @@ class OC_FileCache{ } $mimePart=dirname($data['mimetype']); $user=OC_User::getUser(); - $query=OC_DB::prepare('INSERT INTO *PREFIX*fscache(parent, name, path, size, mtime, ctime, mimetype, mimepart,user,writable,encrypted,versioned) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)'); - $result=$query->execute(array($parent,basename($path),$path,$data['size'],$data['mtime'],$data['ctime'],$data['mimetype'],$mimePart,$user,$data['writable'],$data['encrypted'],$data['versioned'])); + $query=OC_DB::prepare('INSERT INTO *PREFIX*fscache(parent, name, path, path_hash, size, mtime, ctime, mimetype, mimepart,user,writable,encrypted,versioned) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)'); + $result=$query->execute(array($parent,basename($path),$path,md5($path),$data['size'],$data['mtime'],$data['ctime'],$data['mimetype'],$mimePart,$user,$data['writable'],$data['encrypted'],$data['versioned'])); if(OC_DB::isError($result)){ OC_Log::write('files','error while writing file('.$path.') to cache',OC_Log::ERROR); } @@ -162,8 +162,8 @@ class OC_FileCache{ $oldPath=$root.$oldPath; $newPath=$root.$newPath; $newParent=self::getParentId($newPath); - $query=OC_DB::prepare('UPDATE *PREFIX*fscache SET parent=? ,name=?, path=? WHERE path=?'); - $query->execute(array($newParent,basename($newPath),$newPath,$oldPath)); + $query=OC_DB::prepare('UPDATE *PREFIX*fscache SET parent=? ,name=?, path=?, path_hash=? WHERE path_hash=?'); + $query->execute(array($newParent,basename($newPath),$newPath,md5($newPath),md5($oldPath))); } /** @@ -240,7 +240,7 @@ class OC_FileCache{ * - encrypted * - versioned */ - public static function getFolderContent($path,$root=''){ + public static function getFolderContent($path,$root='',$mimetype_filter=''){ if(self::isUpdated($path,$root)){ self::updateFolder($path,$root); } @@ -252,8 +252,8 @@ class OC_FileCache{ } $path=$root.$path; $parent=self::getFileId($path); - $query=OC_DB::prepare('SELECT name,ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE parent=?'); - $result=$query->execute(array($parent))->fetchAll(); + $query=OC_DB::prepare('SELECT name,ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE parent=? AND (mimetype LIKE ? OR mimetype = ?)'); + $result=$query->execute(array($parent, $mimetype_filter.'%', 'httpd/unix-directory'))->fetchAll(); if(is_array($result)){ return $result; }else{ @@ -281,16 +281,17 @@ class OC_FileCache{ /** * get the file id as used in the cache + * unlike the public getId, full paths are used here (/usename/files/foo instead of /foo) * @param string $path * @return int */ private static function getFileId($path){ - $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE path=?'); + $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE path_hash=?'); if(OC_DB::isError($query)){ OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR); return -1; } - $result=$query->execute(array($path)); + $result=$query->execute(array(md5($path))); if(OC_DB::isError($result)){ OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR); return -1; @@ -303,6 +304,39 @@ class OC_FileCache{ return -1; } } + + /** + * get the file id as used in the cache + * @param string path + * @param string root (optional) + * @return int + */ + public static function getId($path,$root=''){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + } + if($root=='/'){ + $root=''; + } + $path=$root.$path; + return self::getFileId($path); + } + + /** + * get the file path from the id, relative to the home folder of the user + * @param int id + * @param string user (optional) + * @return string + */ + public static function getPath($id,$user=''){ + if(!$user){ + $user=OC_User::getUser(); + } + $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE id=? AND user=?'); + $result=$query->execute(array($id,$user)); + $row=$result->fetchRow(); + return $row['path']; + } /** * get the file id of the parent folder, taking into account '/' has no parent @@ -367,8 +401,8 @@ class OC_FileCache{ } } $path=$root.$path; - $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path=?'); - $result=$query->execute(array($path))->fetchRow(); + $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?'); + $result=$query->execute(array(md5($path)))->fetchRow(); if(is_array($result)){ if(isset(self::$savedData[$path])){ $result=array_merge($result,self::$savedData[$path]); @@ -389,8 +423,8 @@ class OC_FileCache{ } } $path=$root.$path; - $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE path=?'); - $result=$query->execute(array($path)); + $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE path_hash=?'); + $result=$query->execute(array(md5($path))); if($row=$result->fetchRow()){ return $row['size']; }else{//file not in cache @@ -469,6 +503,10 @@ class OC_FileCache{ * @param string root (optionak) */ public static function scan($path,$eventSource=false,&$count=0,$root=''){ + if($eventSource){ + $eventSource->send('scanning',array('file'=>$path,'count'=>$count)); + } + $lastSend=$count; if(!$root){ $view=OC_Filesystem::getView(); }else{ @@ -482,13 +520,14 @@ class OC_FileCache{ if($filename != '.' and $filename != '..'){ $file=$path.'/'.$filename; if($view->is_dir($file.'/')){ - if($eventSource){ - $eventSource->send('scanning',array('file'=>$file,'count'=>$count)); - } self::scan($file,$eventSource,$count,$root); }else{ $totalSize+=self::scanFile($file,$root); $count++; + if($count>$lastSend+25 and $eventSource){ + $lastSend=$count; + $eventSource->send('scanning',array('file'=>$path,'count'=>$count)); + } } } } @@ -579,8 +618,8 @@ class OC_FileCache{ $mtime=$view->filemtime($path); $isDir=$view->is_dir($path); $path=$root.$path; - $query=OC_DB::prepare('SELECT mtime FROM *PREFIX*fscache WHERE path=?'); - $result=$query->execute(array($path)); + $query=OC_DB::prepare('SELECT mtime FROM *PREFIX*fscache WHERE path_hash=?'); + $result=$query->execute(array(md5($path))); if($row=$result->fetchRow()){ $cachedMTime=$row['mtime']; return ($mtime>$cachedMTime); @@ -637,6 +676,14 @@ class OC_FileCache{ self::fileSystemWatcherWrite(array('path'=>$path),$root); } } + + /** + * clean old pre-path_hash entries + */ + public static function clean(){ + $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE LENGTH(path_hash)<30'); + $query->execute(); + } } //watch for changes and try to keep the cache up to date diff --git a/lib/files.php b/lib/files.php index 1f8331afb21..a7b83149574 100644 --- a/lib/files.php +++ b/lib/files.php @@ -32,11 +32,11 @@ class OC_Files { * get the content of a directory * @param dir $directory */ - public static function getDirectoryContent($directory){ + public static function getDirectoryContent($directory, $mimetype_filter = ''){ if(strpos($directory,OC::$CONFIG_DATADIRECTORY)===0){ $directory=substr($directory,strlen(OC::$CONFIG_DATADIRECTORY)); } - $files=OC_FileCache::getFolderContent($directory); + $files=OC_FileCache::getFolderContent($directory, '', $mimetype_filter); foreach($files as &$file){ $file['directory']=$directory; $file['type']=($file['mimetype']=='httpd/unix-directory')?'dir':'file'; @@ -59,9 +59,12 @@ class OC_Files { } if(is_array($files)){ + self::validateZipDownload($dir,$files); + $executionTime = intval(ini_get('max_execution_time')); + set_time_limit(0); $zip = new ZipArchive(); - $filename = get_temp_dir()."/ownCloud.zip"; - if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) { + $filename = OC_Helper::tmpFile('.zip'); + if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==TRUE) { exit("cannot open <$filename>\n"); } foreach($files as $file){ @@ -75,15 +78,20 @@ class OC_Files { } } $zip->close(); + set_time_limit($executionTime); }elseif(OC_Filesystem::is_dir($dir.'/'.$files)){ + self::validateZipDownload($dir,$files); + $executionTime = intval(ini_get('max_execution_time')); + set_time_limit(0); $zip = new ZipArchive(); - $filename = get_temp_dir()."/ownCloud.zip"; - if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) { + $filename = OC_Helper::tmpFile('.zip'); + if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==TRUE) { exit("cannot open <$filename>\n"); } $file=$dir.'/'.$files; self::zipAddDir($file,$zip); $zip->close(); + set_time_limit($executionTime); }else{ $zip=false; $filename=$dir.'/'.$files; @@ -96,15 +104,15 @@ class OC_Files { header('Content-Type: application/zip'); header('Content-Length: ' . filesize($filename)); }else{ - header('Content-Type: ' . OC_Filesystem::getMimeType($filename)); - header('Content-Length: ' . OC_Filesystem::filesize($filename)); + $fileData=OC_FileCache::get($filename); + header('Content-Type: ' . $fileData['mimetype']); + header('Content-Length: ' . $fileData['size']); } }elseif($zip or !OC_Filesystem::file_exists($filename)){ header("HTTP/1.0 404 Not Found"); $tmpl = new OC_Template( '', '404', 'guest' ); $tmpl->assign('file',$filename); $tmpl->printPage(); -// die('404 Not Found'); }else{ header("HTTP/1.0 403 Forbidden"); die('403 Forbidden'); @@ -210,6 +218,55 @@ class OC_Files { } /** + * checks if the selected files are within the size constraint. If not, outputs an error page. + * + * @param dir $dir + * @param files $files + */ + static function validateZipDownload($dir, $files) { + if(!OC_Config::getValue('allowZipDownload', true)) { + $l = OC_L10N::get('files'); + header("HTTP/1.0 409 Conflict"); + $tmpl = new OC_Template( '', 'error', 'user' ); + $errors = array( + array( + 'error' => $l->t('ZIP download is turned off.'), + 'hint' => $l->t('Files need to be downloaded one by one.') . '<br/><a href="javascript:history.back()">' . $l->t('Back to Files') . '</a>', + ) + ); + $tmpl->assign('errors', $errors); + $tmpl->printPage(); + exit; + } + + $zipLimit = OC_Config::getValue('maxZipInputSize', OC_Helper::computerFileSize('800 MB')); + if($zipLimit > 0) { + $totalsize = 0; + if(is_array($files)){ + foreach($files as $file){ + $totalsize += OC_Filesystem::filesize($dir.'/'.$file); + } + }else{ + $totalsize += OC_Filesystem::filesize($dir.'/'.$files); + } + if($totalsize > $zipLimit) { + $l = OC_L10N::get('files'); + header("HTTP/1.0 409 Conflict"); + $tmpl = new OC_Template( '', 'error', 'user' ); + $errors = array( + array( + 'error' => $l->t('Selected files too large to generate zip file.'), + 'hint' => 'Download the files in smaller chunks, seperately or kindly ask your administrator.<br/><a href="javascript:history.back()">' . $l->t('Back to Files') . '</a>', + ) + ); + $tmpl->assign('errors', $errors); + $tmpl->printPage(); + exit; + } + } + } + + /** * try to detect the mime type of a file * * @param string path @@ -256,21 +313,58 @@ class OC_Files { return false; } } - + /** * set the maximum upload size limit for apache hosts using .htaccess * @param int size filesisze in bytes + * @return false on failure, size on success */ static function setUploadLimit($size){ - $size=OC_Helper::humanFileSize($size); - $size=substr($size,0,-1);//strip the B - $size=str_replace(' ','',$size); //remove the space between the size and the postfix - $content = "ErrorDocument 404 /".OC::$WEBROOT."/core/templates/404.php\n";//custom 404 error page - $content.= "php_value upload_max_filesize $size\n";//upload limit - $content.= "php_value post_max_size $size\n"; - $content.= "SetEnv htaccessWorking true\n"; - $content.= "Options -Indexes\n"; - @file_put_contents(OC::$SERVERROOT.'/.htaccess', $content); //supress errors in case we don't have permissions for it + //don't allow user to break his config -- upper boundary + if($size > PHP_INT_MAX) { + //max size is always 1 byte lower than computerFileSize returns + if($size > PHP_INT_MAX+1) + return false; + $size -=1; + } else { + $size=OC_Helper::humanFileSize($size); + $size=substr($size,0,-1);//strip the B + $size=str_replace(' ','',$size); //remove the space between the size and the postfix + } + + //don't allow user to break his config -- broken or malicious size input + if(intval($size) == 0) { + return false; + } + + $htaccess = @file_get_contents(OC::$SERVERROOT.'/.htaccess'); //supress errors in case we don't have permissions for + if(!$htaccess) { + return false; + } + + $phpValueKeys = array( + 'upload_max_filesize', + 'post_max_size' + ); + + foreach($phpValueKeys as $key) { + $pattern = '/php_value '.$key.' (\S)*/'; + $setting = 'php_value '.$key.' '.$size; + $hasReplaced = 0; + $content = preg_replace($pattern, $setting, $htaccess, 1, $hasReplaced); + if($content !== NULL) { + $htaccess = $content; + } + if($hasReplaced == 0) { + $htaccess .= "\n" . $setting; + } + } + + //supress errors in case we don't have permissions for it + if(@file_put_contents(OC::$SERVERROOT.'/.htaccess', $htaccess)) { + return OC_Helper::computerFileSize($size); + } + return false; } /** diff --git a/lib/filestorage/common.php b/lib/filestorage/common.php index f632474df01..f0bfc064cb5 100644 --- a/lib/filestorage/common.php +++ b/lib/filestorage/common.php @@ -100,11 +100,11 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { } $head=fread($source,8192);//8kb should suffice to determine a mimetype if($pos=strrpos($path,'.')){ - $extention=substr($path,$pos); + $extension=substr($path,$pos); }else{ - $extention=''; + $extension=''; } - $tmpFile=OC_Helper::tmpFile($extention); + $tmpFile=OC_Helper::tmpFile($extension); file_put_contents($tmpFile,$head); $mime=OC_Helper::getMimeType($tmpFile); unlink($tmpFile); @@ -129,11 +129,11 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { return false; } if($pos=strrpos($path,'.')){ - $extention=substr($path,$pos); + $extension=substr($path,$pos); }else{ - $extention=''; + $extension=''; } - $tmpFile=OC_Helper::tmpFile($extention); + $tmpFile=OC_Helper::tmpFile($extension); $target=fopen($tmpFile,'w'); $count=OC_Helper::streamCopy($source,$target); return $tmpFile; diff --git a/lib/filestorage/google.php b/lib/filestorage/google.php deleted file mode 100644 index 49985548382..00000000000 --- a/lib/filestorage/google.php +++ /dev/null @@ -1,341 +0,0 @@ -<?php - -/** -* ownCloud -* -* @author Michael Gapczynski -* @copyright 2012 Michael Gapczynski mtgap@owncloud.com -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU AFFERO GENERAL PUBLIC LICENSE for more details. -* -* You should have received a copy of the GNU Affero General Public -* License along with this library. If not, see <http://www.gnu.org/licenses/>. -*/ - -require_once 'common.inc.php'; - -class OC_Filestorage_Google extends OC_Filestorage_Common { - - private $datadir; - private $consumer; - private $oauth_token; - private $sig_method; - private $entries; - - public function __construct($arguments) { - $this->datadir = $arguments['datadir']; - $consumer_key = isset($arguments['consumer_key']) ? $arguments['consumer_key'] : 'anonymous'; - $consumer_secret = isset($arguments['consumer_secret']) ? $arguments['consumer_secret'] : 'anonymous'; - $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret); - $this->oauth_token = new OAuthToken($arguments['token'], $arguments['token_secret']); - $this->sig_method = new OAuthSignatureMethod_HMAC_SHA1(); - $this->entries = array(); - } - - private function sendRequest($feedUri, $http_method, $postData = null) { - $feedUri = trim($feedUri); - // create an associative array from each key/value url query param pair. - $params = array(); - $pieces = explode('?', $feedUri); - if (isset($pieces[1])) { - $params = explode_assoc('=', '&', $pieces[1]); - } - // urlencode each url parameter key/value pair - $tempStr = $pieces[0]; - foreach ($params as $key => $value) { - $tempStr .= '&' . urlencode($key) . '=' . urlencode($value); - } - $feedUri = preg_replace('/&/', '?', $tempStr, 1); - $req = OAuthRequest::from_consumer_and_token($this->consumer, $this->oauth_token, $http_method, $feedUri, $params); - $req->sign_request($this->sig_method, $this->consumer, $this->oauth_token); - $auth_header = $req->to_header(); - $result = send_signed_request($http_method, $feedUri, array($auth_header, 'Content-Type: application/atom+xml', 'GData-Version: 3.0'), $postData); - // TODO Return false if error is received - if (!$result) { - return false; - } - $result = explode('<', $result, 2); - $result = isset($result[1]) ? '<'.$result[1] : $result[0]; - $dom = new DOMDocument(); - $dom->loadXML($result); - return $dom; - } - - private function getResource($path) { - if (array_key_exists($path, $this->entries)) { - return $this->entries[$path]; - } else { - $title = basename($path); - $dom = $this->sendRequest('https://docs.google.com/feeds/default/private/full?showfolders=true&title='.$title, 'GET'); - // Check if request was successful and entry exists - if ($dom && $entry = $dom->getElementsByTagName('entry')->item(0)) { - $this->entries[$path] = $entry; - return $entry; - } - return false; - } - } - - private function getExtension($entry) { - $mimetype = $this->getMimeType('', $entry); - switch($mimetype) { - case 'httpd/unix-directory': - return ''; - case 'application/vnd.oasis.opendocument.text': - return 'odt'; - case 'application/vnd.oasis.opendocument.spreadsheet': - return 'ods'; - case 'application/vnd.oasis.opendocument.presentation': - return 'pptx'; - case 'text/html': - return 'html'; - default: - return 'html'; - } - } - - - public function mkdir($path) { - $dir = dirname($path); - // Check if path parent is root directory - if ($dir == '/' || $dir == '\.' || $dir == '.') { - $feedUri = 'https://docs.google.com/feeds/default/private/full'; - // Get parent content link - } else if ($dom = $this->getResource(basename($dir))) { - $feedUri = $dom->getElementsByTagName('content')->item(0)->getAttribute('src'); - } - if (isset($feedUri)) { - $title = basename($path); - // Construct post data - $postData = '<?xml version="1.0" encoding="UTF-8"?>'; - $postData .= '<entry xmlns="http://www.w3.org/2005/Atom">'; - $postData .= '<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#folder"/>'; - $postData .= '<title>'.$title.'</title>'; - $postData .= '</entry>'; - if ($dom = $this->sendRequest($feedUri, 'POST', $postData)) { - return true; - } - } - return false; - } - - public function rmdir($path) { - return $this->unlink($path); - } - - public function opendir($path) { - if ($path == '' || $path == '/') { - $next = 'https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents'; - } else { - if ($entry = $this->getResource($path)) { - $next = $entry->getElementsByTagName('content')->item(0)->getAttribute('src'); - } else { - return false; - } - } - $files = array(); - while ($next) { - $dom = $this->sendRequest($next, 'GET'); - $links = $dom->getElementsByTagName('link'); - foreach ($links as $link) { - if ($link->getAttribute('rel') == 'next') { - $next = $link->getAttribute('src'); - break; - } else { - $next = false; - } - } - $entries = $dom->getElementsByTagName('entry'); - foreach ($entries as $entry) { - $name = $entry->getElementsByTagName('title')->item(0)->nodeValue; - // Google Docs resources don't always include extensions in title - if (!strpos($name, '.')) { - $name .= '.'.$this->getExtension($entry); - } - $files[] = $name; - // Cache entry for future use - $this->entries[$name] = $entry; - } - } - OC_FakeDirStream::$dirs['google'] = $files; - return opendir('fakedir://google'); - } - - public function stat($path) { - if ($path == '' || $path == '/') { - $stat['size'] = $this->free_space($path); - $stat['atime'] = time(); - $stat['mtime'] = time(); - $stat['ctime'] = time(); - } else if ($entry = $this->getResource($path)) { - // NOTE: Native resources don't have a file size - $stat['size'] = $entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'quotaBytesUsed')->item(0)->nodeValue; - $stat['atime'] = strtotime($entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'lastViewed')->item(0)->nodeValue); - $stat['mtime'] = strtotime($entry->getElementsByTagName('updated')->item(0)->nodeValue); - $stat['ctime'] = strtotime($entry->getElementsByTagName('published')->item(0)->nodeValue); - } - return $stat; - } - - public function filetype($path) { - if ($path == '' || $path == '/') { - return 'dir'; - } else if ($entry = $this->getResource($path)) { - $categories = $entry->getElementsByTagName('category'); - foreach ($categories as $category) { - if ($category->getAttribute('scheme') == 'http://schemas.google.com/g/2005#kind') { - $type = $category->getAttribute('label'); - if (strlen(strstr($type, 'folder')) > 0) { - return 'dir'; - } else { - return 'file'; - } - } - } - } - return false; - } - - public function is_readable($path) { - return true; - } - - public function is_writable($path) { - if ($path == '' || $path == '/') { - return true; - } else if ($entry = $this->getResource($path)) { - // Check if edit or edit-media links exist - $links = $entry->getElementsByTagName('link'); - foreach ($links as $link) { - if ($link->getAttribute('rel') == 'edit') { - return true; - } else if ($link->getAttribute('rel') == 'edit-media') { - return true; - } - } - } - return false; - } - - public function file_exists($path) { - if ($path == '' || $path == '/') { - return true; - } else if ($this->getResource($path)) { - return true; - } - return false; - } - - public function unlink($path) { - // Get resource self link to trash resource - if ($entry = $this->getResource($path)) { - $links = $entry->getElementsByTagName('link'); - foreach ($links as $link) { - if ($link->getAttribute('rel') == 'self') { - $feedUri = $link->getAttribute('href'); - } - } - } - if (isset($feedUri)) { - $this->sendRequest($feedUri, 'DELETE'); - return true; - } - return false; - } - - public function rename($path1, $path2) { - // TODO Add support for moving to different collections - // Get resource edit link to rename resource - if ($entry = $this->getResource($path1)) { - $etag = $entry->getElementsByTagName('entry')->item(0)->getAttribute('gd:etag'); - $links = $entry->getElementsByTagName('link'); - foreach ($links as $link) { - if ($link->getAttribute('rel') == 'edit') { - $feedUri = $link->getAttribute('href'); - } - } - } - if (isset($etag) && isset($feedUri)) { - $title = basename($path2); - // Construct post data - $postData = '<?xml version="1.0" encoding="UTF-8"?>'; - $postData .= '<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007" xmlns:gd="http://schemas.google.com/g/2005" gd:etag='.$etag.'>'; - $postData .= '<title>'.$title.'</title>'; - $postData .= '</entry>'; - $this->sendRequest($feedUri, 'PUT', $postData); - return true; - } - return false; - } - - public function fopen($path, $mode) { - if ($entry = $this->getResource($path)) { - $extension = $this->getExtension($path); - $downloadUri = $entry->getElementsByTagName('content')->item(0)->getAttribute('src'); - // TODO Non-native documents don't need these additional parameters - $downloadUri .= '&exportFormat='.$extension.'&format='.$extension; - } - } - - public function getMimeType($path, $entry = null) { - if ($entry == null) { - if ($path == '' || $path == '/') { - return 'httpd/unix-directory'; - } else { - $entry = $this->getResource($path); - } - } - if ($entry) { - $mimetype = $entry->getElementsByTagName('content')->item(0)->getAttribute('type'); - // Native Google Docs resources often default to text/html, but it may be more useful to default to a corresponding ODF mimetype - // Collections get reported as application/atom+xml, make sure it actually is a folder and fix the mimetype - if ($mimetype == 'text/html' || $mimetype == 'application/atom+xml') { - $categories = $entry->getElementsByTagName('category'); - foreach ($categories as $category) { - if ($category->getAttribute('scheme') == 'http://schemas.google.com/g/2005#kind') { - $type = $category->getAttribute('label'); - if (strlen(strstr($type, 'folder')) > 0) { - return 'httpd/unix-directory'; - } else if (strlen(strstr($type, 'document')) > 0) { - return 'application/vnd.oasis.opendocument.text'; - } else if (strlen(strstr($type, 'spreadsheet')) > 0) { - return 'application/vnd.oasis.opendocument.spreadsheet'; - } else if (strlen(strstr($type, 'presentation')) > 0) { - return 'application/vnd.oasis.opendocument.presentation'; - } else if (strlen(strstr($type, 'drawing')) > 0) { - return 'application/vnd.oasis.opendocument.graphics'; - } else { - // If nothing matches return text/html, all native Google Docs resources can be exported as text/html - return 'text/html'; - } - } - } - } - return $mimetype; - } - return false; - } - - public function free_space($path) { - if ($dom = $this->sendRequest('https://docs.google.com/feeds/metadata/default', 'GET')) { - // NOTE: Native Google Docs resources don't count towards quota - $total = $dom->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'quotaBytesTotal')->item(0)->nodeValue; - $used = $dom->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'quotaBytesUsed')->item(0)->nodeValue; - return $total - $used; - } - return false; - } - - public function search($query) { - - } - -}
\ No newline at end of file diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php index 688501aee90..bd757f52ce7 100644 --- a/lib/filestorage/local.php +++ b/lib/filestorage/local.php @@ -86,6 +86,10 @@ class OC_Filestorage_Local extends OC_Filestorage{ return $this->delTree($path); } public function rename($path1,$path2){ + if (!$this->is_writable($path1)) { + OC_Log::write('core','unable to rename, file is not writable : '.$path1,OC_Log::ERROR); + return false; + } if(! $this->file_exists($path1)){ OC_Log::write('core','unable to rename, file does not exists : '.$path1,OC_Log::ERROR); return false; diff --git a/lib/filesystem.php b/lib/filesystem.php index 12905d189f9..dc678fba74c 100644 --- a/lib/filesystem.php +++ b/lib/filesystem.php @@ -249,6 +249,14 @@ class OC_Filesystem{ } /** + * clear all mounts and storage backends + */ + public static function clearMounts(){ + self::$mounts=array(); + self::$storages=array(); + } + + /** * mount an OC_Filestorage in our virtual filesystem * @param OC_Filestorage storage * @param string mountpoint @@ -298,6 +306,19 @@ class OC_Filesystem{ } return true; } + + /** + * checks if a file is blacklsited for storage in the filesystem + * @param array $data from hook + */ + static public function isBlacklisted($data){ + $blacklist = array('.htaccess'); + $filename = strtolower(basename($data['path'])); + if(in_array($filename,$blacklist)){ + $data['run'] = false; + } + } + /** * following functions are equivilent to their php buildin equivilents for arguments/return values. */ diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 89e0385fe9c..95873bd87cf 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -23,11 +23,11 @@ class OC_FilesystemView { private $fakeRoot=''; - + public function __construct($root){ $this->fakeRoot=$root; } - + public function getAbsolutePath($path){ if(!$path){ $path='/'; @@ -137,13 +137,16 @@ class OC_FilesystemView { } public function readfile($path){ $handle=$this->fopen($path,'r'); - $chunkSize = 1024*1024;// 1 MB chunks - while (!feof($handle)) { - echo fread($handle, $chunkSize); - @ob_flush(); - flush(); + if ($handle) { + $chunkSize = 1024*1024;// 1 MB chunks + while (!feof($handle)) { + echo fread($handle, $chunkSize); + @ob_flush(); + flush(); + } + return $this->filesize($path); } - return $this->filesize($path); + return false; } public function is_readable($path){ return $this->basicOperation('is_readable',$path); @@ -189,7 +192,7 @@ class OC_FilesystemView { return $this->basicOperation('unlink',$path,array('delete')); } public function rename($path1,$path2){ - if(OC_FileProxy::runPreProxies('rename',$path1,$path2) and $this->is_writable($path1) and OC_Filesystem::isValidPath($path2)){ + if(OC_FileProxy::runPreProxies('rename',$path1,$path2) and OC_Filesystem::isValidPath($path2)){ $run=true; OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_rename, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2, OC_Filesystem::signal_param_run => &$run)); if($run){ @@ -280,9 +283,14 @@ class OC_FilesystemView { if(OC_Filesystem::isValidPath($path)){ $source=$this->fopen($path,'r'); if($source){ - $extention=substr($path,strrpos($path,'.')); - $tmpFile=OC_Helper::tmpFile($extention); - return file_put_contents($tmpFile,$source); + $extension=''; + $extOffset=strpos($path,'.'); + if($extOffset !== false) { + $extension=substr($path,strrpos($path,'.')); + } + $tmpFile=OC_Helper::tmpFile($extension); + file_put_contents($tmpFile,$source); + return $tmpFile; } } } diff --git a/lib/group.php b/lib/group.php index fbff41e30e9..4ae9302f78b 100644 --- a/lib/group.php +++ b/lib/group.php @@ -34,57 +34,25 @@ * post_removeFromGroup(uid, gid) */ class OC_Group { - // The backend used for user management - private static $_backend; - - // Backends available (except database) - private static $_backends = array(); - - /** - * @brief registers backend - * @param $name name of the backend - * @returns true/false - * - * Makes a list of backends that can be used by other modules - */ - public static function registerBackend( $name ){ - self::$_backends[] = $name; - return true; - } - - /** - * @brief gets available backends - * @returns array of backends - * - * Returns the names of all backends. - */ - public static function getBackends(){ - return self::$_backends; - } + // The backend used for group management + private static $_usedBackends = array(); /** * @brief set the group backend * @param string $backend The backend to use for user managment * @returns true/false */ - public static function setBackend( $backend = 'database' ){ - // You'll never know what happens - if( null === $backend OR !is_string( $backend )){ - $backend = 'database'; + public static function useBackend( $backend ){ + if($backend instanceof OC_Group_Backend){ + self::$_usedBackends[]=$backend; } + } - // Load backend - switch( $backend ){ - case 'database': - case 'mysql': - case 'sqlite': - self::$_backend = new OC_Group_Database(); - break; - default: - $className = 'OC_GROUP_' . strToUpper($backend); - self::$_backend = new $className(); - break; - } + /** + * remove all used backends + */ + public static function clearBackends(){ + self::$_usedBackends=array(); } /** @@ -115,11 +83,18 @@ class OC_Group { $run = true; OC_Hook::emit( "OC_Group", "pre_createGroup", array( "run" => &$run, "gid" => $gid )); - if( $run && self::$_backend->createGroup( $gid )){ - OC_Hook::emit( "OC_Group", "post_createGroup", array( "gid" => $gid )); - return true; - } - else{ + if($run){ + //create the user in the first backend that supports creating users + foreach(self::$_usedBackends as $backend){ + if(!$backend->implementsActions(OC_GROUP_BACKEND_CREATE_GROUP)) + continue; + + $backend->createGroup($gid); + OC_Hook::emit( "OC_User", "post_createGroup", array( "gid" => $gid )); + + return true; + } + }else{ return false; } } @@ -140,11 +115,18 @@ class OC_Group { $run = true; OC_Hook::emit( "OC_Group", "pre_deleteGroup", array( "run" => &$run, "gid" => $gid )); - if( $run && self::$_backend->deleteGroup( $gid )){ - OC_Hook::emit( "OC_Group", "post_deleteGroup", array( "gid" => $gid )); - return true; - } - else{ + if($run){ + //delete the group from all backends + foreach(self::$_usedBackends as $backend){ + if(!$backend->implementsActions(OC_GROUP_BACKEND_DELETE_GROUP)) + continue; + + $backend->deleteGroup($gid); + OC_Hook::emit( "OC_User", "post_deleteGroup", array( "gid" => $gid )); + + return true; + } + }else{ return false; } } @@ -158,7 +140,15 @@ class OC_Group { * Checks whether the user is member of a group or not. */ public static function inGroup( $uid, $gid ){ - return self::$_backend->inGroup($uid, $gid); + foreach(self::$_usedBackends as $backend){ + if(!$backend->implementsActions(OC_GROUP_BACKEND_IN_GROUP)) + continue; + + if($backend->inGroup($uid,$gid)){ + return true; + } + } + return false; } /** @@ -170,10 +160,6 @@ class OC_Group { * Adds a user to a group. */ public static function addToGroup( $uid, $gid ){ - // Does the user exist? - if( !OC_User::userExists($uid)){ - return false; - } // Does the group exist? if( !OC_Group::groupExists($gid)){ return false; @@ -183,11 +169,19 @@ class OC_Group { $run = true; OC_Hook::emit( "OC_Group", "pre_addToGroup", array( "run" => &$run, "uid" => $uid, "gid" => $gid )); - if( $run && self::$_backend->addToGroup( $uid, $gid )){ - OC_Hook::emit( "OC_Group", "post_addToGroup", array( "uid" => $uid, "gid" => $gid )); - return true; - } - else{ + if($run){ + $succes=false; + + //add the user to the all backends that have the group + foreach(self::$_usedBackends as $backend){ + if(!$backend->implementsActions(OC_GROUP_BACKEND_ADD_TO_GROUP)) + continue; + + $succes|=$backend->addToGroup($uid, $gid); + OC_Hook::emit( "OC_User", "post_addToGroup", array( "uid" => $uid, "gid" => $gid )); + } + return $succes; + }else{ return false; } } @@ -204,11 +198,17 @@ class OC_Group { $run = true; OC_Hook::emit( "OC_Group", "pre_removeFromGroup", array( "run" => &$run, "uid" => $uid, "gid" => $gid )); - if( $run && self::$_backend->removeFromGroup( $uid, $gid )){ - OC_Hook::emit( "OC_Group", "post_removeFromGroup", array( "uid" => $uid, "gid" => $gid )); + if($run){ + //remove the user from the all backends that have the group + foreach(self::$_usedBackends as $backend){ + if(!$backend->implementsActions(OC_GROUP_BACKEND_REMOVE_FROM_GOUP)) + continue; + + $backend->removeFromGroup($uid, $gid); + OC_Hook::emit( "OC_User", "post_removeFromGroup", array( "uid" => $uid, "gid" => $gid )); + } return true; - } - else{ + }else{ return false; } } @@ -222,7 +222,14 @@ class OC_Group { * if the user exists at all. */ public static function getUserGroups( $uid ){ - return self::$_backend->getUserGroups($uid); + $groups=array(); + foreach(self::$_usedBackends as $backend){ + if(!$backend->implementsActions(OC_GROUP_BACKEND_GET_USER_GROUPS)) + continue; + + $groups=array_merge($backend->getUserGroups($uid),$groups); + } + return $groups; } /** @@ -232,7 +239,14 @@ class OC_Group { * Returns a list with all groups */ public static function getGroups(){ - return self::$_backend->getGroups(); + $groups=array(); + foreach(self::$_usedBackends as $backend){ + if(!$backend->implementsActions(OC_GROUP_BACKEND_GET_GROUPS)) + continue; + + $groups=array_merge($backend->getGroups(),$groups); + } + return $groups; } /** @@ -249,6 +263,13 @@ class OC_Group { * @returns array with user ids */ public static function usersInGroup($gid){ - return self::$_backend->usersInGroup($gid); + $users=array(); + foreach(self::$_usedBackends as $backend){ + if(!$backend->implementsActions(OC_GROUP_BACKEND_GET_USERS)) + continue; + + $users=array_merge($backend->usersInGroup($gid),$users); + } + return $users; } } diff --git a/lib/group/backend.php b/lib/group/backend.php index 43f94e7ea1a..b3fc06ac9a8 100644 --- a/lib/group/backend.php +++ b/lib/group/backend.php @@ -21,82 +21,65 @@ * */ +/** + * error code for functions not provided by the group backend + */ +define('OC_GROUP_BACKEND_NOT_IMPLEMENTED', -501); +/** + * actions that user backends can define + */ +define('OC_GROUP_BACKEND_CREATE_GROUP', 0x00000001); +define('OC_GROUP_BACKEND_DELETE_GROUP', 0x00000010); +define('OC_GROUP_BACKEND_IN_GROUP', 0x00000100); +define('OC_GROUP_BACKEND_ADD_TO_GROUP', 0x00001000); +define('OC_GROUP_BACKEND_REMOVE_FROM_GOUP', 0x00010000); +define('OC_GROUP_BACKEND_GET_USER_GROUPS', 0x00100000); +define('OC_GROUP_BACKEND_GET_USERS', 0x01000000); +define('OC_GROUP_BACKEND_GET_GROUPS', 0x10000000); /** * Abstract base class for user management */ abstract class OC_Group_Backend { + protected $possibleActions = array( + OC_GROUP_BACKEND_CREATE_GROUP => 'createGroup', + OC_GROUP_BACKEND_DELETE_GROUP => 'deleteGroup', + OC_GROUP_BACKEND_IN_GROUP => 'inGroup', + OC_GROUP_BACKEND_ADD_TO_GROUP => 'addToGroup', + OC_GROUP_BACKEND_REMOVE_FROM_GOUP => 'removeFromGroup', + OC_GROUP_BACKEND_GET_USER_GROUPS => 'getUserGroups', + OC_GROUP_BACKEND_GET_USERS => 'usersInGroup', + OC_GROUP_BACKEND_GET_GROUPS => 'getGroups' + ); + /** - * @brief Try to create a new group - * @param $gid The name of the group to create - * @returns true/false - * - * Trys to create a new group. If the group name already exists, false will - * be returned. - */ - public static function createGroup($gid){} - - /** - * @brief delete a group - * @param $gid gid of the group to delete - * @returns true/false - * - * Deletes a group and removes it from the group_user-table - */ - public static function removeGroup($gid){} - - /** - * @brief is user in group? - * @param $uid uid of the user - * @param $gid gid of the group - * @returns true/false - * - * Checks whether the user is member of a group or not. - */ - public static function inGroup($uid, $gid){} - - /** - * @brief Add a user to a group - * @param $uid Name of the user to add to group - * @param $gid Name of the group in which add the user - * @returns true/false - * - * Adds a user to a group. - */ - public static function addToGroup($uid, $gid){} - - /** - * @brief Removes a user from a group - * @param $uid Name of the user to remove from group - * @param $gid Name of the group from which remove the user - * @returns true/false - * - * removes the user from a group. - */ - public static function removeFromGroup($uid,$gid){} - - /** - * @brief Get all groups a user belongs to - * @param $uid Name of the user - * @returns array with group names - * - * This function fetches all groups a user belongs to. It does not check - * if the user exists at all. - */ - public static function getUserGroups($uid){} + * @brief Get all supported actions + * @returns bitwise-or'ed actions + * + * Returns the supported actions as int to be + * compared with OC_USER_BACKEND_CREATE_USER etc. + */ + public function getSupportedActions(){ + $actions = 0; + foreach($this->possibleActions AS $action => $methodName){ + if(method_exists($this, $methodName)) { + $actions |= $action; + } + } - /** - * @brief get a list of all groups - * @returns array with group names - * - * Returns a list with all groups - */ - public static function getGroups(){} + return $actions; + } /** - * @brief get a list of all users in a group - * @returns array with user ids - */ - public static function usersInGroup($gid){} + * @brief Check if backend implements actions + * @param $actions bitwise-or'ed actions + * @returns boolean + * + * Returns the supported actions as int to be + * compared with OC_GROUP_BACKEND_CREATE_GROUP etc. + */ + public function implementsActions($actions){ + return (bool)($this->getSupportedActions() & $actions); + } } diff --git a/lib/group/database.php b/lib/group/database.php index 1afd4b5fe4c..d401acf43b3 100644 --- a/lib/group/database.php +++ b/lib/group/database.php @@ -117,8 +117,10 @@ class OC_Group_Database extends OC_Group_Backend { if( !self::inGroup( $uid, $gid )){ $query = OC_DB::prepare( "INSERT INTO `*PREFIX*group_user` ( `uid`, `gid` ) VALUES( ?, ? )" ); $result = $query->execute( array( $uid, $gid )); + return true; + }else{ + return false; } - return true; } /** diff --git a/lib/group/dummy.php b/lib/group/dummy.php new file mode 100644 index 00000000000..5220237ecbf --- /dev/null +++ b/lib/group/dummy.php @@ -0,0 +1,159 @@ +<?php + +/** +* ownCloud +* +* @author Frank Karlitschek +* @copyright 2010 Frank Karlitschek karlitschek@kde.org +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * dummy group backend, does not keep state, only for testing use + */ +class OC_Group_Dummy extends OC_Group_Backend { + private $groups=array(); + /** + * @brief Try to create a new group + * @param $gid The name of the group to create + * @returns true/false + * + * Trys to create a new group. If the group name already exists, false will + * be returned. + */ + public function createGroup($gid){ + if(!isset($this->groups[$gid])){ + $this->groups[$gid]=array(); + return true; + }else{ + return false; + } + } + + /** + * @brief delete a group + * @param $gid gid of the group to delete + * @returns true/false + * + * Deletes a group and removes it from the group_user-table + */ + public function deleteGroup($gid){ + if(isset($this->groups[$gid])){ + unset($this->groups[$gid]); + return true; + }else{ + return false; + } + } + + /** + * @brief is user in group? + * @param $uid uid of the user + * @param $gid gid of the group + * @returns true/false + * + * Checks whether the user is member of a group or not. + */ + public function inGroup($uid, $gid){ + if(isset($this->groups[$gid])){ + return (array_search($uid,$this->groups[$gid])!==false); + }else{ + return false; + } + } + + /** + * @brief Add a user to a group + * @param $uid Name of the user to add to group + * @param $gid Name of the group in which add the user + * @returns true/false + * + * Adds a user to a group. + */ + public function addToGroup($uid, $gid){ + if(isset($this->groups[$gid])){ + if(array_search($uid,$this->groups[$gid])===false){ + $this->groups[$gid][]=$uid; + return true; + }else{ + return false; + } + }else{ + return false; + } + } + + /** + * @brief Removes a user from a group + * @param $uid NameUSER of the user to remove from group + * @param $gid Name of the group from which remove the user + * @returns true/false + * + * removes the user from a group. + */ + public function removeFromGroup($uid,$gid){ + if(isset($this->groups[$gid])){ + if(($index=array_search($uid,$this->groups[$gid]))!==false){ + unset($this->groups[$gid][$index]); + }else{ + return false; + } + }else{ + return false; + } + } + + /** + * @brief Get all groups a user belongs to + * @param $uid Name of the user + * @returns array with group names + * + * This function fetches all groups a user belongs to. It does not check + * if the user exists at all. + */ + public function getUserGroups($uid){ + $groups=array(); + foreach($this->groups as $group=>$user){ + if($this->inGroup($uid,$group)){ + $groups[]=$group; + } + } + return $groups; + } + + /** + * @brief get a list of all groups + * @returns array with group names + * + * Returns a list with all groups + */ + public function getGroups(){ + return array_keys($this->groups); + } + + /** + * @brief get a list of all users in a group + * @returns array with user ids + */ + public function usersInGroup($gid){ + if(isset($this->groups[$gid])){ + return $this->groups[$gid]; + }else{ + return array(); + } + } + +} diff --git a/lib/group/example.php b/lib/group/example.php new file mode 100644 index 00000000000..a88159f91be --- /dev/null +++ b/lib/group/example.php @@ -0,0 +1,102 @@ +<?php + +/** +* ownCloud +* +* @author Frank Karlitschek +* @copyright 2010 Frank Karlitschek karlitschek@kde.org +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * abstract reference class for group management + * this class should only be used as a reference for method signatures and their descriptions + */ +abstract class OC_Group_Example { + /** + * @brief Try to create a new group + * @param $gid The name of the group to create + * @returns true/false + * + * Trys to create a new group. If the group name already exists, false will + * be returned. + */ + public static function createGroup($gid){} + + /** + * @brief delete a group + * @param $gid gid of the group to delete + * @returns true/false + * + * Deletes a group and removes it from the group_user-table + */ + public static function deleteGroup($gid){} + + /** + * @brief is user in group? + * @param $uid uid of the user + * @param $gid gid of the group + * @returns true/false + * + * Checks whether the user is member of a group or not. + */ + public static function inGroup($uid, $gid){} + + /** + * @brief Add a user to a group + * @param $uid Name of the user to add to group + * @param $gid Name of the group in which add the user + * @returns true/false + * + * Adds a user to a group. + */ + public static function addToGroup($uid, $gid){} + + /** + * @brief Removes a user from a group + * @param $uid NameUSER of the user to remove from group + * @param $gid Name of the group from which remove the user + * @returns true/false + * + * removes the user from a group. + */ + public static function removeFromGroup($uid,$gid){} + + /** + * @brief Get all groups a user belongs to + * @param $uid Name of the user + * @returns array with group names + * + * This function fetches all groups a user belongs to. It does not check + * if the user exists at all. + */ + public static function getUserGroups($uid){} + + /** + * @brief get a list of all groups + * @returns array with group names + * + * Returns a list with all groups + */ + public static function getGroups(){} + + /** + * @brief get a list of all users in a group + * @returns array with user ids + */ + public static function usersInGroup($gid){} + +} diff --git a/lib/helper.php b/lib/helper.php index 0c6c73aa76b..c33db5f10fe 100644..100755 --- a/lib/helper.php +++ b/lib/helper.php @@ -27,7 +27,7 @@ class OC_Helper { private static $mimetypes=array(); private static $tmpFiles=array(); - + /** * @brief Creates an url * @param $app app @@ -60,6 +60,28 @@ class OC_Helper { } /** + * @brief Returns the server host + * @returns the server host + * + * Returns the server host, even if the website uses one or more + * reverse proxies + */ + public static function serverHost() { + if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { + if (strpos($_SERVER['HTTP_X_FORWARDED_HOST'], ",") !== false) { + $host = trim(array_pop(explode(",", $_SERVER['HTTP_X_FORWARDED_HOST']))); + } + else{ + $host=$_SERVER['HTTP_X_FORWARDED_HOST']; + } + } + else{ + $host = $_SERVER['HTTP_HOST']; + } + return $host; + } + + /** * @brief Creates an absolute url * @param $app app * @param $file file @@ -71,7 +93,7 @@ class OC_Helper { $urlLinkTo = self::linkTo( $app, $file ); // Checking if the request was made through HTTPS. The last in line is for IIS $protocol = isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!='off'); - $urlLinkTo = ($protocol?'https':'http') . '://' . $_SERVER['HTTP_HOST'] . $urlLinkTo; + $urlLinkTo = ($protocol?'https':'http') . '://' . self::serverHost() . $urlLinkTo; return $urlLinkTo; } @@ -101,7 +123,7 @@ class OC_Helper { }elseif( file_exists( OC::$SERVERROOT."/core/img/$image" )){ return OC::$WEBROOT."/core/img/$image"; }else{ - echo('image not found: image:'.$image.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + echo('image not found: image:'.$image.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); die(); } } @@ -166,7 +188,7 @@ class OC_Helper { $bytes = round( $bytes / 1024, 1 ); return "$bytes GB"; } - + /** * @brief Make a computer file size * @param $str file size in a fancy format @@ -202,9 +224,9 @@ class OC_Helper { $bytes = round($bytes, 2); - return $bytes; + return $bytes; } - + /** * @brief Recusive editing of file permissions * @param $path path to file or folder @@ -220,7 +242,7 @@ class OC_Helper { $fullpath = $path.'/'.$file; if(is_link($fullpath)) return FALSE; - elseif(!is_dir($fullpath) && !chmod($fullpath, $filemode)) + elseif(!is_dir($fullpath) && !@chmod($fullpath, $filemode)) return FALSE; elseif(!self::chmodr($fullpath, $filemode)) return FALSE; @@ -254,7 +276,7 @@ class OC_Helper { copy($src, $dest); } } - + /** * @brief Recusive deletion of folders * @param string $dir path to the folder @@ -272,6 +294,9 @@ class OC_Helper { }elseif(file_exists($dir)){ unlink($dir); } + if(file_exists($dir)) { + return false; + } } /** @@ -284,12 +309,10 @@ class OC_Helper { $isWrapped=(strpos($path,'://')!==false) and (substr($path,0,7)=='file://'); $mimeType='application/octet-stream'; if ($mimeType=='application/octet-stream') { - if(count(self::$mimetypes)>0){ - self::$mimetypes = include('mimetypes.fixlist.php'); - } - $extention=strtolower(strrchr(basename($path), ".")); - $extention=substr($extention,1);//remove leading . - $mimeType=(isset(self::$mimetypes[$extention]))?self::$mimetypes[$extention]:'application/octet-stream'; + self::$mimetypes = include('mimetypes.fixlist.php'); + $extension=strtolower(strrchr(basename($path), ".")); + $extension=substr($extension,1);//remove leading . + $mimeType=(isset(self::$mimetypes[$extension]))?self::$mimetypes[$extension]:'application/octet-stream'; } if (@is_dir($path)) { @@ -323,13 +346,13 @@ class OC_Helper { if(!self::$mimetypes || self::$mimetypes != include('mimetypes.list.php')){ self::$mimetypes=include('mimetypes.list.php'); } - $extention=strtolower(strrchr(basename($path), ".")); - $extention=substr($extention,1);//remove leading . - $mimeType=(isset(self::$mimetypes[$extention]))?self::$mimetypes[$extention]:'application/octet-stream'; + $extension=strtolower(strrchr(basename($path), ".")); + $extension=substr($extension,1);//remove leading . + $mimeType=(isset(self::$mimetypes[$extension]))?self::$mimetypes[$extension]:'application/octet-stream'; } return $mimeType; } - + /** * @brief Checks $_REQUEST contains a var for the $s key. If so, returns the html-escaped value of this var; otherwise returns the default value provided by $d. * @param $s name of the var to escape, if set. @@ -337,16 +360,16 @@ class OC_Helper { * @returns the print-safe value. * */ - + //FIXME: should also check for value validation (i.e. the email is an email). public static function init_var($s, $d="") { $r = $d; if(isset($_REQUEST[$s]) && !empty($_REQUEST[$s])) $r = stripslashes(htmlspecialchars($_REQUEST[$s])); - + return $r; } - + /** * returns "checked"-attribut if request contains selected radio element OR if radio element is the default one -- maybe? * @param string $s Name of radio-button element name @@ -402,7 +425,7 @@ class OC_Helper { } return false; } - + /** * copy the contents of one stream to another * @param resource source @@ -419,7 +442,7 @@ class OC_Helper { } return $count; } - + /** * create a temporary file with an unique filename * @param string postfix @@ -434,14 +457,38 @@ class OC_Helper { self::$tmpFiles[]=$file; return $file; } - + + /** + * create a temporary folder with an unique filename + * @return string + * + * temporary files are automatically cleaned up after the script is finished + */ + public static function tmpFolder(){ + $path=get_temp_dir().'/'.md5(time().rand()); + mkdir($path); + self::$tmpFiles[]=$path; + return $path.'/'; + } + /** * remove all files created by self::tmpFile */ public static function cleanTmp(){ + $leftoversFile='/tmp/oc-not-deleted'; + if(file_exists($leftoversFile)){ + $leftovers=file($leftoversFile); + foreach($leftovers as $file) { + self::rmdirr($file); + } + unlink($leftoversFile); + } + foreach(self::$tmpFiles as $file){ if(file_exists($file)){ - unlink($file); + if(!self::rmdirr($file)) { + file_put_contents($leftoversFile, $file."\n", FILE_APPEND); + } } } } diff --git a/lib/image.php b/lib/image.php index 60a714880d0..4c53dc32f58 100644 --- a/lib/image.php +++ b/lib/image.php @@ -216,7 +216,7 @@ class OC_Image { OC_Log::write('core','OC_Image->fixOrientation() No readable file path set.', OC_Log::DEBUG); return false; } - $exif = @exif_read_data($this->filepath, 'IFD0'); + $exif = @exif_read_data($this->filepath, 'IFD0'); if(!$exif) { return false; } @@ -267,6 +267,7 @@ class OC_Image { if($res) { if(imagealphablending($res, true)) { if(imagesavealpha($res, true)) { + imagedestroy($this->resource); $this->resource = $res; return true; } else { @@ -317,10 +318,7 @@ class OC_Image { */ public function loadFromFileHandle($handle) { OC_Log::write('core',__METHOD__.'(): Trying', OC_Log::DEBUG); - $contents = ''; - while (!feof($handle)) { - $contents .= fread($handle, 8192); - } + $contents = stream_get_contents($handle); if($this->loadFromData($contents)) { return $this->resource; } @@ -486,22 +484,24 @@ class OC_Image { imagedestroy($process); return false; } + imagedestroy($this->resource); $this->resource = $process; return true; } /** * @brief Crops the image to the middle square. If the image is already square it just returns. + * @param int maximum size for the result (optional) * @returns bool for success or failure */ - public function centerCrop() { + public function centerCrop($size=0) { if(!$this->valid()) { OC_Log::write('core','OC_Image->centerCrop, No image loaded', OC_Log::ERROR); return false; } $width_orig=imageSX($this->resource); $height_orig=imageSY($this->resource); - if($width_orig === $height_orig) { + if($width_orig === $height_orig and $size==0) { return true; } $ratio_orig = $width_orig/$height_orig; @@ -514,18 +514,26 @@ class OC_Image { $y = ($height_orig/2) - ($height/2); $x = 0; } - $process = imagecreatetruecolor($width, $height); + if($size>0){ + $targetWidth=$size; + $targetHeight=$size; + }else{ + $targetWidth=$width; + $targetHeight=$height; + } + $process = imagecreatetruecolor($targetWidth, $targetHeight); if ($process == false) { OC_Log::write('core','OC_Image->centerCrop. Error creating true color image',OC_Log::ERROR); imagedestroy($process); return false; } - imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $width, $height, $width, $height); + imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $targetWidth, $targetHeight, $width, $height); if ($process == false) { OC_Log::write('core','OC_Image->centerCrop. Error resampling process image '.$width.'x'.$height,OC_Log::ERROR); imagedestroy($process); return false; } + imagedestroy($this->resource); $this->resource = $process; return true; } @@ -558,7 +566,19 @@ class OC_Image { imagedestroy($process); return false; } + imagedestroy($this->resource); $this->resource = $process; return true; } + + public function destroy(){ + if($this->valid()){ + imagedestroy($this->resource); + } + $this->resource=null; + } + + public function __destruct(){ + $this->destroy(); + } } diff --git a/lib/installer.php b/lib/installer.php index 2a9676998f6..6edf4ce1b74 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -62,7 +62,7 @@ class OC_Installer{ //download the file if necesary if($data['source']=='http'){ - $path=OC_Helper::tmpFile('.zip'); + $path=OC_Helper::tmpFile(); if(!isset($data['href'])){ OC_Log::write('core','No href specified when installing app from http',OC_Log::ERROR); return false; @@ -76,14 +76,24 @@ class OC_Installer{ $path=$data['path']; } + //detect the archive type + $mime=OC_Helper::getMimeType($path); + if($mime=='application/zip'){ + rename($path,$path.'.zip'); + $path.='.zip'; + }elseif($mime=='application/x-gzip'){ + rename($path,$path.'.tgz'); + $path.='.tgz'; + }else{ + OC_Log::write('core','Archives of type '.$mime.' are not supported',OC_Log::ERROR); + return false; + } + //extract the archive in a temporary folder - $extractDir=tempnam(get_temp_dir(),'oc_installer_uncompressed_'); - unlink($extractDir); + $extractDir=OC_Helper::tmpFolder(); mkdir($extractDir); - $zip = new ZipArchive; - if($zip->open($path)===true){ - $zip->extractTo($extractDir); - $zip->close(); + if($archive=OC_Archive::open($path)){ + $archive->extract($extractDir); } else { OC_Log::write('core','Failed to open archive when installing app',OC_Log::ERROR); OC_Helper::rmdirr($extractDir); @@ -95,6 +105,17 @@ class OC_Installer{ //load the info.xml file of the app if(!is_file($extractDir.'/appinfo/info.xml')){ + //try to find it in a subdir + $dh=opendir($extractDir); + while($folder=readdir($dh)){ + if(substr($folder,0,1)!='.' and is_dir($extractDir.'/'.$folder)){ + if(is_file($extractDir.'/'.$folder.'/appinfo/info.xml')){ + $extractDir.='/'.$folder; + } + } + } + } + if(!is_file($extractDir.'/appinfo/info.xml')){ OC_Log::write('core','App does not provide an info.xml file',OC_Log::ERROR); OC_Helper::rmdirr($extractDir); if($data['source']=='http'){ @@ -102,7 +123,7 @@ class OC_Installer{ } return false; } - $info=OC_App::getAppInfo($extractDir.'/appinfo/info.xml'); + $info=OC_App::getAppInfo($extractDir.'/appinfo/info.xml',true); $basedir=OC::$APPSROOT.'/apps/'.$info['id']; //check if an app with the same id is already installed @@ -154,7 +175,7 @@ class OC_Installer{ } //set the installed version - OC_Appconfig::setValue($info['id'],'installed_version',$info['version']); + OC_Appconfig::setValue($info['id'],'installed_version',OC_App::getAppVersion($info['id'])); OC_Appconfig::setValue($info['id'],'enabled','no'); return $info['id']; } @@ -275,8 +296,8 @@ class OC_Installer{ if(is_file(OC::$APPSROOT."/apps/$app/appinfo/install.php")){ include(OC::$APPSROOT."/apps/$app/appinfo/install.php"); } - $info=OC_App::getAppInfo(OC::$APPSROOT."/apps/$app/appinfo/info.xml"); - OC_Appconfig::setValue($app,'installed_version',$info['version']); + $info=OC_App::getAppInfo($app); + OC_Appconfig::setValue($app,'installed_version',OC_App::getAppVersion($app)); return $info; } } diff --git a/lib/json.php b/lib/json.php index cedf79fd7c3..0d208ce12a2 100644 --- a/lib/json.php +++ b/lib/json.php @@ -24,7 +24,7 @@ class OC_JSON{ */ public static function checkAppEnabled($app){ if( !OC_App::isEnabled($app)){ - $l = new OC_L10N('core'); + $l = OC_L10N::get('core'); self::error(array( 'data' => array( 'message' => $l->t('Application is not enabled') ))); exit(); } @@ -35,7 +35,7 @@ class OC_JSON{ */ public static function checkLoggedIn(){ if( !OC_User::isLoggedIn()){ - $l = new OC_L10N('core'); + $l = OC_L10N::get('core'); self::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); exit(); } @@ -47,7 +47,7 @@ class OC_JSON{ public static function checkAdminUser(){ self::checkLoggedIn(); if( !OC_Group::inGroup( OC_User::getUser(), 'admin' )){ - $l = new OC_L10N('core'); + $l = OC_L10N::get('core'); self::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); exit(); } diff --git a/lib/l10n.php b/lib/l10n.php index 636326f9864..c0ecdbd1b70 100644 --- a/lib/l10n.php +++ b/lib/l10n.php @@ -25,6 +25,11 @@ */ class OC_L10N{ /** + * cached instances + */ + protected static $instances=array(); + + /** * cache */ protected static $cache = array(); @@ -46,6 +51,21 @@ class OC_L10N{ 'date' => 'd.m.Y', 'datetime' => 'd.m.Y H:i:s', 'time' => 'H:i:s'); + + /** + * get an L10N instance + * @return OC_L10N + */ + public static function get($app,$lang=null){ + if(is_null($lang)){ + if(!isset(self::$instances[$app])){ + self::$instances[$app]=new OC_L10N($app); + } + return self::$instances[$app]; + }else{ + return new OC_L10N($app,$lang); + } + } /** * @brief The constructor @@ -261,17 +281,14 @@ class OC_L10N{ public static function findAvailableLanguages($app=null){ $available=array('en');//english is always available $dir = self::findI18nDir($app); - if(file_exists($dir)){ - $dh = opendir($dir); - while(($file = readdir($dh)) !== false){ - if(substr($file, -4, 4) == '.php' and (strlen($file) == 6 || strlen($file) == 9)){ + if(is_dir($dir)){ + $files=scandir($dir); + foreach($files as $file){ + if(substr($file, -4, 4) == '.php'){ $i = substr($file, 0, -4); - if($i != ''){ - $available[] = $i; - } + $available[] = $i; } } - closedir($dh); } return $available; } diff --git a/lib/log.php b/lib/log.php index 4e450a027f5..8bb2839be66 100644 --- a/lib/log.php +++ b/lib/log.php @@ -1,78 +1,39 @@ <?php /** - * ownCloud - * - * @author Robin Appelman - * @copyright 2012 Robin Appelman icewind1991@gmail.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU AFFERO GENERAL PUBLIC LICENSE for more details. - * - * You should have received a copy of the GNU Affero General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. */ /** - *logging utilities + * logging utilities * - * Log is saved at data/owncloud.log (on default) + * Log is saved by default at data/owncloud.log using OC_Log_Owncloud. + * Selecting other backend is done with a config option 'log_type'. */ -class OC_Log{ +class OC_Log { const DEBUG=0; const INFO=1; const WARN=2; const ERROR=3; const FATAL=4; + static protected $class = null; + /** * write a message in the log * @param string $app * @param string $message * @param int level */ - public static function write($app,$message,$level){ - $minLevel=OC_Config::getValue( "loglevel", 2 ); - if($level>=$minLevel){ - $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' ); - $logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' ); - $entry=array('app'=>$app,'message'=>$message,'level'=>$level,'time'=>time()); - $fh=fopen($logFile,'a'); - fwrite($fh,json_encode($entry)."\n"); - fclose($fh); - } - } - - /** - * get entries from the log in reverse chronological order - * @param int limit - * @param int offset - * @return array - */ - public static function getEntries($limit=50,$offset=0){ - $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' ); - $logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' ); - $entries=array(); - if(!file_exists($logFile)){ - return array(); - } - $contents=file($logFile); - if(!$contents){//error while reading log - return array(); - } - $end=max(count($contents)-$offset-1,0); - $start=max($end-$limit,0); - for($i=$end;$i>$start;$i--){ - $entries[]=json_decode($contents[$i]); + public static function write($app, $message, $level) { + if (!self::$class) { + self::$class = 'OC_Log_'.ucfirst(OC_Config::getValue('log_type', 'owncloud')); + call_user_func(array(self::$class, 'init')); } - return $entries; + $log_class=self::$class; + $log_class::write($app, $message, $level); } } diff --git a/lib/log/owncloud.php b/lib/log/owncloud.php new file mode 100644 index 00000000000..0ed30510134 --- /dev/null +++ b/lib/log/owncloud.php @@ -0,0 +1,79 @@ +<?php +/** + * ownCloud + * + * @author Robin Appelman + * @copyright 2012 Robin Appelman icewind1991@gmail.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/** + * logging utilities + * + * Log is saved at data/owncloud.log (on default) + */ + +class OC_Log_Owncloud { + static protected $logFile; + + /** + * Init class data + */ + public static function init() { + $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' ); + self::$logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' ); + } + + /** + * write a message in the log + * @param string $app + * @param string $message + * @param int level + */ + public static function write($app, $message, $level) { + $minLevel=OC_Config::getValue( "loglevel", 2 ); + if($level>=$minLevel){ + $entry=array('app'=>$app, 'message'=>$message, 'level'=>$level,'time'=>time()); + $fh=fopen(self::$logFile, 'a'); + fwrite($fh, json_encode($entry)."\n"); + fclose($fh); + } + } + + /** + * get entries from the log in reverse chronological order + * @param int limit + * @param int offset + * @return array + */ + public static function getEntries($limit=50, $offset=0){ + self::init(); + $entries=array(); + if(!file_exists(self::$logFile)) { + return array(); + } + $contents=file(self::$logFile); + if(!$contents) {//error while reading log + return array(); + } + $end=max(count($contents)-$offset-1, 0); + $start=max($end-$limit,0); + for($i=$end;$i>$start;$i--) { + $entries[]=json_decode($contents[$i]); + } + return $entries; + } +} diff --git a/lib/log/syslog.php b/lib/log/syslog.php new file mode 100644 index 00000000000..d1fb28d8b0a --- /dev/null +++ b/lib/log/syslog.php @@ -0,0 +1,37 @@ +<?php +/** + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Log_Syslog { + static protected $levels = array( + OC_Log::DEBUG => LOG_DEBUG, + OC_Log::INFO => LOG_INFO, + OC_Log::WARN => LOG_WARNING, + OC_Log::ERROR => LOG_ERR, + OC_Log::FATAL => LOG_CRIT, + ); + + /** + * Init class data + */ + public static function init() { + openlog('ownCloud', LOG_PID | LOG_CONS, LOG_USER); + // Close at shutdown + register_shutdown_function('closelog'); + } + + /** + * write a message in the log + * @param string $app + * @param string $message + * @param int level + */ + public static function write($app, $message, $level) { + $syslog_level = self::$levels[$level]; + syslog($syslog_level, '{'.$app.'} '.$message); + } +} diff --git a/lib/migrate.php b/lib/migrate.php new file mode 100644 index 00000000000..f46d860e806 --- /dev/null +++ b/lib/migrate.php @@ -0,0 +1,715 @@ +<?php +/** + * ownCloud + * + * @author Tom Needham + * @copyright 2012 Tom Needham tom@owncloud.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +/** + * provides an interface to migrate users and whole ownclouds + */ +class OC_Migrate{ + + + // Array of OC_Migration_Provider objects + static private $providers=array(); + // User id of the user to import/export + static private $uid=false; + // Holds the ZipArchive object + static private $zip=false; + // Stores the type of export + static private $exporttype=false; + // Array of temp files to be deleted after zip creation + static private $tmpfiles=array(); + // Holds the db object + static private $MDB2=false; + // Schema db object + static private $schema=false; + // Path to the sqlite db + static private $dbpath=false; + // Holds the path to the zip file + static private $zippath=false; + // Holds the OC_Migration_Content object + static private $content=false; + + /** + * register a new migration provider + * @param OC_Migrate_Provider $provider + */ + public static function registerProvider($provider){ + self::$providers[]=$provider; + } + + /** + * @brief finds and loads the providers + */ + static private function findProviders(){ + // Find the providers + $apps = OC_App::getAllApps(); + + foreach($apps as $app){ + $path = OC::$SERVERROOT . '/apps/' . $app . '/appinfo/migrate.php'; + if( file_exists( $path ) ){ + include( $path ); + } + } + } + + /** + * @brief exports a user, or owncloud instance + * @param optional $uid string user id of user to export if export type is user, defaults to current + * @param ootional $type string type of export, defualts to user + * @param otional $path string path to zip output folder + * @return false on error, path to zip on success + */ + public static function export( $uid=null, $type='user', $path=null ){ + $datadir = OC_Config::getValue( 'datadirectory' ); + // Validate export type + $types = array( 'user', 'instance', 'system', 'userfiles' ); + if( !in_array( $type, $types ) ){ + OC_Log::write( 'migration', 'Invalid export type', OC_Log::ERROR ); + return json_encode( array( array( 'success' => false ) ) ); + } + self::$exporttype = $type; + // Userid? + if( self::$exporttype == 'user' ){ + // Check user exists + if( !is_null($uid) ){ + $db = new OC_User_Database; + if( !$db->userExists( $uid ) ){ + OC_Log::write('migration', 'User: '.$uid.' is not in the database and so cannot be exported.', OC_Log::ERROR); + return json_encode( array( 'success' => false ) ); + } + self::$uid = $uid; + } else { + self::$uid = OC_User::getUser(); + } + } + // Calculate zipname + if( self::$exporttype == 'user' ){ + $zipname = 'oc_export_' . self::$uid . '_' . date("y-m-d_H-i-s") . '.zip'; + } else { + $zipname = 'oc_export_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '.zip'; + } + // Calculate path + if( self::$exporttype == 'user' ){ + self::$zippath = $datadir . '/' . self::$uid . '/' . $zipname; + } else { + if( !is_null( $path ) ){ + // Validate custom path + if( !file_exists( $path ) || !is_writeable( $path ) ){ + OC_Log::write( 'migration', 'Path supplied is invalid.', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + self::$zippath = $path . $zipname; + } else { + // Default path + self::$zippath = get_temp_dir() . '/' . $zipname; + } + } + // Create the zip object + if( !self::createZip() ){ + return json_encode( array( 'success' => false ) ); + } + // Do the export + self::findProviders(); + $exportdata = array(); + switch( self::$exporttype ){ + case 'user': + // Connect to the db + self::$dbpath = $datadir . '/' . self::$uid . '/migration.db'; + if( !self::connectDB() ){ + return json_encode( array( 'success' => false ) ); + } + self::$content = new OC_Migration_Content( self::$zip, self::$MDB2 ); + // Export the app info + $exportdata = self::exportAppData(); + // Add the data dir to the zip + self::$content->addDir( $datadir . '/' . self::$uid, true, '/' ); + break; + case 'instance': + self::$content = new OC_Migration_Content( self::$zip ); + // Creates a zip that is compatable with the import function + $dbfile = tempnam( "/tmp", "owncloud_export_data_" ); + OC_DB::getDbStructure( $dbfile, 'MDB2_SCHEMA_DUMP_ALL'); + + // Now add in *dbname* and *dbprefix* + $dbexport = file_get_contents( $dbfile ); + $dbnamestring = "<database>\n\n <name>" . OC_Config::getValue( "dbname", "owncloud" ); + $dbtableprefixstring = "<table>\n\n <name>" . OC_Config::getValue( "dbtableprefix", "oc_" ); + $dbexport = str_replace( $dbnamestring, "<database>\n\n <name>*dbname*", $dbexport ); + $dbexport = str_replace( $dbtableprefixstring, "<table>\n\n <name>*dbprefix*", $dbexport ); + // Add the export to the zip + self::$content->addFromString( $dbexport, "dbexport.xml" ); + // Add user data + foreach(OC_User::getUsers() as $user){ + self::$content->addDir( $datadir . '/' . $user . '/', true, "/userdata/" ); + } + break; + case 'userfiles': + self::$content = new OC_Migration_Content( self::$zip ); + // Creates a zip with all of the users files + foreach(OC_User::getUsers() as $user){ + self::$content->addDir( $datadir . '/' . $user . '/', true, "/" ); + } + break; + case 'system': + self::$content = new OC_Migration_Content( self::$zip ); + // Creates a zip with the owncloud system files + self::$content->addDir( OC::$SERVERROOT . '/', false, '/'); + foreach (array(".git", "3rdparty", "apps", "core", "files", "l10n", "lib", "ocs", "search", "settings", "tests") as $dir) { + self::$content->addDir( OC::$SERVERROOT . '/' . $dir, true, "/"); + } + break; + } + if( !$info = self::getExportInfo( $exportdata ) ){ + return json_encode( array( 'success' => false ) ); + } + // Add the export info json to the export zip + self::$content->addFromString( $info, 'export_info.json' ); + if( !self::$content->finish() ){ + return json_encode( array( 'success' => false ) ); + } + return json_encode( array( 'success' => true, 'data' => self::$zippath ) ); + } + + /** + * @brief imports a user, or owncloud instance + * @param $path string path to zip + * @param optional $type type of import (user or instance) + * @param optional $uid userid of new user + */ + public static function import( $path, $type='user', $uid=null ){ + OC_Util::checkAdminUser(); + $datadir = OC_Config::getValue( 'datadirectory' ); + // Extract the zip + if( !$extractpath = self::extractZip( $path ) ){ + return json_encode( array( 'success' => false ) ); + } + // Get export_info.json + $scan = scandir( $extractpath ); + // Check for export_info.json + if( !in_array( 'export_info.json', $scan ) ){ + OC_Log::write( 'migration', 'Invalid import file, export_info.json note found', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + $json = json_decode( file_get_contents( $extractpath . 'export_info.json' ) ); + if( $json->exporttype != $type ){ + OC_Log::write( 'migration', 'Invalid import file', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + self::$exporttype = $type; + + // Have we got a user if type is user + if( self::$exporttype == 'user' ){ + if( !$uid ){ + self::$uid = $json->exporteduser; + } else { + self::$uid = $uid; + } + } + + // Handle export types + switch( self::$exporttype ){ + case 'user': + // Check user availability + if( OC_User::userExists( self::$uid ) ){ + OC_Log::write( 'migration', 'User already exists', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + $run = true; + OC_Hook::emit( "OC_User", "pre_createUser", array( "run" => &$run, "uid" => self::$uid, "password" => $json->hash )); + if( !$run ){ + // Something stopped the user creation + OC_Log::write( 'migration', 'User creation failed', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + // Create the user + if( !self::createUser( self::$uid, $json->hash ) ){ + return json_encode( array( 'success' => false ) ); + } + // Emit the post_createUser hook (password is already hashed, will cause problems + OC_Hook::emit( "OC_User", "post_createUser", array( "uid" => self::$uid, "password" => $json->hash )); + // Make the new users data dir + $path = $datadir . '/' . self::$uid; + if( !mkdir( $path, 0755, true ) ){ + OC_Log::write( 'migration', 'Failed to create users data dir: '.$path, OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + // Copy data + if( !self::copy_r( $extractpath . $json->exporteduser, $datadir . '/' . self::$uid ) ){ + return json_encode( array( 'success' => false ) ); + } + // Import user app data + if( !$appsimported = self::importAppData( $extractpath . $json->exporteduser . '/migration.db', $json, self::$uid ) ){ + return json_encode( array( 'success' => false ) ); + } + // All done! + if( !self::unlink_r( $extractpath ) ){ + OC_Log::write( 'migration', 'Failed to delete the extracted zip', OC_Log::ERROR ); + } + return json_encode( array( 'success' => true, 'data' => $appsimported ) ); + break; + case 'instance': + /* + * EXPERIMENTAL + // Check for new data dir and dbexport before doing anything + // TODO + + // Delete current data folder. + OC_Log::write( 'migration', "Deleting current data dir", OC_Log::INFO ); + if( !self::unlink_r( $datadir, false ) ){ + OC_Log::write( 'migration', 'Failed to delete the current data dir', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + + // Copy over data + if( !self::copy_r( $extractpath . 'userdata', $datadir ) ){ + OC_Log::write( 'migration', 'Failed to copy over data directory', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); + } + + // Import the db + if( !OC_DB::replaceDB( $extractpath . 'dbexport.xml' ) ){ + return json_encode( array( 'success' => false ) ); + } + // Done + return json_encode( 'success' => true ); + */ + break; + } + + } + + /** + * @brief recursively deletes a directory + * @param $dir string path of dir to delete + * $param optional $deleteRootToo bool delete the root directory + * @return bool + */ + private static function unlink_r( $dir, $deleteRootToo=true ){ + if( !$dh = @opendir( $dir ) ){ + return false; + } + while (false !== ($obj = readdir($dh))){ + if($obj == '.' || $obj == '..') { + continue; + } + if (!@unlink($dir . '/' . $obj)){ + self::unlink_r($dir.'/'.$obj, true); + } + } + closedir($dh); + if ( $deleteRootToo ) { + @rmdir($dir); + } + return true; + } + + /** + * @brief copies recursively + * @param $path string path to source folder + * @param $dest string path to destination + * @return bool + */ + private static function copy_r( $path, $dest ){ + if( is_dir($path) ){ + @mkdir( $dest ); + $objects = scandir( $path ); + if( sizeof( $objects ) > 0 ){ + foreach( $objects as $file ){ + if( $file == "." || $file == ".." ) + continue; + // go on + if( is_dir( $path . '/' . $file ) ){ + self::copy_r( $path .'/' . $file, $dest . '/' . $file ); + } else { + copy( $path . '/' . $file, $dest . '/' . $file ); + } + } + } + return true; + } + elseif( is_file( $path ) ){ + return copy( $path, $dest ); + } else { + return false; + } + } + + /** + * @brief tries to extract the import zip + * @param $path string path to the zip + * @return string path to extract location (with a trailing slash) or false on failure + */ + static private function extractZip( $path ){ + self::$zip = new ZipArchive; + // Validate path + if( !file_exists( $path ) ){ + OC_Log::write( 'migration', 'Zip not found', OC_Log::ERROR ); + return false; + } + if ( self::$zip->open( $path ) != TRUE ) { + OC_Log::write( 'migration', "Failed to open zip file", OC_Log::ERROR ); + return false; + } + $to = get_temp_dir() . '/oc_import_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '/'; + if( !self::$zip->extractTo( $to ) ){ + return false; + } + self::$zip->close(); + return $to; + } + + /** + * @brief connects to a MDB2 database scheme + * @returns bool + */ + static private function connectScheme(){ + // We need a mdb2 database connection + self::$MDB2->loadModule( 'Manager' ); + self::$MDB2->loadModule( 'Reverse' ); + + // Connect if this did not happen before + if( !self::$schema ){ + require_once('MDB2/Schema.php'); + self::$schema=MDB2_Schema::factory( self::$MDB2 ); + } + + return true; + } + + /** + * @brief creates a migration.db in the users data dir with their app data in + * @return bool whether operation was successfull + */ + private static function exportAppData( ){ + + $success = true; + $return = array(); + + // Foreach provider + foreach( self::$providers as $provider ){ + $success = true; + // Does this app use the database? + if( file_exists( OC::$SERVERROOT.'/apps/'.$provider->getID().'/appinfo/database.xml' ) ){ + // Create some app tables + $tables = self::createAppTables( $provider->getID() ); + if( is_array( $tables ) ){ + // Save the table names + foreach($tables as $table){ + $return['apps'][$provider->getID()]['tables'][] = $table; + } + } else { + // It failed to create the tables + $success = false; + } + } + + // Run the export function? + if( $success ){ + // Set the provider properties + $provider->setData( self::$uid, self::$content ); + $return['apps'][$provider->getID()]['success'] = $provider->export(); + } else { + $return['apps'][$provider->getID()]['success'] = false; + $return['apps'][$provider->getID()]['message'] = 'failed to create the app tables'; + } + + // Now add some app info the the return array + $appinfo = OC_App::getAppInfo( $provider->getID() ); + $return['apps'][$provider->getID()]['version'] = OC_App::getAppVersion($provider->getID()); + + } + + return $return; + + } + + + /** + * @brief generates json containing export info, and merges any data supplied + * @param optional $array array of data to include in the returned json + * @return bool + */ + static private function getExportInfo( $array=array() ){ + $info = array( + 'ocversion' => OC_Util::getVersion(), + 'exporttime' => time(), + 'exportedby' => OC_User::getUser(), + 'exporttype' => self::$exporttype + ); + // Add hash if user export + if( self::$exporttype == 'user' ){ + $query = OC_DB::prepare( "SELECT password FROM *PREFIX*users WHERE uid LIKE ?" ); + $result = $query->execute( array( self::$uid ) ); + $row = $result->fetchRow(); + $hash = $row ? $row['password'] : false; + if( !$hash ){ + OC_Log::write( 'migration', 'Failed to get the users password hash', OC_log::ERROR); + return false; + } + $info['hash'] = $hash; + $info['exporteduser'] = self::$uid; + } + if( !is_array( $array ) ){ + OC_Log::write( 'migration', 'Supplied $array was not an array in getExportInfo()', OC_Log::ERROR ); + } + // Merge in other data + $info = array_merge( $info, (array)$array ); + // Create json + $json = json_encode( $info ); + return $json; + } + + /** + * @brief connects to migration.db, or creates if not found + * @param $db optional path to migration.db, defaults to user data dir + * @return bool whether the operation was successful + */ + static private function connectDB( $path=null ){ + // Has the dbpath been set? + self::$dbpath = !is_null( $path ) ? $path : self::$dbpath; + if( !self::$dbpath ){ + OC_Log::write( 'migration', 'connectDB() was called without dbpath being set', OC_Log::ERROR ); + return false; + } + // Already connected + if(!self::$MDB2){ + require_once('MDB2.php'); + + $datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); + + // DB type + if( class_exists( 'SQLite3' ) ){ + $dbtype = 'sqlite3'; + } else if( is_callable( 'sqlite_open' ) ){ + $dbtype = 'sqlite'; + } else { + OC_Log::write( 'migration', 'SQLite not found', OC_Log::ERROR ); + return false; + } + + // Prepare options array + $options = array( + 'portability' => MDB2_PORTABILITY_ALL & (!MDB2_PORTABILITY_FIX_CASE), + 'log_line_break' => '<br>', + 'idxname_format' => '%s', + 'debug' => true, + 'quote_identifier' => true + ); + $dsn = array( + 'phptype' => $dbtype, + 'database' => self::$dbpath, + 'mode' => '0644' + ); + + // Try to establish connection + self::$MDB2 = MDB2::factory( $dsn, $options ); + // Die if we could not connect + if( PEAR::isError( self::$MDB2 ) ){ + die( self::$MDB2->getMessage() ); + OC_Log::write( 'migration', 'Failed to create/connect to migration.db', OC_Log::FATAL ); + OC_Log::write( 'migration', self::$MDB2->getUserInfo(), OC_Log::FATAL ); + OC_Log::write( 'migration', self::$MDB2->getMessage(), OC_Log::FATAL ); + return false; + } + // We always, really always want associative arrays + self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC); + } + return true; + + } + + /** + * @brief creates the tables in migration.db from an apps database.xml + * @param $appid string id of the app + * @return bool whether the operation was successful + */ + static private function createAppTables( $appid ){ + + if( !self::connectScheme() ){ + return false; + } + + // There is a database.xml file + $content = file_get_contents( OC::$SERVERROOT . '/apps/' . $appid . '/appinfo/database.xml' ); + + $file2 = 'static://db_scheme'; + // TODO get the relative path to migration.db from the data dir + // For now just cheat + $path = pathinfo( self::$dbpath ); + $content = str_replace( '*dbname*', self::$uid.'/migration', $content ); + $content = str_replace( '*dbprefix*', '', $content ); + + $xml = new SimpleXMLElement($content); + foreach($xml->table as $table){ + $tables[] = (string)$table->name; + } + + file_put_contents( $file2, $content ); + + // Try to create tables + $definition = self::$schema->parseDatabaseDefinitionFile( $file2 ); + + unlink( $file2 ); + + // Die in case something went wrong + if( $definition instanceof MDB2_Schema_Error ){ + OC_Log::write( 'migration', 'Failed to parse database.xml for: '.$appid, OC_Log::FATAL ); + OC_Log::write( 'migration', $definition->getMessage().': '.$definition->getUserInfo(), OC_Log::FATAL ); + return false; + } + + $definition['overwrite'] = true; + + $ret = self::$schema->createDatabase( $definition ); + + // Die in case something went wrong + if( $ret instanceof MDB2_Error ){ + OC_Log::write( 'migration', 'Failed to create tables for: '.$appid, OC_Log::FATAL ); + OC_Log::write( 'migration', $ret->getMessage().': '.$ret->getUserInfo(), OC_Log::FATAL ); + return false; + } + return $tables; + + } + + /** + * @brief tries to create the zip + * @param $path string path to zip destination + * @return bool + */ + static private function createZip(){ + self::$zip = new ZipArchive; + // Check if properties are set + if( !self::$zippath ){ + OC_Log::write('migration', 'createZip() called but $zip and/or $zippath have not been set', OC_Log::ERROR); + return false; + } + if ( self::$zip->open( self::$zippath, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE ) !== TRUE ) { + OC_Log::write('migration', 'Failed to create the zip with error: '.self::$zip->getStatusString(), OC_Log::ERROR); + return false; + } else { + return true; + } + } + + /** + * @brief returns an array of apps that support migration + * @return array + */ + static public function getApps(){ + $allapps = OC_App::getAllApps(); + foreach($allapps as $app){ + $path = OC::$SERVERROOT . '/apps/' . $app . '/lib/migrate.php'; + if( file_exists( $path ) ){ + $supportsmigration[] = $app; + } + } + return $supportsmigration; + } + + /** + * @brief imports a new user + * @param $db string path to migration.db + * @param $info object of migration info + * @param $uid optional uid to use + * @return array of apps with import statuses, or false on failure. + */ + public static function importAppData( $db, $info, $uid=null ){ + // Check if the db exists + if( file_exists( $db ) ){ + // Connect to the db + if(!self::connectDB( $db )){ + OC_Log::write('migration','Failed to connect to migration.db',OC_Log::ERROR); + return false; + } + } else { + OC_Log::write('migration','Migration.db not found at: '.$db, OC_Log::FATAL ); + return false; + } + + // Find providers + self::findProviders(); + + // Generate importinfo array + $importinfo = array( + 'olduid' => $info->exporteduser, + 'newuid' => self::$uid + ); + + foreach( self::$providers as $provider){ + // Is the app in the export? + $id = $provider->getID(); + if( isset( $info->apps->$id ) ){ + // Is the app installed + if( !OC_App::isEnabled( $id ) ){ + OC_Log::write( 'migration', 'App: ' . $id . ' is not installed, can\'t import data.', OC_Log::INFO ); + $appsstatus[$id] = 'notsupported'; + } else { + // Did it succeed on export? + if( $info->apps->$id->success ){ + // Give the provider the content object + if( !self::connectDB( $db ) ){ + return false; + } + $content = new OC_Migration_Content( self::$zip, self::$MDB2 ); + $provider->setData( self::$uid, $content, $info ); + // Then do the import + if( !$appsstatus[$id] = $provider->import( $info->apps->$id, $importinfo ) ){ + // Failed to import app + OC_Log::write( 'migration', 'Failed to import app data for user: ' . self::$uid . ' for app: ' . $id, OC_Log::ERROR ); + } + } else { + // Add to failed list + $appsstatus[$id] = false; + } + } + } + } + + return $appsstatus; + + } + + /* + * @brief creates a new user in the database + * @param $uid string user_id of the user to be created + * @param $hash string hash of the user to be created + * @return bool result of user creation + */ + public static function createUser( $uid, $hash ){ + + // Check if userid exists + if(OC_User::userExists( $uid )){ + return false; + } + + // Create the user + $query = OC_DB::prepare( "INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )" ); + $result = $query->execute( array( $uid, $hash)); + if( !$result ){ + OC_Log::write('migration', 'Failed to create the new user "'.$uid.""); + } + return $result ? true : false; + + } + +} diff --git a/lib/migration/content.php b/lib/migration/content.php new file mode 100644 index 00000000000..7ef88f36e43 --- /dev/null +++ b/lib/migration/content.php @@ -0,0 +1,252 @@ +<?php +/** + * ownCloud + * + * @author Tom Needham + * @copyright 2012 Tom Needham tom@owncloud.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +/** + * provides methods to add and access data from the migration + */ +class OC_Migration_Content{ + + private $zip=false; + // Holds the MDB2 object + private $db=null; + // Holds an array of tmpfiles to delete after zip creation + private $tmpfiles=false; + + /** + * @brief sets up the + * @param $zip ZipArchive object + * @param optional $db a MDB2 database object (required for exporttype user) + * @return bool + */ + public function __construct( $zip, $db=null ){ + + $this->zip = $zip; + $this->db = $db; + + if( !is_null( $db ) ){ + // Get db path + $db = $this->db->getDatabase(); + $this->tmpfiles[] = $db; + } + + } + + // @brief prepares the db + // @param $query the sql query to prepare + public function prepare( $query ){ + + // Optimize the query + $query = $this->processQuery( $query ); + + // Optimize the query + $query = $this->db->prepare( $query ); + + // Die if we have an error (error means: bad query, not 0 results!) + if( PEAR::isError( $query ) ) { + $entry = 'DB Error: "'.$result->getMessage().'"<br />'; + $entry .= 'Offending command was: '.$query.'<br />'; + OC_Log::write( 'migration', $entry, OC_Log::FATAL ); + return false; + } else { + return $query; + } + + } + + /** + * @brief processes the db query + * @param $query the query to process + * @return string of processed query + */ + private function processQuery( $query ){ + $query = str_replace( '`', '\'', $query ); + $query = str_replace( 'NOW()', 'datetime(\'now\')', $query ); + $query = str_replace( 'now()', 'datetime(\'now\')', $query ); + // remove table prefixes + $query = str_replace( '*PREFIX*', '', $query ); + return $query; + } + + /** + * @brief copys rows to migration.db from the main database + * @param $options array of options. + * @return bool + */ + public function copyRows( $options ){ + if( !array_key_exists( 'table', $options ) ){ + return false; + } + + $return = array(); + + // Need to include 'where' in the query? + if( array_key_exists( 'matchval', $options ) && array_key_exists( 'matchcol', $options ) ){ + + // If only one matchval, create an array + if(!is_array($options['matchval'])){ + $options['matchval'] = array( $options['matchval'] ); + } + + foreach( $options['matchval'] as $matchval ){ + // Run the query for this match value (where x = y value) + $sql = "SELECT * FROM *PREFIX*" . $options['table'] . " WHERE " . $options['matchcol'] . " LIKE ?"; + $query = OC_DB::prepare( $sql ); + $results = $query->execute( array( $matchval ) ); + $newreturns = $this->insertData( $results, $options ); + $return = array_merge( $return, $newreturns ); + } + + } else { + // Just get everything + $sql = "SELECT * FROM *PREFIX*" . $options['table']; + $query = OC_DB::prepare( $sql ); + $results = $query->execute(); + $return = $this->insertData( $results, $options ); + + } + + return $return; + + } + + /** + * @brief saves a sql data set into migration.db + * @param $data a sql data set returned from self::prepare()->query() + * @param $options array of copyRows options + * @return void + */ + private function insertData( $data, $options ){ + $return = array(); + // Foreach row of data to insert + while( $row = $data->fetchRow() ){ + // Now save all this to the migration.db + foreach($row as $field=>$value){ + $fields[] = $field; + $values[] = $value; + } + + // Generate some sql + $sql = "INSERT INTO `" . $options['table'] . '` ( `'; + $fieldssql = implode( '`, `', $fields ); + $sql .= $fieldssql . "` ) VALUES( "; + $valuessql = substr( str_repeat( '?, ', count( $fields ) ),0,-2 ); + $sql .= $valuessql . " )"; + // Make the query + $query = $this->prepare( $sql ); + if( !$query ){ + OC_Log::write( 'migration', 'Invalid sql produced: '.$sql, OC_Log::FATAL ); + return false; + exit(); + } else { + $query->execute( $values ); + // Do we need to return some values? + if( array_key_exists( 'idcol', $options ) ){ + // Yes we do + $return[] = $row[$options['idcol']]; + } else { + // Take a guess and return the first field :) + $return[] = reset($row); + } + } + $fields = ''; + $values = ''; + } + return $return; + } + + /** + * @brief adds a directory to the zip object + * @param $dir string path of the directory to add + * @param $recursive bool + * @param $internaldir string path of folder to add dir to in zip + * @return bool + */ + public function addDir( $dir, $recursive=true, $internaldir='' ) { + $dirname = basename($dir); + $this->zip->addEmptyDir($internaldir . $dirname); + $internaldir.=$dirname.='/'; + if( !file_exists( $dir ) ){ + return false; + } + if ($dirhandle = opendir($dir)) { + while (false !== ( $file = readdir($dirhandle))) { + + if (( $file != '.' ) && ( $file != '..' )) { + + if (is_dir($dir . '/' . $file) && $recursive) { + $this->addDir($dir . '/' . $file, $recursive, $internaldir); + } elseif (is_file($dir . '/' . $file)) { + $this->zip->addFile($dir . '/' . $file, $internaldir . $file); + } + } + } + closedir($dirhandle); + } else { + OC_Log::write('admin_export',"Was not able to open directory: " . $dir,OC_Log::ERROR); + return false; + } + return true; + } + + /** + * @brief adds a file to the zip from a given string + * @param $data string of data to add + * @param $path the relative path inside of the zip to save the file to + * @return bool + */ + public function addFromString( $data, $path ){ + // Create a temp file + $file = tempnam( get_temp_dir(). '/', 'oc_export_tmp_' ); + $this->tmpfiles[] = $file; + if( !file_put_contents( $file, $data ) ){ + OC_Log::write( 'migation', 'Failed to save data to a temporary file', OC_Log::ERROR ); + return false; + } + // Add file to the zip + $this->zip->addFile( $file, $path ); + return true; + } + + /** + * @brief closes the zip, removes temp files + * @return bool + */ + public function finish(){ + if( !$this->zip->close() ){ + OC_Log::write( 'migration', 'Failed to write the zip file with error: '.$this->zip->getStatusString(), OC_Log::ERROR ); + return false; + } + $this->cleanup(); + return true; + } + + /** + * @brief cleans up after the zip + */ + private function cleanup(){ + // Delete tmp files + foreach($this->tmpfiles as $i){ + unlink( $i ); + } + } +} diff --git a/lib/migration/provider.php b/lib/migration/provider.php new file mode 100644 index 00000000000..91336f3019d --- /dev/null +++ b/lib/migration/provider.php @@ -0,0 +1,52 @@ +<?php +/** + * provides search functionalty + */ +abstract class OC_Migration_Provider{ + + protected $id=false; + protected $content=false; + protected $uid=false; + protected $olduid=false; + protected $appinfo=false; + + public function __construct( $appid ){ + // Set the id + $this->id = $appid; + OC_Migrate::registerProvider( $this ); + } + + /** + * @brief exports data for apps + * @return array appdata to be exported + */ + abstract function export( ); + + /** + * @brief imports data for the app + * @return void + */ + abstract function import( ); + + /** + * @brief sets the OC_Migration_Content object to $this->content + * @param $content a OC_Migration_Content object + */ + public function setData( $uid, $content, $info=null ){ + $this->content = $content; + $this->uid = $uid; + $id = $this->id; + if( !is_null( $info ) ){ + $this->olduid = $info->exporteduser; + $this->appinfo = $info->apps->$id; + } + } + + /** + * @brief returns the appid of the provider + * @return string + */ + public function getID(){ + return $this->id; + } +} diff --git a/lib/mimetypes.fixlist.php b/lib/mimetypes.fixlist.php index 1c6acbc4438..a40fbd9e228 100644 --- a/lib/mimetypes.fixlist.php +++ b/lib/mimetypes.fixlist.php @@ -10,5 +10,12 @@ return array( 'pl'=>'text/x-script.perl', 'py'=>'text/x-script.phyton', 'vcf' => 'text/vcard', - 'vcard' => 'text/vcard' + 'vcard' => 'text/vcard', + 'doc'=>'application/msword', + 'docx'=>'application/msword', + 'xls'=>'application/msexcel', + 'xlsx'=>'application/msexcel', + 'ppt'=>'application/mspowerpoint', + 'pptx'=>'application/mspowerpoint', + 'sgf' => 'application/sgf' ); diff --git a/lib/mimetypes.list.php b/lib/mimetypes.list.php index e0570e84ea5..ccf47999b1c 100644 --- a/lib/mimetypes.list.php +++ b/lib/mimetypes.list.php @@ -21,7 +21,7 @@ */ /** - * list of mimetypes by extention + * list of mimetypes by extension */ return array( diff --git a/lib/ocsclient.php b/lib/ocsclient.php index 9d5932fb720..d830a4f3e7e 100644..100755 --- a/lib/ocsclient.php +++ b/lib/ocsclient.php @@ -29,13 +29,45 @@ class OC_OCSClient{ /** + * @brief Get the url of the OCS AppStore server. + * @returns string of the AppStore server + * + * This function returns the url of the OCS AppStore server. It´s possible to set it in the config file or it will fallback to the default + */ + private static function getAppStoreURL(){ + $configurl=OC_Config::getValue('appstoreurl', ''); + if($configurl<>'') { + $url=$configurl; + }else{ + $url='http://api.apps.owncloud.com/v1'; + } + return($url); + } + + /** + * @brief Get the url of the OCS KB server. + * @returns string of the KB server + * This function returns the url of the OCS knowledge base server. It´s possible to set it in the config file or it will fallback to the default + */ + private static function getKBURL(){ + $configurl=OC_Config::getValue('knowledgebaseurl', ''); + if($configurl<>'') { + $url=$configurl; + }else{ + $url='http://api.apps.owncloud.com/v1'; + } + return($url); + } + + + /** * @brief Get all the categories from the OCS server * @returns array with category ids * * This function returns a list of all the application categories on the OCS server */ public static function getCategories(){ - $url='http://api.apps.owncloud.com/v1/content/categories'; + $url=OC_OCSClient::getAppStoreURL().'/content/categories'; $xml=@file_get_contents($url); if($xml==FALSE){ @@ -64,12 +96,16 @@ class OC_OCSClient{ * This function returns a list of all the applications on the OCS server */ public static function getApplications($categories){ + if(OC_Config::getValue('appstoreenabled', true)==false){ + return(array()); + } + if(is_array($categories)) { $categoriesstring=implode('x',$categories); }else{ $categoriesstring=$categories; } - $url='http://api.apps.owncloud.com/v1/content/data?categories='.urlencode($categoriesstring).'&sortmode=new&page=0&pagesize=10'; + $url=OC_OCSClient::getAppStoreURL().'/content/data?categories='.urlencode($categoriesstring).'&sortmode=new&page=0&pagesize=10'; $apps=array(); $xml=@file_get_contents($url); if($xml==FALSE){ @@ -104,7 +140,7 @@ class OC_OCSClient{ * This function returns an applications from the OCS server */ public static function getApplication($id){ - $url='http://api.apps.owncloud.com/v1/content/data/'.urlencode($id); + $url=OC_OCSClient::getAppStoreURL().'/content/data/'.urlencode($id); $xml=@file_get_contents($url); if($xml==FALSE){ @@ -137,7 +173,7 @@ class OC_OCSClient{ * This function returns an download url for an applications from the OCS server */ public static function getApplicationDownload($id,$item){ - $url='http://api.apps.owncloud.com/v1/content/download/'.urlencode($id).'/'.urlencode($item); + $url=OC_OCSClient::getAppStoreURL().'/content/download/'.urlencode($id).'/'.urlencode($item); $xml=@file_get_contents($url); if($xml==FALSE){ @@ -164,9 +200,15 @@ class OC_OCSClient{ * This function returns a list of all the knowledgebase entries from the OCS server */ public static function getKnownledgebaseEntries($page,$pagesize){ + if(OC_Config::getValue('knowledgebaseenabled', true)==false){ + $kbe=array(); + $kbe['totalitems']=0; + return $kbe; + } + $p= (int) $page; $s= (int) $pagesize; - $url='http://api.apps.owncloud.com/v1/knowledgebase/data?type=150&page='.$p.'&pagesize='.$s; + $url=OC_OCSClient::getKBURL().'/knowledgebase/data?type=150&page='.$p.'&pagesize='.$s; $kbe=array(); $xml=@file_get_contents($url); diff --git a/lib/remote/cloud.php b/lib/remote/cloud.php deleted file mode 100644 index a9c74e8bf5f..00000000000 --- a/lib/remote/cloud.php +++ /dev/null @@ -1,204 +0,0 @@ -<?php -/** - * Class for connection to a remote owncloud installation - * - */ -class OC_REMOTE_CLOUD{ - private $path; - private $connected=false; - private $cookiefile=false; - - /** - * make an api call to the remote cloud - * @param string $action - * @param array parameters - * @param bool assoc when set to true, the result will be parsed as associative array - * - */ - private function apiCall($action,$parameters=false,$assoc=false){ - if(!$this->cookiefile){ - $this->cookiefile=get_temp_dir().'/remoteCloudCookie'.uniqid(); - } - $url=$this->path.='/files/api.php'; - $fields_string="action=$action&"; - if(is_array($parameters)){ - foreach($parameters as $key=>$value){ - $fields_string.=$key.'='.$value.'&'; - } - rtrim($fields_string,'&'); - } - $ch=curl_init(); - curl_setopt($ch,CURLOPT_URL,$url); - curl_setopt($ch,CURLOPT_POST,count($parameters)); - curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string); - curl_setopt($ch, CURLOPT_COOKIEFILE,$this->cookiefile); - curl_setopt($ch, CURLOPT_COOKIEJAR,$this->cookiefile); - curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); - $result=curl_exec($ch); - $result=trim($result); - $info=curl_getinfo($ch); - $httpCode=$info['http_code']; - curl_close($ch); - if($httpCode==200 or $httpCode==0){ - return json_decode($result,$assoc); - }else{ - return false; - } - } - - public function __construct($path,$user,$password){ - $this->path=$path; - $this->connected=$this->apiCall('login',array('username'=>$user,'password'=>$password)); - } - - /** - * check if we are stull logged in on the remote cloud - * - */ - public function isLoggedIn(){ - if(!$this->connected){ - return false; - } - return $this->apiCall('checklogin'); - } - - public function __get($name){ - switch($name){ - case 'connected': - return $this->connected; - } - } - - /** - * disconnect from the remote cloud - * - */ - public function disconnect(){ - $this->connected=false; - if(is_file($this->cookiefile)){ - unlink($this->cookiefile); - } - $this->cookiefile=false; - } - - /** - * create a new file or directory - * @param string $dir - * @param string $name - * @param string $type - */ - public function newFile($dir,$name,$type){ - if(!$this->connected){ - return false; - } - return $this->apiCall('new',array('dir'=>$dir,'name'=>$name,'type'=>$type),true); - } - - /** - * deletes a file or directory - * @param string $dir - * @param string $file - */ - public function delete($dir,$name){ - if(!$this->connected){ - return false; - } - return $this->apiCall('delete',array('dir'=>$dir,'file'=>$name),true); - } - - /** - * moves a file or directory - * @param string $sorceDir - * @param string $sorceFile - * @param string $targetDir - * @param string $targetFile - */ - public function move($sourceDir,$sourceFile,$targetDir,$targetFile){ - if(!$this->connected){ - return false; - } - return $this->apiCall('move',array('sourcedir'=>$sourceDir,'source'=>$sourceFile,'targetdir'=>$targetDir,'target'=>$targetFile),true); - } - - /** - * copies a file or directory - * @param string $sorceDir - * @param string $sorceFile - * @param string $targetDir - * @param string $targetFile - */ - public function copy($sourceDir,$sourceFile,$targetDir,$targetFile){ - if(!$this->connected){ - return false; - } - return $this->apiCall('copy',array('sourcedir'=>$sourceDir,'source'=>$sourceFile,'targetdir'=>$targetDir,'target'=>$targetFile),true); - } - - /** - * get a file tree - * @param string $dir - */ - public function getTree($dir){ - if(!$this->connected){ - return false; - } - return $this->apiCall('gettree',array('dir'=>$dir),true); - } - - /** - * get the files inside a directory of the remote cloud - * @param string $dir - */ - public function getFiles($dir){ - if(!$this->connected){ - return false; - } - return $this->apiCall('getfiles',array('dir'=>$dir),true); - } - - /** - * get a remove file and save it in a temporary file and return the path of the temporary file - * @param string $dir - * @param string $file - * @return string - */ - public function getFile($dir, $file){ - if(!$this->connected){ - return false; - } - $ch=curl_init(); - if(!$this->cookiefile){ - $this->cookiefile=get_temp_dir().'/remoteCloudCookie'.uniqid(); - } - $tmpfile=tempnam(get_temp_dir(),'remoteCloudFile'); - $fp=fopen($tmpfile,'w+'); - $url=$this->path.="/files/api.php?action=get&dir=$dir&file=$file"; - curl_setopt($ch,CURLOPT_URL,$url); - curl_setopt($ch, CURLOPT_COOKIEFILE,$this->cookiefile); - curl_setopt($ch, CURLOPT_COOKIEJAR,$this->cookiefile); - curl_setopt($ch, CURLOPT_FILE, $fp); - curl_exec($ch); - fclose($fp); - curl_close($ch); - return $tmpfile; - } - - public function sendFile($sourceDir,$sourceFile,$targetDir,$targetFile){ - $source=$sourceDir.'/'.$sourceFile; - $tmp=OC_Filesystem::toTmpFile($source); - return $this->sendTmpFile($tmp,$targetDir,$targetFile); - } - - public function sendTmpFile($tmp,$targetDir,$targetFile){ - $token=sha1(uniqid().$tmp); - $file=get_temp_dir().'/'.'remoteCloudFile'.$token; - rename($tmp,$file); - if( OC_Config::getValue( "forcessl", false ) or isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') { - $url = "https://". $_SERVER['SERVER_NAME'] . OC::$WEBROOT; - }else{ - $url = "http://". $_SERVER['SERVER_NAME'] . OC::$WEBROOT; - } - return $this->apiCall('pull',array('dir'=>$targetDir,'file'=>$targetFile,'token'=>$token,'source'=>$url),true); - } -} - diff --git a/lib/search.php b/lib/search.php index 6b33fa38140..12055418687 100644 --- a/lib/search.php +++ b/lib/search.php @@ -26,13 +26,22 @@ */ class OC_Search{ static private $providers=array(); + static private $registeredProviders=array(); + + /** + * remove all registered search providers + */ + public static function clearProviders(){ + self::$providers=array(); + self::$registeredProviders=array(); + } /** * register a new search provider to be used * @param string $provider class name of a OC_Search_Provider */ - public static function registerProvider($provider){ - self::$providers[]=$provider; + public static function registerProvider($class,$options=array()){ + self::$registeredProviders[]=array('class'=>$class,'options'=>$options); } /** @@ -41,10 +50,25 @@ class OC_Search{ * @return array An array of OC_Search_Result's */ public static function search($query){ + self::initProviders(); $results=array(); foreach(self::$providers as $provider){ - $results=array_merge($results, $provider::search($query)); + $results=array_merge($results, $provider->search($query)); } return $results; } + + /** + * create instances of all the registered search providers + */ + private static function initProviders(){ + if(count(self::$providers)>0){ + return; + } + foreach(self::$registeredProviders as $provider){ + $class=$provider['class']; + $options=$provider['options']; + self::$providers[]=new $class($options); + } + } } diff --git a/lib/search/provider.php b/lib/search/provider.php index 9487ca51f2b..838ab696d04 100644 --- a/lib/search/provider.php +++ b/lib/search/provider.php @@ -2,11 +2,13 @@ /** * provides search functionalty */ -interface OC_Search_Provider { +class OC_Search_Provider { + public function __construct($options){} + /** * search for $query * @param string $query * @return array An array of OC_Search_Result's */ - static function search($query); + public function search($query){} } diff --git a/lib/search/provider/file.php b/lib/search/provider/file.php index 3bdb3bcd2af..a37af495599 100644 --- a/lib/search/provider/file.php +++ b/lib/search/provider/file.php @@ -1,7 +1,7 @@ <?php -class OC_Search_Provider_File implements OC_Search_Provider{ - static function search($query){ +class OC_Search_Provider_File extends OC_Search_Provider{ + function search($query){ $files=OC_FileCache::search($query,true); $results=array(); foreach($files as $fileData){ diff --git a/lib/template.php b/lib/template.php index eea2925975c..eeba2410b68 100644 --- a/lib/template.php +++ b/lib/template.php @@ -76,7 +76,7 @@ function simple_file_size($bytes) { } function relative_modified_date($timestamp) { - $l=new OC_L10N('template'); + $l=OC_L10N::get('template'); $timediff = time() - $timestamp; $diffminutes = round($timediff/60); $diffhours = round($diffminutes/60); @@ -140,7 +140,7 @@ class OC_Template{ /** * @brief Constructor * @param $app app providing the template - * @param $file name of the tempalte file (without suffix) + * @param $file name of the template file (without suffix) * @param $renderas = ""; produce a full page * @returns OC_Template object * @@ -151,10 +151,20 @@ class OC_Template{ * "admin". */ public function __construct( $app, $name, $renderas = "" ){ - // Read the selected theme from the config file - $theme=OC_Config::getValue( "theme" ); + // Set the private data + $this->renderas = $renderas; + $this->application = $app; + $this->vars = array(); + $this->l10n = OC_L10N::get($app); - // Read the detected formfactor and use the right file name. + $this->findTemplate($name); + } + + /** + * @brief Returns the formfactor extension for current formfactor + */ + protected function getFormFactorExtension() + { $formfactor=$_SESSION['formfactor']; if($formfactor=='default') { $fext=''; @@ -167,70 +177,79 @@ class OC_Template{ }else{ $fext=''; } + return $fext; + } + /** + * @brief find the template with the given name + * @param $name of the template file (without suffix) + * + * Will select the template file for the selected theme and formfactor. + * Checking all the possible locations. + */ + protected function findTemplate($name) + { + // Read the selected theme from the config file + $theme=OC_Config::getValue( "theme" ); + + // Read the detected formfactor and use the right file name. + $fext = $this->getFormFactorExtension(); + + $app = $this->application; // Check if it is a app template or not. if( $app != "" ){ // Check if the app is in the app folder or in the root if( file_exists( OC::$APPSROOT."/apps/$app/templates/" )){ // Check if the template is overwritten by the selected theme - if( file_exists( OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name$fext.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name$fext.php"; - $path = OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name.php"; - $path = OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"; - }elseif( OC::$APPSROOT."/apps/$app/templates/"."$name$fext.php" ){ - $template = OC::$APPSROOT."/apps/$app/templates/"."$name$fext.php"; - $path = OC::$APPSROOT."/apps/$app/templates/"; - }else{ - $template = OC::$APPSROOT."/apps/$app/templates/"."$name.php"; - $path = OC::$APPSROOT."/apps/$app/templates/"; + if ($this->checkPathForTemplate(OC::$SERVERROOT."/themes/$theme/apps/$app/templates/", $name, $fext)) { + }elseif ($this->checkPathForTemplate(OC::$APPSROOT."/apps/$app/templates/", $name, $fext)) { } }else{ // Check if the template is overwritten by the selected theme - if( file_exists( OC::$SERVERROOT."/themes/$theme/$app/templates/"."$name$fext.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/$app/templates/"."$name$fext.php"; - $path = OC::$SERVERROOT."/themes/$theme/$app/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/themes/$theme/$app/templates/"."$name.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/$app/templates/"."$name.php"; - $path = OC::$SERVERROOT."/themes/$theme/$app/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/$app/templates/"."$name$fext.php" )){ - $template = OC::$SERVERROOT."/$app/templates/"."$name$fext.php"; - $path = OC::$SERVERROOT."/$app/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/$app/templates/"."$name.php" )){ - $template = OC::$SERVERROOT."/$app/templates/"."$name.php"; - $path = OC::$SERVERROOT."/$app/templates/"; + if ($this->checkPathForTemplate(OC::$SERVERROOT."/themes/$theme/$app/templates/", $name, $fext)) { + }elseif ($this->checkPathForTemplate(OC::$SERVERROOT."/$app/templates/", $name, $fext)) { }else{ - echo('template not found: template:'.$name.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + echo('template not found: template:'.$name.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); die(); } - } + } }else{ // Check if the template is overwritten by the selected theme - if( file_exists( OC::$SERVERROOT."/themes/$theme/core/templates/"."$name$fext.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/core/templates/"."$name$fext.php"; - $path = OC::$SERVERROOT."/themes/$theme/core/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/themes/$theme/core/templates/"."$name.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/core/templates/"."$name.php"; - $path = OC::$SERVERROOT."/themes/$theme/core/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/core/templates/"."$name$fext.php" )){ - $template = OC::$SERVERROOT."/core/templates/"."$name$fext.php"; - $path = OC::$SERVERROOT."/core/templates/"; + if ($this->checkPathForTemplate(OC::$SERVERROOT."/themes/$theme/core/templates/", $name, $fext)) { + } elseif ($this->checkPathForTemplate(OC::$SERVERROOT."/core/templates/", $name, $fext)) { }else{ - $template = OC::$SERVERROOT."/core/templates/"."$name.php"; - $path = OC::$SERVERROOT."/core/templates/"; + echo('template not found: template:'.$name.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + die(); } } + } - - // Set the private data - $this->renderas = $renderas; - $this->application = $app; - $this->template = $template; - $this->path = $path; - $this->vars = array(); - $this->l10n = new OC_L10N($app); + /** + * @brief check Path For Template with and without $fext + * @param $path to check + * @param $name of the template file (without suffix) + * @param $fext formfactor extension + * @return bool true when found + * + * Will set $this->template and $this->path if there is a template at + * the specifief $path + */ + protected function checkPathForTemplate($path, $name, $fext) + { + if ($name =='') return false; + $template = null; + if( is_file( $path.$name.$fext.'.php' )){ + $template = $path.$name.$fext.'.php'; + }elseif( is_file( $path.$name.'.php' )){ + $template = $path.$name.'.php'; + } + if ($template) { + $this->template = $template; + $this->path = $path; + return true; + } + return false; } /** @@ -267,7 +286,7 @@ class OC_Template{ $this->vars[$key] = array( $value ); } } - + /** * @brief Add a custom element to the header * @param string tag tag name of the element @@ -295,11 +314,25 @@ class OC_Template{ } } + /* + * @brief append the $file-url if exist at $root + * @param $type of collection to use when appending + * @param $root path to check + * @param $web base for path + * @param $file the filename + */ + public function appendIfExist($type, $root, $web, $file) { + if (is_file($root.'/'.$file)) { + $this->append( $type, $web.'/'.$file); + return true; + } + return false; + } /** * @brief Proceeds the template * @returns content * - * This function proceeds the template. If $this->renderas is set, it will + * This function proceeds the template. If $this->renderas is set, it * will produce a full page. */ public function fetchPage(){ @@ -329,68 +362,44 @@ class OC_Template{ }else{ $page = new OC_Template( "core", "layout.guest" ); } - + // Read the selected theme from the config file $theme=OC_Config::getValue( "theme" ); // Read the detected formfactor and use the right file name. - $formfactor=$_SESSION['formfactor']; - if($formfactor=='default') { - $fext=''; - }elseif($formfactor=='mobile') { - $fext='.mobile'; - }elseif($formfactor=='tablet') { - $fext='.tablet'; - }elseif($formfactor=='standalone') { - $fext='.standalone'; - }else{ - $fext=''; - } + $fext = $this->getFormFactorExtension(); // Add the core js files or the js files provided by the selected theme foreach(OC_Util::$scripts as $script){ // Is it in 3rd party? - if(is_file(OC::$THIRDPARTYROOT."/$script.js" )){ - $page->append( "jsfiles", OC::$THIRDPARTYWEBROOT."/$script.js" ); + if($page->appendIfExist('jsfiles', OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $script.'.js')) { // Is it in apps and overwritten by the theme? - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/apps/$script$fext.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/apps/$script$fext.js" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/apps/$script.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/apps/$script.js" ); + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$script.js" )) { // Is it part of an app? - }elseif(is_file(OC::$APPSROOT."/apps/$script$fext.js" )){ - $page->append( "jsfiles", OC::$APPSWEBROOT."/apps/$script$fext.js" ); - }elseif(is_file(OC::$APPSROOT."/apps/$script.js" )){ - $page->append( "jsfiles", OC::$APPSWEBROOT."/apps/$script.js" ); + }elseif($page->appendIfExist('jsfiles', OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$script.js" )) { // Is it in the owncloud root but overwritten by the theme? - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/$script$fext.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/$script$fext.js" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/$script.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/$script.js" ); - + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$script.js" )) { + // Is it in the owncloud root ? - }elseif(is_file(OC::$SERVERROOT."/$script$fext.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/$script$fext.js" ); - }elseif(is_file(OC::$SERVERROOT."/$script.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/$script.js" ); + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "$script.js" )) { // Is in core but overwritten by a theme? - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/core/$script$fext.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/core/$script$fext.js" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/core/$script.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/core/$script.js" ); + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$script.js" )) { // Is it in core? - }elseif(is_file(OC::$SERVERROOT."/core/$script$fext.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/core/$script$fext.js" ); - }elseif(is_file(OC::$SERVERROOT."/core/$script.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/core/$script.js" ); + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$script.js" )) { }else{ - echo('js file not found: script:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + echo('js file not found: script:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); die(); } @@ -398,54 +407,46 @@ class OC_Template{ // Add the css files foreach(OC_Util::$styles as $style){ // is it in 3rdparty? - if(is_file(OC::$THIRDPARTYROOT."/$style.css" )){ - $page->append( "cssfiles", OC::$THIRDPARTYWEBROOT."/$style.css" ); + if($page->appendIfExist('cssfiles', OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $style.'.css')) { + // or in apps? - }elseif(is_file(OC::$APPSROOT."/apps/$style$fext.css" )){ - $page->append( "cssfiles", OC::$APPSWEBROOT."/apps/$style$fext.css" ); - }elseif(is_file(OC::$APPSROOT."/apps/$style.css" )){ - $page->append( "cssfiles", OC::$APPSWEBROOT."/apps/$style.css" ); + }elseif($page->appendIfExist('cssfiles', OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$style.css" )) { + // or in the owncloud root? - }elseif(is_file(OC::$SERVERROOT."/$style$fext.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/$style$fext.css" ); - }elseif(is_file(OC::$SERVERROOT."/$style.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/$style.css" ); - // or in core ? - }elseif(is_file(OC::$SERVERROOT."/core/$style$fext.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/core/$style$fext.css" ); - }elseif(is_file(OC::$SERVERROOT."/core/$style.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/core/$style.css" ); + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "$style.css" )) { + + // or in core ? + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$style.css" )) { }else{ - echo('css file not found: style:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + echo('css file not found: style:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); die(); } } - // Add the theme css files. you can override the default values here + // Add the theme css files. you can override the default values here if(!empty($theme)) { - foreach(OC_Util::$styles as $style){ - if(is_file(OC::$SERVERROOT."/themes/$theme/apps/$style$fext.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/apps/$style$fext.css" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/apps/$style.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/apps/$style.css" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/$style$fext.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/$style$fext.css" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/$style.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/$style.css" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/core/$style$fext.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/core/$style$fext.css" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/core/$style.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/core/$style.css" ); - } - } - } - + foreach(OC_Util::$styles as $style){ + if($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$style.css" )) { + + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$style.css" )) { + + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$style.css" )) { + } + } + } + // Add custom headers $page->assign('headers',$this->headers); foreach(OC_Util::$headers as $header){ $page->append('headers',$header); } - + // Add css files and js files $page->assign( "content", $data ); return $page->fetchPage(); diff --git a/lib/updater.php b/lib/updater.php index 57623797ae5..deb0f05945e 100644 --- a/lib/updater.php +++ b/lib/updater.php @@ -36,6 +36,7 @@ class OC_Updater{ $version['installed']=OC_Config::getValue('installedat'); $version['updated']=OC_Appconfig::getValue('core', 'lastupdatedat', OC_Config::getValue( 'lastupdatedat')); $version['updatechannel']='stable'; + $version['edition']=OC_Util::getEditionString(); $versionstring=implode('x',$version); //fetch xml data from updater @@ -58,9 +59,9 @@ class OC_Updater{ public static function ShowUpdatingHint(){ $data=OC_Updater::check(); if(isset($data['version']) and $data['version']<>'') { - $txt='<span style="color:#AA0000; font-weight:bold;">'.$data['versionstring'].' is available. Please click <a href="'.$data['web'].'">here</a> for more information</span>'; + $txt='<span style="color:#AA0000; font-weight:bold;">'.$data['versionstring'].' is available. Get <a href="'.$data['web'].'">more information</a></span>'; }else{ - $txt='Your ownCloud is up to date'; + $txt='up to date'; } return($txt); } diff --git a/lib/user.php b/lib/user.php index fda19a33154..8c27ec30cc2 100644 --- a/lib/user.php +++ b/lib/user.php @@ -186,7 +186,7 @@ class OC_User { * @param $password The password of the user * @returns true/false * - * Log in a user - if the password is ok + * Log in a user and regenerate a new session - if the password is ok */ public static function login( $uid, $password ){ $run = true; @@ -195,6 +195,7 @@ class OC_User { if( $run ){ $uid=self::checkPassword( $uid, $password ); if($uid){ + session_regenerate_id(); self::setUserId($uid); OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid, 'password'=>$password )); return true; @@ -221,7 +222,8 @@ class OC_User { */ public static function logout(){ OC_Hook::emit( "OC_User", "logout", array()); - $_SESSION['user_id'] = false; + session_unset(); + session_destroy(); OC_User::unsetMagicInCookie(); return true; } diff --git a/lib/user/database.php b/lib/user/database.php index 3eade276dd9..c1bac1bb0b5 100644 --- a/lib/user/database.php +++ b/lib/user/database.php @@ -172,7 +172,7 @@ class OC_User_Database extends OC_User_Backend { * @return boolean */ public function userExists($uid){ - $query = OC_DB::prepare( "SELECT * FROM `*PREFIX*users` WHERE uid = ?" ); + $query = OC_DB::prepare( "SELECT * FROM `*PREFIX*users` WHERE uid LIKE ?" ); $result = $query->execute( array( $uid )); return $result->numRows() > 0; diff --git a/lib/user/dummy.php b/lib/user/dummy.php new file mode 100644 index 00000000000..cfc96c5c52d --- /dev/null +++ b/lib/user/dummy.php @@ -0,0 +1,114 @@ +<?php + +/** +* ownCloud +* +* @author Frank Karlitschek +* @copyright 2010 Frank Karlitschek karlitschek@kde.org +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * dummy user backend, does not keep state, only for testing use + */ +class OC_User_Dummy extends OC_User_Backend { + private $users=array(); + /** + * @brief Create a new user + * @param $uid The username of the user to create + * @param $password The password of the new user + * @returns true/false + * + * Creates a new user. Basic checking of username is done in OC_User + * itself, not in its subclasses. + */ + public function createUser($uid, $password){ + if(isset($this->users[$uid])){ + return false; + }else{ + $this->users[$uid]=$password; + return true; + } + } + + /** + * @brief delete a user + * @param $uid The username of the user to delete + * @returns true/false + * + * Deletes a user + */ + public function deleteUser( $uid ){ + if(isset($this->users[$uid])){ + unset($this->users[$uid]); + return true; + }else{ + return false; + } + } + + /** + * @brief Set password + * @param $uid The username + * @param $password The new password + * @returns true/false + * + * Change the password of a user + */ + public function setPassword($uid, $password){ + if(isset($this->users[$uid])){ + $this->users[$uid]=$password; + return true; + }else{ + return false; + } + } + + /** + * @brief Check if the password is correct + * @param $uid The username + * @param $password The password + * @returns true/false + * + * Check if the password is correct without logging in the user + */ + public function checkPassword($uid, $password){ + if(isset($this->users[$uid])){ + return ($this->users[$uid]==$password); + }else{ + return false; + } + } + + /** + * @brief Get a list of all users + * @returns array with all uids + * + * Get a list of all users. + */ + public function getUsers(){ + return array_keys($this->users); + } + + /** + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ + public function userExists($uid){ + return isset($this->users[$uid]); + } +} diff --git a/lib/util.php b/lib/util.php index fa5b3daaab6..2ea392ec31d 100644 --- a/lib/util.php +++ b/lib/util.php @@ -25,7 +25,7 @@ class OC_Util { $success=@mkdir($CONFIG_DATADIRECTORY_ROOT); if(!$success) { $tmpl = new OC_Template( '', 'error', 'guest' ); - $tmpl->assign('errors',array(1=>array('error'=>"Can't create data directory (".$CONFIG_DATADIRECTORY_ROOT.")",'hint'=>"You can usually fix this by giving the webserver write access to the ownCloud directory '".OC::$SERVERROOT."' "))); + $tmpl->assign('errors',array(1=>array('error'=>"Can't create data directory (".$CONFIG_DATADIRECTORY_ROOT.")",'hint'=>"You can usually fix this by giving the webserver write access to the ownCloud directory '".OC::$SERVERROOT."' (in a terminal, use the command 'chown -R www-data:www-data /path/to/your/owncloud/install/data' "))); $tmpl->printPage(); exit; } @@ -66,7 +66,7 @@ class OC_Util { * @return array */ public static function getVersion(){ - return array(3,00,3); + return array(3,80,0); } /** @@ -74,9 +74,17 @@ class OC_Util { * @return string */ public static function getVersionString(){ - return '3'; + return '4 alpha'; } + /** + * get the current installed edition of ownCloud. There is the community edition that just returns an empty string and the enterprise edition that returns "Enterprise". + * @return string + */ + public static function getEditionString(){ + return ''; + } + /** * add a javascript file * diff --git a/lib/vcategories.php b/lib/vcategories.php index 5a7bacd2025..b3b6a493c8d 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -50,13 +50,12 @@ class OC_VCategories { * parameter should normally be omitted but to make an app able to * update categories for all users it is made possible to provide it. * @param $defcategories An array of default categories to be used if none is stored. - * NOTE: Not implemented. */ - public function __construct($app, $user=null, $defcategories=null) { + public function __construct($app, $user=null, $defcategories=array()) { $this->app = $app; $this->user = is_null($user) ? OC_User::getUser() : $user; $categories = trim(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); - $this->categories = $categories != '' ? unserialize($categories) : array(); + $this->categories = $categories != '' ? unserialize($categories) : $defcategories; } /** @@ -65,6 +64,7 @@ class OC_VCategories { */ public function categories() { OC_Log::write('core','OC_VCategories::categories: '.print_r($this->categories, true), OC_Log::DEBUG); + usort($this->categories, 'strnatcasecmp'); // usort to also renumber the keys return $this->categories; } @@ -97,7 +97,6 @@ class OC_VCategories { } if(count($newones) > 0) { $this->categories = array_merge($this->categories, $newones); - natcasesort($this->categories); // Dunno if this is necessary if($sync === true) { $this->save(); } @@ -147,6 +146,7 @@ class OC_VCategories { * @brief Save the list with categories */ private function save() { + usort($this->categories, 'strnatcasecmp'); // usort to also renumber the keys $escaped_categories = serialize($this->categories); OC_Log::write('core','OC_VCategories::save: '.print_r($this->categories, true), OC_Log::DEBUG); OC_Preferences::setValue($this->user, $this->app, self::PREF_CATEGORIES_LABEL, $escaped_categories); |